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

时间:2017-04-07 09:58:00

标签: javascript angularjs

我有两个组成部分:

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

插入正常,但我需要从cmpTop访问cmpOne控制器方法 - 并且无法弄清楚如何。

我到目前为止尝试添加require: {cmpTop: '^^'} - 因为在插入完成之前没有父组件而无法正常工作。

那么,我怎样才能做到这一点?我的意思是 - 将一些组件插入另一个组件,并将其方法分享给添加的孩子。

更新

以下是plunker:http://plnkr.co/edit/mgwC5Mbh5qid5q5ELDdQ?p=info

因此,我需要从PanelController

访问DialogComponentController的方法

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

3 个答案:

答案 0 :(得分:1)

您可以使用公共服务在它们之间进行通信(如提及的那样)。

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 = ...指向一个指令中的函数,然后从另一个指令中调用它。

答案 1 :(得分:0)

您的代码有什么问题?

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

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

继承?

根据documentation

  

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

如何分享方法?

@K Scandrett的答案很棒,可能是最好的做法,但我最喜欢的解决方案是:

在DialogComponentController中:

$rootScope.$emit("abc"); 

在PanelController中:

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

答案 2 :(得分:0)

检查此工作示例。

 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>