更新与绑定数据无关的范围属性的更改时的ng-repeat

时间:2015-04-15 00:56:31

标签: javascript angularjs

我正在使用Angular(1.2.1)应用,并且我在模板中获得了ng-repeat的指令,如下所示:

 <div ng-repeat="item in list | filter: filterList"></div>

 <button ng-click="setColorMode('red')">Show only red items</button>
 <button ng-click="setSizeMode('small')">Show only small items</button>
 <!-- etc... -->

指令控制器中的类似内容:

$scope.list = [
    { color: 'red',  size: 'large' },
    { color: 'blue', size: 'small' }
    //...
]

$scope.colorMode = null; 
$scope.sizeMode = null;

$scope.setColorMode = function(value){$scope.colorMode = value;}
$scope.setSizeMode = function(value){$scope.sizeMode = value;}


$scope.filterList = function(item){

    if ($scope.colorMode){
        if ($scope.colorMode != item.color) return false;
    }
    if ($scope.sizeMode){
        if ($scope.sizeMode != item.size) return false;
    }

    return true;
}

colorModesizeMode被初始化为null,这意味着所有颜色和大小的所有项都显示在repeat中(因为filter函数中的两个条件都计算为false,所以true是回)。

UI允许用户过滤列表以仅显示给定大小和/或颜色的项目,在这种情况下,相应的$scope.___mode变量设置为给定的值,导致过滤器功能检查和对于其字段值与给定值不匹配的项目,返回false。

我的问题是,在模式之间切换会更改$ scope上的变量,但不会更改ng-repeat绑定的数据。因此,当模式改变时,过滤器功能不会被重新执行,并且ng-repeat的内容保持不变,直到数据中的某些内容发生变化。

直观地说,我曾预料到,因为那些$ scope字段用于确定ng-repeat中明确提到的过滤器函数的结果,所以angular会监视这些值并更新它们。唉,情况似乎并非如此,所以我要问:

做我想做的事最干净的方法是什么?

我可以通过在模式设置器功能中修改数据阵列上的某些内容来解决这个问题,但是(与我此处的简化示例相反),数据不属于控制器 - 它通过它访问一个与其他控制器同时共享的服务,所以我真的不愿意这样做。无论如何,肯定有更好的解决方案......对吧?

2 个答案:

答案 0 :(得分:0)

您可以将ng-repeat绑定到新的$scope.filteredList列表,并将其初始化为与$scope.list具有相同的数据。新div:

<div ng-repeat="item in filteredList"></div>

编辑:为了更好地优化这一点并使其成为单个$watch函数,您应该将每个模式变量添加到单个对象$scope.modes。然后,您的模式将存储为$scope.modes.colorMode$scope.modes.sizeMode

然后,您可以使用$watchCollection变量上的$scope.modes来观察任何模式的变化。在该手表中,您可以在$scope.list上运行内置过滤器,如下所示:

$watchCollection('modes', function(newValue, oldValue){
    angular.copy($scope.list, $scope.filteredList);
    if($scope.modes.colorMode){
        $scope.filteredList = $filter('filter')($scope.filteredList, {color: $scope.modes.colorMode});
    }
    if($scope.modes.sizeMode){
        $scope.filteredList = $filter('filter')($scope.filteredList, {size: $scope.modes.sizeMode});
    }
}

我创建了一个简单的JSFiddle here

答案 1 :(得分:0)

您有以下几种选择: 1.手动过滤(创建数组filteredList,填充它,在方法setXXXMode中手动重新计算) 2.在js:

中编写自定义过滤器
app.filter('myfilter', function() {
  return function(itemlist, mode, value) {
    if (mode...)
  }
})

in html:

ng-repeat="item in list | myfilter:mode:value"
<button ng-click="mode='color';value='red'">Show only red items</button>

第二种方法看起来更好,在这里我更喜欢它;但是如果你的数组很大并且包含复杂的对象,有时候1种方法会更好,因为你可以随时控制过滤启动的频率。

你可以使用这样的过滤器:

P.S。如果你的例子是准确的,那么你可以使用:

ng-repeat="item in list | filter:{mode:value}"
<button ng-click="mode='color';value='red'">Show only red items</button>