如何将组件方法分享给孩子?

Posted

技术标签:

【中文标题】如何将组件方法分享给孩子?【英文标题】:How to share component methods to child? 【发布时间】:2017-09-02 15:55:44 【问题描述】:

我有两个组件:

<cmp-one></cmp-one> 被插入到 DOM 中,而我正在使用 $compile 创建一个 <cmp-top>。 然后在cmpTop 控制器中,我需要获取<cmp-one> 并将其插入<cmp-top>

插入工作正常,但我需要从 cmpOne 访问 cmpTop 控制器方法 - 并且不知道如何。

到目前为止,我尝试的是添加 require: cmpTop: '^^' - 不起作用,因为在插入完成之前没有父组件。

那么,我该如何实现呢?我的意思是 - 将一些组件插入另一个组件,并将其方法共享给添加的子组件。

更新

这里是 plunker:http://plnkr.co/edit/mgwC5Mbh5qid5q5ELDdQ?p=info

所以,我需要从DialogComponentController 访问PanelController 的方法。

或者,也许我做错了 - 所以请告诉我如何正确地做到这一点。

【问题讨论】:

你能用这个添加一个 plunker 吗? @MarcusH,我试试,谢谢关注) <comp-one />html 中开始,然后您使用该指令来构建 <comp-top /> 我添加了一个 plunker 在你的 plunker ccmPanel 不是 ccmDialog 的孩子(或反之亦然),他们是兄弟姐妹。这是故意的吗? 【参考方案1】:

您可以使用公共服务在它们之间进行通信(如 playerone 所述)。

app.controller('mainController', function($scope, menuSelection) 
  $scope.menuSelection = menuSelection; // retrieve settings object from service method and bring into scope
  // now whenever one sets $scope.menuSelection.selected = "object 2", it will update the value in the other controller as well (and vice-versa)
);

app.controller('secondController', function($scope, menuSelection) 
  $scope.menuSelection = menuSelection; // retrieve settings object from service method and bring into scope
);

app.factory('menuSelection', function() 
  var settings = ;
  settings.selected = 'Object 1';  // default
  return settings;
);

您可以将$scope.menuSelection.myFooFunction = ... 指向一个指令中的函数并从另一个指令中调用它。

【讨论】:

为了帮助我更新了您的代码,并提供了一个当您单击面板或对话框plnkr.co/edit/IJiIsMcUWX3K9osMYuZw?p=info 时在其他组件中调用函数的示例【参考方案2】:

你的代码有什么问题?

$element
      .find('.panel')
      .append(srcEl
        .css('display', 'block')
      );

您在这里使用.find类选择器,但根据documentation,angular 只支持标签选择器

继承?

根据documentation

组件只控制自己的视图和数据:组件不应该修改任何超出自己范围的数据或 DOM。通常,在 AngularJS 中,可以通过范围继承和监视在应用程序的任何位置修改数据。这是实用的,但当不清楚应用程序的哪个部分负责修改数据时也会导致问题。 这就是组件指令使用隔离范围的原因,因此不可能进行整个范围的操作。

那么如何共享方法呢?

@K Scandrett 的回答很棒,可能是最佳实践,但我最喜欢的解决方案是:

在 DialogComponentController 中:

$rootScope.$emit("abc"); 

在面板控制器中:

$rootScope.$on("abc",function()
    console.log("got it");
    //and do whatever you want 
);

【讨论】:

【参考方案3】:

检查这个工作示例。

 var app = angular.module('plunker', []);


    PanelController.$inject = ['$element'];
    function PanelController($element) 
        var $ctrl = this;

        $ctrl.showAlert = function () 
            alert('Message from PanelController');
        ;

        $ctrl.close = function () 
            // $element.remove();
        ;

        $ctrl.onShow = function () 
        ;

        $ctrl.$onInit = $onInit;
        $ctrl.$onDestroy = $onDestroy;

        function $onInit() 

            var srcEl = angular.element(document.querySelector($ctrl.source));

            srcEl.attr('panel', '$ctrl');

            $element
              .find('.panel')
              .append(srcEl
                .css('display', 'block')
              );

            $ctrl.onShow();

            var bodyRect = document.body.getBoundingClientRect(),
                elRect = $element[0].getBoundingClientRect(),
                position = 
                    left: '',
                    top: '',
                    right: '',
                    bottom: ''
                ;

            position.top = (bodyRect.height - elRect.height) / 4; //eslint-disable-line no-magic-numbers
            position.left = (bodyRect.width - elRect.width) / 2; //eslint-disable-line no-magic-numbers

            $element.css('top', position.top + 'px');
            $element.css('left', position.left + 'px');
        

        function $onDestroy() 
        
    

    function DialogComponentController() 
        var $ctrl = this;

        $ctrl.callPanelMethod = function () 
            var scope = angular.element($('ccm-panel div')).scope();
            scope.$ctrl.showAlert();
        
        $ctrl.actions = 
            close: function (event, button) 

                event.preventDefault();
                event.stopPropagation();

                $ctrl.instance.hide(button);
            
        ;

        $ctrl.$onInit = $onInit;
        $ctrl.$onDestroy = $onDestroy;

        $ctrl.$onChanges = function () 
        ;

        function $onInit() 
        

        function $onDestroy() 
        
    


    app.component('ccmDialog', 
        template: '<div style="border: 1px solid green; margin: 5px" >dialog <button ng-click="$ctrl.callPanelMethod()">click here to get alert from controll PanelController </button></div>',
        controller: DialogComponentController,

        bindings: 
            panel: '<',
            panelShown: '&'
        
    );
    app.component('ccmPanel', 
        template: '<div>' +
                  '<div style="border: 1px solid red" class="panel" ng-click="$ctrl.close()">panel</div>' +
                  '</div>',
        controller: PanelController,
        bindings: 
            source: '='
        
    );

    app.controller('MainCtrl', function ($rootScope, $scope, $compile) 
        $scope.name = 'World';

        $scope.open = function (source, target) 
            var scope = $rootScope.$new();

            scope.$ctrl = 
                source: source
            ;

            var el = $compile('<ccm-panel source="$ctrl.source" style="position: absolute;"></ccm-panel>')(scope);

            angular.element(document.querySelector(target)).append(el);
        
    );
 <script data-require="angular.js@1.5.x" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js" data-semver="1.5.11"></script>
 <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
 <div ng-app="plunker" ng-controller="MainCtrl">
    <p>Hello name!</p>
    <button ng-click="open('ccm-dialog', 'body')">open dialog</button>
    <ccm-dialog panel="test" style="display: none"></ccm-dialog>
</div>

【讨论】:

以上是关于如何将组件方法分享给孩子?的主要内容,如果未能解决你的问题,请参考以下文章

分享实用思维导图模板,孩子期末复习就靠它了

如何把app分享到微信

Taro 微信小程序 分享/转发给好友

我给孩子的第七堂C++课录屏分享

如何通过道具异步传递道具给孩子?

如何给wordpress网站添加百度分享按钮或悬浮窗