2014-02-24 125 views
1

我读过一些类似的回答我的问题控制器通信,如this one虽然不能将其翻译成我自己的要求 - 来自缺乏了解......指令与分离范围与AngularJS

我有一个控制器:

appControllers.controller('TransactionsCtrl', ['$scope', 'InfiniteScrollingDataService', function ($scope, dataService) { 
    // setup our scope properties 
    $scope.$root.title = 'Transactions'; 
    var urlQuery = { 
     skip: 0, 
     take: 25, 
     search: '', 
     order: 'DateTimeCreated', 
     orderBy: 'desc', 
     transactionTypeID: null, 
     transactionStatusID: null 
    }; 
    var apiUrl = 'api/transactions'; 
    $scope.transactions = new dataService(apiUrl, urlQuery); 

    $scope.Filter = function (senderParent, type, id) { 
     $scope.FilterApplied = true; 
     console.log('filter in controller: ' + senderParent + ' ' + type + ' ' + id); 
    } 
}]); 

而且我有一个指令:

appDirectives.directive('bootstrapListItems', ['$rootScope', function ($rootScope) { 

    return { 
     restrict: 'A', 
     templateUrl: 'bootstrapDropDownItems.html', 
     link: function (scope, element, attrs) { 

      scope.type = attrs.useGlobaljsonObject; 
      scope.parentElement = attrs.id; 
      scope.items = []; 

      var obj = $rootScope.globalJSON[scope.type]; 

      for (o in obj) { 
       scope.items.push({ key: o, value: obj[o] }) 
      } 
     }  
    } 

}]); 

而对于我的指令模板:

<script type="text/ng-template" id="bootstrapDropDownItems.html"> 

    <li class="active"><a href="#" class="lnkFilterList">- Any -</a></li> 
    <li ng-repeat="item in items"> 
     <a href="#" class="lnkFilterList" ng-click="Filter(parentElement, type, item.key)">{{item.value}}</a> 
    </li> 

</script> 

如果我不隔离指令的作用域,那么控制器被调用正确,我看到控制台注销我的参数。

但是,我(想)我需要隔离范围,因为该页面上会有这个指令的倍数。

当我添加scope: {}到我的指令控制器功能不再被调用。

我也尝试将我的ng-click更改为ng-click="$parent.Filter(.....)" - 这似乎也没有工作。

任何人都可以请我指出正确的方向吗?

+0

这将有助于解决您的问题http://stackoverflow.com/questions/15991137/calling-method-of-parent-controller-from-a-directive-in-angularjs/15991525#15991525 –

回答

3

ng-click="$parent.Filter(.....)"不起作用,因为您在ng-repeat中创建了一个(非隔离)范围。在这种情况下,你会写

ng-click="$parent.$parent.Filter(.....)" 

,但不这样做......

你可以发出在单击事件处理程序的事件,并在控制器中侦听它。

<script type="text/ng-template" id="bootstrapDropDownItems.html"> 

    <li class="active"><a href="#" class="lnkFilterList">- Any -</a></li> 
    <li ng-repeat="item in items"> 
     <a href="#" class="lnkFilterList" ng-click="onClick(parentElement, type, item.key)">{{item.value}}</a> 
    </li> 

</script> 

指令:

appDirectives.directive('bootstrapListItems', ['$rootScope', function ($rootScope) { 

    return { 
     restrict: 'A', 
     templateUrl: 'bootstrapDropDownItems.html', 
     link: function (scope, element, attrs) { 

      scope.type = attrs.useGlobaljsonObject; 
      scope.parentElement = attrs.id; 
      scope.items = []; 

      var obj = $rootScope.globalJSON[scope.type]; 

      for (o in obj) { 
       scope.items.push({ key: o, value: obj[o] }) 
      } 
      scope.onClick = function(){ 
       // pass an array of original arguments to the event 
       scope.$emit('someEventName', Array.prototype.slice.call(arguments)); 
      }; 
     }  
    } 

}]); 

控制器:

appControllers.controller('TransactionsCtrl', ['$scope', 'InfiniteScrollingDataService', function ($scope, dataService) { 
    // setup our scope properties 
    $scope.$root.title = 'Transactions'; 
    var urlQuery = { 
     skip: 0, 
     take: 25, 
     search: '', 
     order: 'DateTimeCreated', 
     orderBy: 'desc', 
     transactionTypeID: null, 
     transactionStatusID: null 
    }; 
    var apiUrl = 'api/transactions'; 
    $scope.transactions = new dataService(apiUrl, urlQuery); 

    $scope.$on('someEventName', function(e, args){ 
     // call the $scope.Filter function with the passed array of arguments 
     $scope.Filter.apply(null, args); 
    }); 
    $scope.Filter = function (senderParent, type, id) { 
     $scope.FilterApplied = true; 
     console.log('filter in controller: ' + senderParent + ' ' + type + ' ' + id); 
    } 
}]); 
+0

嗨。我喜欢这个解决方案,因为它可以让我在指令中更改所选项目的某些课程信息。然而,我几乎复制/粘贴这个,出于某种原因,我的参数在我的$ scope中是空的。$ on('filterSelected',function(e,args){...'并且都是undefined在我的$ scope.Filter函数。任何想法,我可能会出错? – Darren

+0

其实 - 如果我改变'Array.prototype.slice(参数)'只是'参数'它一切按规定工作。不知道为什么(不使用片之前......) – Darren

+0

任何想法为什么Array.prototype.slice(arguments)返回一个空数组? – Darren

1

拥有在多个地方使用,并不意味着你不能使用共享范围的指令。如果指令总是显示相同的状态(因此每个继承和操作控制器的相同属性),或者它们每个都打算显示它们自己的状态版本(因此被隔离),那么这个决定归结为。因为你在$ scope.FilterApplied中设置了一个控制器级变量,我假设你只是想在页面上重复相同的控件?如果是这样,你可以坚持一个继承范围。

如果不是,每个指令都需要它自己的功能,您最好将Filter代码移动到指令和控制器都注入的服务中,以便实用程序功能可以共享,但设置和过滤器的状态是根据范围而不是共享的。

最终取决于你如何使用它。

+0

我假设(由于缺乏这方面的知识),我将需要一个隔离范围。网页上会有几个使用此指令的元素。每个显示列表中的不同项目。另外,当选择过滤器的项目时,我需要设置所选项目的类别。在这种情况下,仍然不确定是否需要隔离作用域。 – Darren

+0

继承作用域将简单地允许它继承其父代的作用域,而不是创建自己的作用域。如果您显示的是同一个列表,并且它由控制器中的对象/属性确定,那么继承范围是最简单的路径。指令的每个实例都可以包含属性,以更改它们显示的列表的哪一部分。只有在操作和封装自己的数据副本时,才需要隔离范围。否则,每次更改控制器列表时,它们都会一起更改。这只是一个原型链。 –

+0

啊,好的。现在它变得更清晰了。在这些列表中没有双向绑定或类似的东西。这只是告诉控制器从应用此过滤器的web api获取一些数据。我喜欢kamilkp给予的解决方案,因为我可以在被选中的项目的指令内做更多的事情 - 更改类等等。谢谢你澄清 – Darren