Search code examples
javascriptangularjsangularjs-serviceangular-promiseangularjs-factory

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


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:

enter image description here

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


Solution

  • 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);
        };
    }