3

I'm new to angular and I'm creating a simple app. It navigates between projects, pulled in via JSON:

http://plnkr.co/edit/FTfa1rcVaf85xTu65oSR?p=preview

I am also using a factory, where I make a call such as get or getOne, so that it deals with the $http in one place, only calling it if the data hasn't already been fetched.

This all works fine when you start on the home page, but when you start on an individual project page, both get and getOne are called at the same time, pulling in duplicate data. You can test this by opening the Plunker in it's own window and going to a url such as /#/projects/1.

I know why this is happening, I just can't figure out how to stop it.

Is there a simple fix for this or am I going about it the completely wrong way?

Thanks for taking a look.

AlexKempton
  • 1,648
  • 15
  • 28
  • Line 48: var projects = this.get(); - don't think you need that if you've previously fetched all the projects? – Ally Jan 29 '15 at 20:03
  • Hey @Ally, that's correct if you only load from the home page, but if you start with a URL such as `/project/1`, both `get` and `getOne` fire at the same time and `getOne` has nothing to grab. Perhaps I need a way to wait for the first `get` call to finish? Feels like I'm overcomplicating a simple task. – AlexKempton Jan 29 '15 at 20:23

1 Answers1

5

Have your functions return promises via $q, instead of raw data. Then you'll be able to chain them with .then() to achieve the wait you need:

get: function() {
    // Create a deferred object
    var deferred = $q.defer();

    // Do stuff in here
    // ...
    // and depending on the results,
    // call deferred.resolve(data) or deferred.reject(error)

    // Return the promise object
    return deferred.promise;
}

Then, in the code that calls this function, you can:

MyFactory.get().then(function (data) {
    $scope.var = data;
}

This pattern is pretty common in Angular, and works well.

Updated plunkr: here. I switched around the way you were simulating the server request lag so that I could easily resolve my deferred object in the .success() callback of $http.

Nate Barbettini
  • 51,256
  • 26
  • 134
  • 147
  • Thanks so much @Nate, I played around with `$q.defer` earlier but had no luck! I'm still confused as to how it fixes this situation, I knew it was useful for when you have multiple functions that all have to return, but can't see how it is useful here. Does it also prevent a function being called multiple times? All the examples I've read only talk about the chaining. – AlexKempton Jan 29 '15 at 21:13
  • 1
    No, `$q` does not prevent the function from being called multiple times. All this pattern here accomplishes is "wrapping" an operation that will be asynchronous in a promise so you can properly run code after the operation completes. Since the `get()` and `getOne()` functions encapsulate an async operation, it's easiest if the functions themselves return promises. A lot of Angular libraries return promises in this way. – Nate Barbettini Jan 29 '15 at 21:18
  • I see. This fixes my issue but doesn't actually prevent the call being made twice. This is problematic because the factory contains a `projects` array that needs to be populated and kept up to date, for use in other methods (that I didn't include in the example). Perhaps this method just isn't feasible, however. – AlexKempton Jan 29 '15 at 21:44
  • 1
    To solve that problem, you could use a locking mechanism (like setting a flag to `true` when the first call is made) so that any subsequent calls after the first one will be returned with the same (original) promise, or be immediately returned with the cached data. Should be pretty easy to do -- let me know if you have trouble. – Nate Barbettini Jan 29 '15 at 21:48
  • 1
    Cheers for the advice. Had to do a fair bit of shuffling to get it to work, but got there in the end, with a new found understanding of `defer`! http://plnkr.co/edit/R2NrNDhz3Dn2si1UMuFf?p=preview – AlexKempton Jan 29 '15 at 22:55
  • Great! I took a quick glance and it looks like you have a good solution there. Glad I could help. – Nate Barbettini Jan 29 '15 at 23:23