问题
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 .then
s. 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