使用隔离范围使用嵌套指令调用父控制器的函数

时间:2016-01-18 19:53:53

标签: javascript angularjs angularjs-directive

我有一个treeview指令,我试图从父控制器调用一个函数,我似乎无法得到函数来调用。我不确定是否是由于树视图的结构和子元素的嵌套或者是什么。

在我的html中,我将指令声明为:

<div ng-controller="treeController as vm">
    <tree src="myList" filter="doSomething()"></tree>
    <a ng-click="clicked()"> link</a>
</div>

我在指令中声明了一个属性/参数filter,它应该调用主控制器中的doSomething()函数。

主控制器包含以下代码(用于构建树以及调用函数的测试。

app.controller("treeController", ['$scope', function($scope) {

    var vm = this;

   $scope.doSomething = function () {
        var item = data;
   }

   $scope.clicked = function () {
       alert('clicked');
   }

        $scope.myList = {
            children: [
              {
                  name: "Event",
                  children: [
                    {
                        name: "Event Date",
                        children: [
                          {
                              name: "2008",
                              FilterType: '_eventStartDate',
                              Parent: '_event'
                          },
                          {
                              name: "2009",
                              FilterType: '_eventStartDate',
                              Parent: '_event'
                          }
                        ]
                    },
                    {
                        name: "Event Attendee",
                        children: [
                          {
                              name: "Person 1",
                              FilterType: '_eventAttenddeeName',
                              Parent: '_Event'
                          },
                          {
                              name: "Person 2",
                              FilterType: '_eventAttenddeeName',
                              Parent: '_Event'
                          }
                        ]
                    }
                  ]
              }]
        };
}]);

在我的指令中,我声明了隔离范围,以及参数filter(第二个app.directive),我使用模型绑定前缀'&'作为前缀。在模板中,我然后调用ng-click,它应该调用主控制器中的函数doSomething()。但是......没有骰子。

app.directive('tree', function() {
//builds the tree
    return {
        restrict: 'E', 
        replace: true,
        scope: {
            t: '=src'
        },
        template: '<ul><branch ng-repeat="c in t.children" src="c"></branch></ul>'
    };
});

app.directive('branch', function($compile) {
//directive that builds the children/branches
    return {
        restrict: 'E', 
        replace: true, 
        scope: {
            b: '=src',
            filter: '&'
        },
        template: '<li><input type="checkbox" ng-click="filter()" ng-hide="visible" /><a>{{ b.name }}</a></li>',
        link: function (scope, element, attrs) {

           var has_children = angular.isArray(scope.b.children);
            scope.visible = has_children;
            if (has_children) {
                element.append('<tree src="b"></tree>');

                $compile(element.contents())(scope);
            }

            element.on('click', function(event) {
                event.stopPropagation();

                if (has_children) {
                    element.toggleClass('collapsed');
                }
            });
            //test to call function within directive
            //scope.doSomething = function(b) {
            //    alert('test');
            //}
        }
    };
});

我发布了公开jsFiddle以及工作代码示例

对我错过的任何建议?

现在我只是试图调用该方法,但最终我需要将所选项目作为参数传递回控制器,但是现在我只想弄清楚为什么我的控制器中的函数会不被打电话。

提前致谢

更新 有人建议将过滤器的声明从分支移动到树指令。

我在本地更新了代码,因此树指令如下所示:

app.directive('tree', function() {
    return {
        restrict: 'E', 
        replace: true,
        scope: {
            t: '=src',
            filter: '&'
        },
        template: '<ul><branch ng-repeat="c in t.children" src="c"></branch></ul>'
    };
});

注意:filter参数已从辅助指令中删除。输出没有变化。控制器内的功能仍未调用。

2 个答案:

答案 0 :(得分:0)

你的树指令没有filter方法。你的branch指令只有那个属性

<div ng-controller="treeController as vm">
    <tree src="myList" filter="doSomething()"></tree>
    <a ng-click="clicked()"> link</a>
</div>

app.directive('tree', function() {
//builds the tree
    return {
        restrict: 'E', 
        replace: true,
        scope: {
            t: '=src',
            filter: '&'
        },
        template: '<ul><branch ng-repeat="c in t.children" src="c" filter="doSomething()"></branch></ul>'
    };
});

app.directive('branch', function($compile) {
//directive that builds the children/branches
    return {
        restrict: 'E', 
        replace: true, 
        scope: {
            b: '=src',
            filter: '&'
        },
        template: '<li><input type="checkbox" ng-click="filter()" ng-hide="visible" /><a>{{ b.name }}</a></li>',
        link: function (scope, element, attrs) {

           var has_children = angular.isArray(scope.b.children);
            scope.visible = has_children;
            if (has_children) {
                element.append('<tree src="b"></tree>');

                $compile(element.contents())(scope);
            }

            element.on('click', function(event) {
                event.stopPropagation();

                if (has_children) {
                    element.toggleClass('collapsed');
                }
            });
            //test to call function within directive
            //scope.doSomething = function(b) {
            //    alert('test');
            //}
        }
    };
});

答案 1 :(得分:0)

<强>更新 Sundar的评论让我走上正确的道路这里是更新的指令,对我来说主要的问题是我正在使用嵌套指令,因此嵌套项(正在进行函数调用)超出了控制器的范围更正这包括Sundar的更改,但要使嵌套指令起作用,我必须在父指令级别显式设置控制器。如果您需要在应用程序的多个区域中使用指令,我意识到这不是一个好的选择。但对我来说,该指令仅用于一个位置,因此该解决方案有效。如果有人有任何其他建议或更好的方法,我会感激他们。

app.directive('tree', function() {
    return {
        restrict: 'E', 
        replace: true,
        scope: {
            t: '=src',
            filter: '&'
        },
        controller:'treeController', //explicitly set the controller of the parent directive
        template: '<ul><branch ng-repeat="c in t.children" src="c" filter="doSomething(data)"></branch></ul>'
    };
});

app.directive('branch', function($compile) {
    return {
        restrict: 'E', 
        replace: true, 
        scope: {
            b: '=src',
            filter: '&'
        },

        template: '<li><input type="checkbox" ng-click="innerCall()" ng-hide="visible" /><a>{{ b.name }}</a></li>',
        link: function (scope, element, attrs) {

           var has_children = angular.isArray(scope.b.children);
            scope.visible = has_children;
            if (has_children) {
                element.append('<tree src="b"></tree>');

                $compile(element.contents())(scope);
            }

            element.on('click', function(event) {
                event.stopPropagation();

                if (has_children) {
                    element.toggleClass('collapsed');
                }
            });
            scope.innerCall = function() {
                scope.filter(scope.b);
            }
        }
    };
});