lemontree lemontree - 1 month ago 53
AngularJS Question

2 controllers depend on a HTTP request inside a factory

So I have 2 controllers that depend on data that is being fetched by a function inside a factory. The factory looks like this:

factory.getData = function() {
const req = {...};
return $http(req).then((res) => {
this.data1 = res.data.response[0];
this.data2 = res.data.response[1];
return res;
})


then in my controllers:

this.factory.getData().then((data) => {
this.controllerData1 = this.factory.data1;
this.controllerData2 = this.factory.data2;
})


Note: I omitted the actual factory name.
This gets me the data I need however both controllers will fire off the http request which is obviously not ideal. So I need the second controller to wait until the data1 and data2 have been defined. How can I make this happen?

Answer
factory.dataPromise = null;

factory.getData = function() {
   if (this.dataPromise !== null) {
      return this.dataPromise;
   }
   else {
       const req = {...};
       return this.dataPromise = $http(req).then((res) => {
           this.data1 = res.data.response[0];
           this.data2 = res.data.response[1];
           return res;
       })
   }
}

This is a little crude but should be able to get the job here, although honestly I would suggest refactoring the code a little. But I wanted to do this answer with as little refactoring as possible.

The key is to always return a promise. As long as you do that, you're alright. If we check if this.data1 and this.data2 are already available, we can return an immediately resolved promise, without the need to make another HTTP call.

Oh, and if it wasn't clear, you'll need to include $q (or replace this with whatever other Promise library you want) to be able to create promises plainly.

To Think About: Not really a serious problem, but when you call factory.getData() you don't actually use the value that is resolved by the promise. That's why in my answer, I just have a variable whateverdata there, because it really doesn't matter what you return based on your code, because it doesn't get used.

Maybe then, it's better to let the promise do the work. I would suggest this refactor in that case:

factory.dataPromise = null;

factory.getData = function() {
   if (this.dataPromise !== null) {
      return this.dataPromise;
   }
   else {
       const req = {...};
       return this.dataPromise = $http(req).then((res) => {
           this.data1 = res.data.response[0];
           this.data2 = res.data.response[1];
           return { data1: this.data1, data2: this.data2 };
       })
   }
}

this.factory.getData().then((data) => {
    this.controllerData1 = data.data1;
    this.controllerData2 = data.data2;
})

It's a little more intuitive, and it actually leverages the benefits of promises. But, in the end it's up to you.

Comments