0

What I'm trying to do is to resolve the item I need using a loop rather than create a API request for that item due to the fact I already have that item in memory.

So, I have a list if items in my service and when I click to go to the item details I do this:

.state('app.itemDetails', {
        url: '/items/:itemId',
        templateUrl: 'modules/items/views/items.details.view.html',
        controller: 'DetailsController',
        resolve: angular.extend(
            helper.resolveFor('ngDialog'), {
                item: function ($q, $stateParams, itemsManager) {
                    var deferred = $q.defer();
                    var obj = {};
                    var promise = _.each(itemsManager.list, function (item) {
                        if (item.id === $stateParams.itemId) {
                            obj = item;
                        }
                        return $q.when(obj);
                    });

                    $q.all(promise).then(function (item) {
                        deferred.resolve(item);
                    });

                    return deferred.promise;
                }
            }
        )
    })

It looks like it bypass the _.each and return always the same item... How can I handle it?

EDIT:

// Generates a resolve object by passing script names
  // previously configured in constant.APP_REQUIRES
  this.resolveFor = function () {
    var _args = arguments;
    return {
      deps: ['$ocLazyLoad','$q', function ($ocLL, $q) {
        // Creates a promise chain for each argument
        var promise = $q.when(1); // empty promise
        for(var i=0, len=_args.length; i < len; i ++){
          promise = andThen(_args[i]);
        }
        return promise;

        // creates promise to chain dynamically
        function andThen(_arg) {
          // also support a function that returns a promise
          if(typeof _arg == 'function')
              return promise.then(_arg);
          else
              return promise.then(function() {
                // if is a module, pass the name. If not, pass the array
                var whatToLoad = getRequired(_arg);
                // simple error check
                if(!whatToLoad) return $.error('Route resolve: Bad resource name [' + _arg + ']');
                // finally, return a promise
                return $ocLL.load( whatToLoad );
              });
        }
        // check and returns required data
        // analyze module items with the form [name: '', files: []]
        // and also simple array of script files (for not angular js)
        function getRequired(name) {
          if (appRequires.modules)
              for(var m in appRequires.modules)
                  if(appRequires.modules[m].name && appRequires.modules[m].name === name)
                      return appRequires.modules[m];
          return appRequires.scripts && appRequires.scripts[name];
        }

      }]};
  }; // resolveFor

EDIT 2:

                    var id = $stateParams.itemId;
                    return _.each(ItemsManager.list, function (item) {
                        if (item.id == id) {
                            console.log('found');
                            console.log(item);
                            return item;
                        }
                    });

In the console.log I receive the item correctly. The view do not receive it...

11
  • How does the helper work? Is it injected in some way? You know you can't inject services in the config-phase right? Commented Dec 9, 2015 at 16:52
  • Added the helper code. Commented Dec 9, 2015 at 17:07
  • Sure, and where is this code? In a service? Because you can't inject services in config phase. What happens if you remove this part and just do the item resolve? Commented Dec 9, 2015 at 17:12
  • It works fine in all my other routers... it resolve for the dependencies and if I do an asynchronous query it resolve it correctly... What I'm trying to do here is to avoid the AJAX call to get an object already in my list... And that helper is part of a provider. Commented Dec 9, 2015 at 17:15
  • OK, I'm not sure what to do next... But your console.log in the controller, does it actually log anything? What do you get if you console.log the item from inside the resolve function (if you use eg the answer I provided) Commented Dec 9, 2015 at 17:50

3 Answers 3

1

_.each doesn't return what you return in the predicate. Use _.map instead. _.map will return an array of the objects you return in the predicate.

View the docs.

Also, it's not entirely clear what you are trying to do. You don't need to return a promise. If you only want to return the item in the itemsManager.list that correspond to the $stateParams.itemId, you can use

    item: function ($stateParams, itemsManager){
     return _.find(itemsManager.list, 
            function(item){
              return item.id === $stateParams.itemId;
            }
         );
}

and return that specific item.

Sign up to request clarification or add additional context in comments.

6 Comments

Before using each I was using find without success... It will be nice if you can provide a full example. Thanks...
Sorry, the edit is made from my phone, so not perfectly formatted, but I think you get what I mean
What I'm trying to do is exactly what you said... I have a list of items and I have to return the one that match the id of the $stateParams. I'm getting crazy because I can not do it... I just pasted your code, it load the page but the $scope.item is not updated with item returned by router. :(
it's just $scope.item = item with a console.log($scope.item); Item is passed like .controller('detailsController', function ($scope, item) {...})
Please show how this helper object is declared/used. From the provided snippet it looks like it is an injected service. But you can't inject services in the config-phase, which is where you set up these states
|
1

Why don't you simply do this...?

item: function ($q, $stateParams, itemsManager) {
    var deferred = $q.defer();
    _.each(itemsManager.list, function (item) {
        if (item.id === $stateParams.itemId) {
            deferred.resolve(item);
            return false; //stop iterating
        }
        return true;
    });

    return deferred.promise;
}

I am assuming there is only one item that meet the condition

UPDATE: On a second thought I think it is useless to use a promise there, the execution will be blocked in the iteration. You can return the found item directly, the resolve property in the state can be defined with a function that returns a value too instead of a promise.

item: function ($stateParams, itemsManager) {
    var obj;
    _.each(itemsManager.list, function (item) {
        if (item.id === $stateParams.itemId) {
            obj = item;
            return false; //stop iterating
        }
        return true;
    });

    return obj;
}

7 Comments

It keep loading without returning the item... :(
I see it, unfortunately I don't know how to edit it let it work as expected... Could you please add a code snippet for your new comment? Thanks
check my snippet above
I was doing exactly like that before starting using promises. The problem is that it render then page before resolving the item and I see only errors within the page...
Using each in this way is exactly like using find, only you can't break each with returning false like that. Find will break when the predicate returns true
|
0

You could use _.find instead of looping through the entire list.

var item = _.find(itemsManager.list, {id : $stateParams.itemId});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.