我现在对定制过滤器定时问题非常头疼。 我有一个演示(学习Angular)图库应用程序,我在其中使用带有复选框的自定义过滤器来选择不同类别的照片。
简单:当在ng-repeat指令上使用自定义过滤器时,我注意到这个http://screencast.com/t/xPGX1lyTu9Yp ...经过几个小时的调试后我得出结论,问题是来自的数据来自过滤器运行时我的JSON不存在,但是如果没有过滤器,一切似乎都加载好了。
以下是此http://plnkr.co/edit/KbBg67 的plnkr(我复制粘贴代码,修改了一下,还没有工作,会在早上修复它,但这是代码)
我开始在我的服务中使用延迟和承诺来获取JSON数据,所以我控制器和其他人都会等待数据加载,就像这样[服务]
angular.module('services', []).factory('getAllPosts', ['$http', '$q', '$timeout',
function($http, $q, $timeout) {
//defining the promised based API
var deffered = $q.defer();
//the getData function
var getData = function() {
//defining a empty data array
var theData = {};
//using $http to get the dat
$http.get('/wordpress/api/get_recent_posts/').success(function(data) {
// prepare data here
//assigning our data to the theData array.
// // New stuff here, we are pushing the data one by one to populate the array faster so it isn't emtpy .. ?!
theData.length = 0;
for (var i = 0; i < data.length; i++) {
theData.push(data[i]);
}
theData = data;
});
//setting a timeout for the data and waiting if necesarry.
$timeout(function() {
deffered.resolve(theData);
}, 1000);
//when it s done, return the promise... i think so. ?!
return deffered.promise;
}
return {
//creating a getData handler to use in controllers.
getData: getData
};
}])
我的控制器就像这样[CONTROLLER]
.controller('ListController', ['$scope', 'getAllPosts', 'getCategories', '$location',
function($scope, getAllPosts, getCategories) {
$scope.name = 'list';
getAllPosts.getData().then(function(data) {
return $scope.posts = data.posts;
});
getCategories.get(function(data){
return $scope.categories = data.categories;
})
}
])
我正在使用getData()。then()在加载时获取它。
我意识到我并没有对过滤器[FILTER]
说同样的话angular.module('filters', [])
.filter('checkboxFilter', function($filter) {
return function(post, prefs) {
var i, j, k, n, out, matchingpost = [];
// loop through the post
for (i = 0; i < post.length; i++) {
console.log('I passed the length ... wtf?')
out = false;
n = 0;
if (prefs) {
// for each item, loop through the checkboxes categories
for (j = 0; j < prefs.length; j++) {
// for each category, loop through the checkboxes categories of the current category
for (k = 0; k < prefs[j].categories.length; k++) {
// test if the current item property name is the same as the filter name
if (post[i][prefs[j].slug] === prefs[j].categories[k].slug) {
// test if checkbox is checked for this property
(prefs[j].categories[k].value) ? n++ : out = true;
break;
}
}
if (out) break;
// if one filter in each categories is true, add item to the matchingpost
if (n === prefs.length) {
matchingpost.push(post[i]);
}
}
}
}
return matchingpost;
}
})
问题是我开始阅读一本有角度的书,但我并没有理解很多东西,所以我去了一个实践经验,慢慢地每一点都落到了地方但是这一个...我花了很多时间在它。我想如果我再次接受它会更有意义。
问题:如何摆脱这些错误并使过滤器在加载后读取数据?
侧面问题:通过不同的服务,我输出我骨干网中的所有现有类别(Wordpress)并在复选框中重复这些类别,如何将复选框链接到此过滤器的结果? (这对我来说并不明显,虽然我已经看过一些例子......)
侧面问题2:为什么我的所有请求都会成倍增加,就像我发布的第一个屏幕截图一样,没有等待,这是我正在讨论的部分http://screencast.com/t/lcrWnlioL3u ...到目前为止我只有44个帖子,但看起来即使数据存在,过滤器也会再次调用它。
这种行为也与其他事情有关......我想知道我做错了什么。
注释:我今晚使用角度1.2.0rc1,所有行为都出现在我使用的其他版本中:1.0.7.0,1.1.5。
答案 0 :(得分:4)
我认为实现此目的的真正方法是覆盖默认的$interpolateProvider
以启用返回promises的过滤器。这样,您可以推迟渲染某些已过滤的表达式,直到它们被解析。
但请记住,您不能轻易地为链式过滤器执行此操作。您可能也会被迫重写$parse
以启用对承诺链接的支持。
我现在面临着同样的问题,因此,我可以继续前进而去做。如果是这样,我将确保在我的项目(http://github.com/agileapes/bootstrapui)的github存储库上发布答案的链接。
修改强>
另一种(大多数)简单方法是将任意参数传递给通过HTTP调用(或任何其他方式)更新的过滤器:
.controller("MyController", function ($scope, $q, $timeout) {
$scope.result = null;
var deferred = $q.defer();
$timeout(function () {
$scope.result = [1, 2, 3, 4];
}, 2000);
});
这里我刚刚通过超时更新了结果,但我不必这样做。这只是为了演示。您可以以任何方式更新$scope.result
。
以下是一个示例过滤器,结果中只包含偶数数字:
.filter('even', function () {
return function (input) {
if (!angular.isArray(input)) {
return input;
}
var result = [];
angular.forEach(input, function (x) {
if (x % 2 == 0) {
result.push(x);
}
});
return result;
}
});
现在,在我看来,我可以这样使用它们:
<div ng-controller="MyController">
<ul ng-if="result.length"> <!-- It is nice to not pollute the DOM with empty lists -->
<li ng-repeat="item in result | even">{{item}}</li>
</ul>
</div>
几秒钟后,应该填充列表,ngRepeat
指令应该接收过滤结果。
这里的诀窍是我已经为该特定result
变量进行了摘要循环,这意味着正在为该变量提供的过滤器也将被重新执行,这反过来意味着一切都会按预期顺利进行。
答案 1 :(得分:1)
没有必要创建自己的承诺,因为AngularJS $http
服务已经为您完成此任务。
因此,您的服务可以简化为:
angular.module('services', []).factory('getAllPosts', ['$http', function($http) {
return {
getData: function() {
// Return the promise that is created by the $http service
return $http.get('/wordpress/api/get_recent_posts/')
}
};
}]);
然后在你的控制器中:
angular.module('yourModule')
.controller('ListController', ['$scope', 'getAllPosts',
function($scope, getAllPosts) {
$scope.items = []; // Placeholder for the data
getAllPosts.getData()
.success(function(data, status, header, config){
// Fill placeholder with data as soon as it is received
$scope.items = data;
});
}
]);
然后在您看来,您可以使用ng-model
指令或ng-repeat
指令来显示您的数据:
<li ng-repeat="item in items">
{{item.someProperty}}
</li>
如果您想应用自定义过滤器,请使用:
<li ng-repeat="item in items | your_filter">
{{item.someProperty}}
</li>
当$scope.items
更新时,AngularJS会自动更新视图,因此您无需为此编写额外的代码。
希望有所帮助!
答案 2 :(得分:0)
//defining a empty data array
var theData = {};
这是一个对象定义,而不是数组定义。尝试用
替换它var theData = [];
它可能会解决您的问题。
答案 3 :(得分:0)
似乎 - 虽然相当昂贵 - 解决这个问题的方法是循环,直到信息到达。 - 欢迎任何其他解决方案。
像这样:
.filter('checkboxFilter', function() {
return function(post, prefs) {
//define empty vars, strict mode
var i, j, k, n, out, matchingpost = [];
//check to see if the posts have arrived
if (post == undefined) {
//posts are not here yet
} else {
//posts have arrived.
//iterate through all the posts
for (i = 0; i < post.length; i++) {
out = false;
n = 0;
var eachPostCategories = post[i].categories;
//console.log(eachPostCategories)
for (j = 0; j < eachPostCategories.length; j++) {
//console.log(' post categories are');
//console.log(eachPostCategories[j]);
if (prefs == undefined) {
//preferences aren't in yet
} else {
//preferences are here.
//now we should iterate through all the preferences and compare them to the posts.
for (k = 0; k < prefs.length; k++) {
//prefs[j].slug
//console.log('categories are');
//console.log(prefs[k].slug)
if (eachPostCategories[j].slug === prefs[k].slug) {
//console.log('this post has the categories');
//console.log(post[i]);
//WHAT DOES THIS LINE MEAN?
/*(prefs[k].slug) ? n++ : out = true;
break;*/
n++
} else {
out = true;
break;
}
console.log('n is ' + n);
}
if (out) break;
// if one filter in each categories is true, add item to the matchingpost
if (n === prefs.length) {
matchingpost.push(post[i]);
}
}
}
}
}
if (matchingpost.length == 0) {
//return matchingpost = post
} else {
return matchingpost;
}
}
})
过滤器还不完美,每个对象都是重复的,我可以根据类别隐藏元素,但我不能让它们出现:|
我似乎没有抓住这个概念,如果有人可以给我一些指示它会很棒。
作为一般概念,我正在比较像:
这样的对象 debug: [{"id":2,"slug":"architecture","title":"Architecture","description":"","parent":0,"post_count":16,"selected":"true"},{"id":13,"slug":"day","title":"Day","description":"","parent":0,"post_count":37,"selected":"true"},{"id":7,"slug":"funny","title":"Funny","description":"","parent":0,"post_count":6,"selected":"true"},{"id":4,"slug":"landscape","title":"Landscape","description":"","parent":0,"post_count":12,"selected":"true"},{"id":11,"slug":"nature","title":"Nature","description":"","parent":0,"post_count":3,"selected":"true"},{"id":12,"slug":"night","title":"Night","description":"","parent":0,"post_count":8,"selected":"true"},{"id":10,"slug":"old","title":"Old","description":"","parent":0,"post_count":3,"selected":"true"},{"id":3,"slug":"people","title":"People","description":"","parent":0,"post_count":15,"selected":"true"},{"id":9,"slug":"rooftops","title":"Rooftops","description":"","parent":0,"post_count":2,"selected":"true"},{"id":8,"slug":"weird","title":"Weird","description":"","parent":0,"post_count":1,"selected":"true"}]
发布有多个类别的对象(例如,帖子Zoomed Houses有Day,Architecture类别)
答案 4 :(得分:0)
对于任何有兴趣的人:
我通过简单地捕获由于未定义对象而引发的错误来解决这个问题,然后抛出类似throw "Object not yet loaded. Trying again...";
的错误
app.filter('translate', function() {
return function(input) {
try {
var index = input.toUpperCase();
if (app.translation[index]) {
if (input[0] === index[0])
return app.translation[index].capitalize();
return app.translation[index];
}
return input;
}
catch(err) {
throw "Translation not loaded yet, trying again...";
}
};
})
app.run(function($http) {
$http.get("translations/" + "NB_ENG" + ".json", {
cache: true
}).success(function(data) {
app.translation = data;
console.info("Translation loaded.");
}).error(function(q,w,e) {
app.translation = 1;
console.error("Failed getting translation: "+q + " | " + w + " | " + e + " | ");
});
});
我在等待翻译文件,然后才能翻译所有单词。 Angular一次又一次地运行过滤器,直到它获得有效的返回。