AngularJS promises and timing with custom filters -
i'm having massive headache right regarding custom filters timing. have demo (learning angular) gallery app in using custom filter checkboxes select different categories of photos.
the simptoms: when using custom filter on ng-repeat directive noticed http://screencast.com/t/xpgx1lytu9yp ... after few hours of debugging got conclusion problem data json not there when filter runs, though without filter seems load ok.
here plnkr http://plnkr.co/edit/kbbg67 (i copy pasted code, modified bit, not working yet, fix in morning, code)
i started using deferring , promises in services fetches json data controllers , else wait data load, [services]
angular.module('services', []).factory('getallposts', ['$http', '$q', '$timeout', function($http, $q, $timeout) { //defining promised based api var deffered = $q.defer(); //the getdata function var getdata = function() { //defining empty data array var thedata = {}; //using $http dat $http.get('/wordpress/api/get_recent_posts/').success(function(data) { // prepare data here //assigning our data thedata array. // // new stuff here, pushing data 1 one populate array faster isn't emtpy .. ?! thedata.length = 0; (var = 0; < data.length; i++) { thedata.push(data[i]); } thedata = data; }); //setting timeout data , waiting if necesarry. $timeout(function() { deffered.resolve(thedata); }, 1000); //when s done, return promise... think so. ?! return deffered.promise; } return { //creating getdata handler use in controllers. getdata: getdata }; }])
my controller [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; }) } ])
i'm using getdata().then() fetch while it's loaded.
i realize not telling same thing filter [filter]
angular.module('filters', []) .filter('checkboxfilter', function($filter) { return function(post, prefs) { var i, j, k, n, out, matchingpost = []; // loop through post (i = 0; < post.length; i++) { console.log('i passed length ... wtf?') out = false; n = 0; if (prefs) { // each item, loop through checkboxes categories (j = 0; j < prefs.length; j++) { // each category, loop through checkboxes categories of current category (k = 0; k < prefs[j].categories.length; k++) { // test if current item property name same filter name if (post[i][prefs[j].slug] === prefs[j].categories[k].slug) { // test if checkbox checked property (prefs[j].categories[k].value) ? n++ : out = true; break; } } if (out) break; // if 1 filter in each categories true, add item matchingpost if (n === prefs.length) { matchingpost.push(post[i]); } } } } return matchingpost; } })
the thing started reading angular book , didn't understood many things went hands on experience, every bit falls place 1 ... i've been spending time on it. think if take on again make more sense.
question: how rid of errors , make filter read data after it's been loaded?
side-question: through different service outputting existing categories in backbone (wordpress) , ng-repeat them in checkboxes, how link checkboxes results of filters? (it isn't obvious me yet, though have seen examples....)
side-question 2: why requests multiply, in first screenshot posted, no wait, part talking http://screencast.com/t/lcrwnliol3u ... have 44 posts far, after data there, filter calls again.
this behaviour hapenned on other things ... wondering doing wrong.
annotation: using angular 1.2.0rc1 of tonight, behaviors appeared other versions used: 1.0.7.0, 1.1.5.
i think real way override default $interpolateprovider
enable filters return promises. way, defer rendering of filtered expressions until resolved.
remember, though, cannot chained filters trivially. forced rewrite $parse
enable support chaining of promises.
i faced same problem @ moment, , such, might go ahead , it. if so, make sure post link answer on github repository project (http://github.com/agileapes/bootstrapui).
edit
another (mostly) easy way pass arbitrary argument filter updated via http call (or other means):
.controller("mycontroller", function ($scope, $q, $timeout) { $scope.result = null; var deferred = $q.defer(); $timeout(function () { $scope.result = [1, 2, 3, 4]; }, 2000); });
here have updated result via timeout, don't have way. demonstration. update $scope.result
in way choose.
here sample filter, include even numbers in 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; } });
now, in view, can use them together, way:
<div ng-controller="mycontroller"> <ul ng-if="result.length"> <!-- nice not pollute dom empty lists --> <li ng-repeat="item in result | even">{{item}}</li> </ul> </div>
after couple of seconds or so, list should populated , ngrepeat
directive should receive filtered result.
the trick, here, have made digest cycle happen particular result
variable, means filter being fed variable re-executed, in turns means happen smoothly , expected.
Comments
Post a Comment