筛选传入指令的数据会引发异常
Filter on data passed into directive throws exception
我正在使用一个指令来模板化对象列表。根据指令的使用位置,应筛选模板中呈现的对象列表。在一种方法中,代码如下所示:
person_list.html
<ul>
<li ng-repeat="person in (people | selected:true)">
<a class="selected-{{ person.selected }}" ng-click="toggleSelect( person )">{{ person.name }}</a>
</li>
</ul>
person_list.js
app.directive('personList', function(){
return {
restrict: 'E',
scope: {people: '=list'},
controller: "ListCtrl",
templateUrl: 'person_list.html'
}
});
selected_filter.js
app.filter('selected', function(){
return function(list, criteria){
return list.filter(function(element){
return !!element.selected === criteria;
});
}
});
该指令的使用方式如下:
<person-list list="people"></person-list>
我想使用的另一种方法是从指令外部过滤列表:
person_list.html
<ul>
<li ng-repeat="person in people">
<a class="selected-{{ person.selected }}" ng-click="toggleSelect( person )">{{ person.name }}</a>
</li>
</ul>
该指令将按如下方式使用:
<person-list list="people | selected:true"></person-list>
但是,Angular 不喜欢这样。异常Cannot call method 'filter' of undefined
在筛选器内引发。目标是使指令尽可能简单,部分原因是将此筛选器作为可选组件。
我想知道的是:
- 为什么第一种方法有效,而第二种方法无效?
- 哪些替代方法可以满足这些要求?
请参阅完整的 Plunker 示例。
目前的代码中有很多竞争条件(初始化顺序)和其他微妙之处。
首先,解决您描述的错误。
解决前promise
的初始值是多少
首次评估people | selected:true
时,people
是一个未解决的承诺。因此,angular
调用值为 undefined
的过滤器。这是正确的 (TM) 行为,因为会有过滤器想要捕获该undefined
,然后在后台解析该值时显示一些默认值。这种情况需要在过滤器中处理:
app.filter('selected', function(){
return function(list, criteria){
if (typeof list !== 'undefined') {
return list.filter(function(element){
return !!element.selected === criteria;
});
} else {
return [];
}
}
});
使用 angular 的filter
可以更轻松地将此过滤器编写为people | filter:{'selected' : true}
,该优雅地处理承诺(以及其他所有内容)。我假设您有使用自定义过滤器的理由。
其他问题
指令scope
是先初始化还是控制器的scope
属性people
在ListCtrl
和directive
的独立作用域上定义:
app.directive('personList', function(){
return {
restrict: 'E',
scope: {people: '=list'}, // <-- 'people' on scope
controller: "ListCtrl", // <-- Also defines 'people' on scope
templateUrl: 'person_list.html'
}
});
目前尚不清楚哪些people
实际上会延续到模板中。我怀疑您需要控制器的toggleSelection
函数,但不需要people
字段的初始化。因此,您需要此类内容:
app.directive('personList', function(){
return {
restrict: 'E',
scope: {people: '=list'},
controller: ['$scope', function ($scope) {
$scope.toggleSelect = function (p) {
p.selected = !p.selected;
};
}],
templateUrl: 'person_list.html'
}
});
根据您希望如何与应用程序的其余部分进行通信,您可以在link
函数或controller
中定义toggleSelect
函数(如此处所示)。
关于混合过滤器和承诺
通过这些更改,由于指令上的=list
绑定和返回新列表对象的people | selected:true
,您也会遇到Error: 10 $digest() iterations reached. Aborting!
。我怀疑问题就在这里,因为只使用了对象相等,而没有使用angular.equals
。但是,我不是那里的专家。
我不喜欢在原语以外的任何东西上使用filters
,因为很难确保对象相等并防止此类错误。此外,由于这些问题,我不太喜欢直接在 UI 中使用promises
。
通常,我发现最好让controller
执行过滤任务以及位于UI model
和view
之间的任何其他逻辑。因此,我会在控制器中的$scope
上定义一个属性,该属性是在解决promise
后设置的,然后在模板中使用它。这确实使控制器更厚一些。
工作示例:http://plnkr.co/edit/8eMvGUWsxQwe4fhypBf1?p=preview
您的设置中存在许多问题。建议您在指令中使用完全不同的控制器引用,因为您将数据从ListCtrl
传递到指令,然后在指令中调用相同的控制器并再次检索相同的数据
一个问题是摘要循环将在数据从承诺中可用之前运行指令。承诺似乎不会传递到指令中。这意味着首次运行过滤器时未定义指令中的people
范围
要修复过滤器,请执行以下操作:
app.filter('selected', function(){
return function(list, criteria){
if(!angular.isUndefined(list)){
return list.filter(function(element){
return !!element.selected === criteria;
});
}
}
});
不要尝试筛选指令的属性。 ng-repeat
允许这样做,因为它的指令需要过滤器。将过滤器放在模板中的 ng-repeat 上,或过滤指令本身中的数据。
这是您的 plunker 的一个版本,不会抛出错误
- 用程序搜索JQuery数据表中的文本
- 要求输入在数据列表中
- 正在将数据主题添加到所有项目
- 函数参数中的数据与指定变量之间的任何性能差异
- 在VanillaJS中模拟模型双向数据绑定
- CSS-如何定位内容数据标题
- 使用电话间隙在Android应用程序中显示SQL Lite的数据
- 将数据插入android中的SQLite存储时出现异常
- 每当我试图将简单的图像源转换为数据URL时,就会出现安全错误异常
- 在zapier中发送请求数据时出现空指针异常
- Iframe 数据从父页面发布,如果服务器上发生异常,则重新加载父页面
- 筛选传入指令的数据会引发异常
- AngularJS 2 - 内部属性数据绑定 - 异常:类型错误:无法读取未定义的属性
- 未捕获的异常:每个数据元素都必须实现一个唯一的“id”属性slick.dataview.js
- 处理Rally数据存储中的null异常
- jQuery数据选择器解析日期引发无效的日期异常
- 如何覆盖Sencha Touch数据存储代理异常侦听器
- 服务返回异常数据
- 网页数据格式异常
- html5 canvas-Javascript createImageData抛出DOM异常9,rgb数据不工作