AngularJS : How to use the $q promise feature in this situation to wait for data to be ready?

允我心安 提交于 2019-12-22 10:05:13

问题


I have a Controller which starts an API call in a Factory. Currently I start the call, then I have a function after that call to check the status of the Array. However I'm not sure how to force it to wait here while the data is being gathered, thus the need for some kind of $q implementation.

As you can see in the screenshot below, vs.tickers returns an empty Object, or Array. Then finally the console.log in GetTickersFactory fires:

1st Controller

if (root.tickerType === 'portfolio') {

    // Call to factory to start the API GETS:
    GetTickersFactory.getTickers('portfolio');

    // I then call a function in the Factory to return the array
    // Which isn't ready yet of course since it returns undefined...
    vs.tickers = GetTickersFactory.returnPortfolioTickers();

    console.log('portfolio');
    console.log('vs.tickers = ', vs.tickers);
}

getTickers function in the GetTickersFactory | Perhaps this helps: the Gist for the full Factory.

function getTickers(type, load, searchedTicker) {
    load = load || loadString; searchedTicker = searchedTicker || '';

    var portfolioTickersArray = [], searchedTickersArray  = [];

    tickersPane.loadingTickersDone = false;

    switch(type) {
        case 'searched':
            ....
            break;

        case 'portfolio':

            if (portfolioCached) {
                // The API Call (cached)
                ApiFactory.getWatchList().then(function(data) {
                    portfolioTickersArray = renderTickers(data.data.tickers, undefined, type);
                    portfolioTickers.that = portfolioTickersArray;
                    tickersPane.loadingTickersDone = true;
                    console.log('portfolioTickersArray: ', portfolioTickersArray);
                    return portfolioTickersArray;
                });

            } else {
                // The API Call (not cached)
                ApiFactory.getWatchListRefresh().then(function(data) {
                    portfolioTickersArray = renderTickers(data.data.tickers, undefined, type);
                    portfolioTickers.that = portfolioTickersArray;
                    portfolioCached = true;
                    tickersPane.loadingTickersDone = true;
                    console.log('portfolioTickersArray: ', portfolioTickersArray);
                    return portfolioTickersArray;
                });
            }
            break;
    }

    function renderTickers(data, searchedTicker, type) {
        ....
    }
}

The return Array function I'm using inside of the getTickersFactory.js I believe I shouldn't use this however and figure out how to use promises instead:

function returnPortfolioTickers() {
    return portfolioTickers.that;
}

Note I did originally try this, but with the same results:

vs.tickers = GetTickersFactory.getTickers('portfolio');

vs.tickers would return undefined


回答1:


Your switch cases should return a promise so that it caller function will .then called when promise gets resolved

Factory Code

function getTickers(type, load, searchedTicker) {
    //other code remains same
    tickersPane.loadingTickersDone = false;
    switch (type) {
        case 'searched':
            return ApiFactory.getTickers(null, load).then(function(data) {
                //other code remains same
                if (tickersPane.tempTickers.length > 0) {
                    //other code remains same
                    return returnData(searchedTickersArray);
                }
                return []; //return default variable to continue promise chain
            });
            break;
        case 'portfolio':
            tickersPane.addOption = false;
            tickersPane.removeOption = true;
            tickersPane.displayTopTags = false;
            tickersPane.displayPortfolio = true;

            if (portfolioCached) {
                return ApiFactory.getWatchList().then(function(data) {
                    //other code remains same
                    return returnData(portfolioTickersArray);
                });
            } else {
                return ApiFactory.getWatchListRefresh().then(function(data) {
                    //other code remains same
                    return returnData(portfolioTickersArray);
                });
            }
            break;
    }
    function renderTickers(data, searchedTicker, type) {
        //this should be as is
    }
    function returnData(data) {
        tickersPane.loadingTickersDone = true;
        return data;
    }
    //tickersPane.loadingTickersDone = true;
    //return data; //removed this line and move to function
}

Controller

if (root.tickerType === 'portfolio') {
    // Call to factory to start the API GETS:
    GetTickersFactory.getTickers('portfolio').then(resp){
         vs.tickers = GetTickersFactory.returnPortfolioTickers();
         console.log('portfolio');
         console.log('vs.tickers = ', vs.tickers);
    };
}



回答2:


If you want to use the ES6-styled promise:

function getTickers(type, load, searchedTicker) {

  return $q(function (resolve, reject) {

     if (doTheGoodThings()) {
       resolve('This is ok!');
     } else {
       reject('This did not work');
     }

  }
}

And then in your controller:

if (root.tickerType === 'portfolio') {

  GetTickersFactory.getTickers('portfolio').then(function (result) {
    console.log('Worked: ' + result);
  }, function (error) {
    console.log('Error: ' + error);
  });

}



回答3:


You already have two methods that return promises (getWatchList and getWatchListRefresh) so you can just return those methods and chain more .thens. No need to use $q here.

Hopefully this simplified example might help steer you in the right direction...

function getTickers(type) {
    var tickers;

    switch(type) {
        // ...
        case 'portfolio': 
            var getList = portfolioCached ? getWatchList : getWatchListRefresh;
            // tickers will be set to the promise returned
            // by getWatchList or getWatchListRefresh
            tickers = getList().then(function(data) {
                if (!portfolioCached) {
                  portfolioCached = true;
                }
                // the result returned by renderTickers will be 
                // passed to any `.then` that is chained
                return renderTickers(data.data.tickers, undefined, type);
            });
        break;
    }

    // return the tickers promise
    return tickers;
}

Then in your controller:

// the `tickers` param here will be the result
// returned by renderTickers()
GetTickersFactory.getTickers('portfolio').then(function(tickers) {
    vs.tickers = tickers;
});


来源:https://stackoverflow.com/questions/31328924/angularjs-how-to-use-the-q-promise-feature-in-this-situation-to-wait-for-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!