I am building a vue app that will search YouTube channels based on which options are selected.
When the option is TRUE, I push that string into an array which holds the URLs of the axios.get() requests.
I am looping through that array and running axios.get() and returning the value. I am getting a response under Promise{} with and object inside [[PromiseValue]].
At the end I am combining the responses into a vue data element(catAndDogResults) but I am getting an undefined in the end.
Is there a better way to do what I am trying to do?
data () {
return {
catVideos: true,
dogVideos: true,
catResults: [],
dogResults: [],
catAndDogResults: []
}
},
methods:
search: function() {
var that = this
var cats = 'https://www.googleapis.com/youtube/v3/search?part=snippet&q=cats'
var dogs = 'https://www.googleapis.com/youtube/v3/search?part=snippet&q=dogs'
var urls = []
if (this.catVideos == true) {
urls.push(cats)
}
if (this.dogVideos == true) {
urls.push(dogs)
}
function getVideos() {
for (var i = 0; i < urls.length; i++) {
console.log(axios.get(urls[i])) // returns under [[PromiseValue]]:object
return axios.get(urls[i])
}
}
axios.all([
getVideos()
])
.then(axios.spread(function (catRes, dogRes) {
that.catResults = catRes.data.items
that.dogResults = dogRes.data.items
that.catAndDogResults = that.catResults.concat(that.dogResults)
}))
}
EDITS
Fixed spelling mistakes
Try changing your getVideos() method to return the array after the for loop:
function getVideos() {
var requests = [];
for (var i = 0; i < urls.length; i++) {
requests.push(axios.get(urls[i]));
}
return requests;
}
And then, call it like that:
axios.all(getVideos())
.then(function (catRes, dogRes) { ... })
The answer provided by #tiagodws should fix the issue. I just wanted to rewrite the getVideos function, you could write it using ES6 syntax like the following:
var getVideos = () => urls.map(url => axios.get(url))
function (type) getMember {
var that = this;
var url = "/XXXXX";
return axios.post(url)
}
axios.all().then(axios.spread(function () {
console.log('init finished')
}));
now I have to function GetMember of different type,so I choose
axios.all(),I hope it work,yeah, it can work.
axios.all([getMember(0),getMember(1),getMember(2)]).then(axios.spread(
function () {
console.log('init finished');
console.log(arguments.length)//3
}));
but I think it`s not graceful for coding. I want to write a circulation ,and push arguments into "all(" ")",like this,I try 'eval(str)',it can work and run the function that I want to run,but arguments.length only be one, I can get all the data from all requests.
I found the following method. It is not the best, but it does work:
var requestFun = '[';
for (var i = 0; i < operType.length; i++) {
requestFun += 'this.getMemberInfo(operType[' + i + ']),';
}
requestFun += ']'
axios.all(eval(requestFun)).then(axios.spread(function () {
})
I am modifying an existing Angular JS application (code can be found here https://github.com/gmathiou/gtfs-manager).
In one file (trips-page-module.js) I have the following code:
$scope.saveTrip = function(itemToSave) {
$scope.computeNewStoptimeSequence();
LoadDataService.saveTrip(itemToSave)
.then(function(data) {
if (data["_id"] != null) {
$scope.tripsForRoutes.push(data);
$scope.active_trip_item = data;
}
})
.then( function (data) {
var dirtyElem = angular.element("ng-dirty");
var toUpdate = [];
for(var i = 0; i <= dirtyElem.length, i++){
toUpdate.push(dirtyElem[i].scope().stoptime);
}
LoadDataService.saveStopTimesForTrip(toUpdate);
})
.then(function(data) {
$scope.editing = false;
});
}
which, basically, creates an array of all the elements that are dirty and have to be updated before passing it to LoadDataService.saveStopTimesForTrip.
Still, when I run it I get that dirtyElem[i] is undefined. I clearly understand this is due to the asynchronous nature of the code.
What I don't get is how can I fix it? How can I wait for all my async function to finish?
i have an app the automatically insert data to mongodb after calling an api in jive, my problem is the response is paginated.
var getAPICall=function(apiLink){
console.log(apiLink);
var response = HTTP.get(apiLink, {
headers: {
Authorization: getAPIToken()
}
});
return response;
}
var getAPIToken = function(){
var token = HTTP.post("https://api.jivesoftware.com/analytics/v1/auth/login?clientId=fakeclientid.i&clientSecret=fakesecret.s");
//console.log(token);
return token.content;
}
the response looks like this.
{"paging":{"next":"https://cloudalytics-api-phx.prod.jivehosted.com:443/analytics/v2/export/activity/lastday?startIndex=100&count=100&show-all=true","itemsPerPage":100,"totalCount":164406,"currentPage":1,"totalPages":1645}, list: [{....}]}
which has next, currentPage and totalPage field
im planning to do a loop for the next page function and stop when totalPage is equal to currentPage
im doing this
var res = getAPICall(baseline);
_.each(res.data.list, function(item) {
console.log(item.uuid);
Reports.upsert({"uuid":item.uuid},{$set :item});
});
var totalPage = res.data.paging.totalPage;
for(var current = res.data.paging.currentPage ; current <= totalPage ;) {
var res = getAPICall(res.data.paging.next );
_.each(res.data.list, function(item) {
console.log(item.uuid);
Reports.upsert({"uuid":item.uuid},{$set :item});
});
}
but this statement only runs until the next page with infinite loop. any ways i can do this better with functional approach?
im new in javascript please hammer me.
thanks!
this should be pretty simple with recursion.
var myFunction = function(baseline){
var res = getAPICall(baseline);
_.each(res.data.list, function(item) {
console.log(item.uuid);
Reports.upsert({"uuid":item.uuid},{$set :item});
});
if (res.data.paging.currentPage != res.data.paging.totalPage) {
myFunction(res.data.paging.next)
}
}
myFunction(baseline);
What I have is simple CRUD operation. Items are listed on page, when user clicks button add, modal pops up, user enters data, and data is saved and should automatically (without refresh)be added to the list on page.
Service:
getAllIncluding: function(controllerAction, including) {
var query = breeze.EntityQuery.from(controllerAction).expand(including);
return manager.executeQuery(query).fail(getFailed);
},
addExerciseAndCategories: function(data, initialValues) {
var addedExercise = manager.createEntity("Exercise", initialValues);
_.forEach(data, function(item) {
manager.createEntity("ExerciseAndCategory", { ExerciseId: addedExercise._backingStore.ExerciseId, CategoryId: item.CategoryId });
});
saveChanges().fail(addFailed);
function addFailed() {
removeItem(items, item);
}
},
Controller:
$scope.getAllExercisesAndCategories = function() {
adminCrudService.getAllIncluding("ExercisesAndCategories", "Exercise,ExerciseCategory")
.then(querySucceeded)
.fail(queryFailed);
};
function querySucceeded(data) {
$scope.queryItems = adminCrudService.querySucceeded(data);
var exerciseIds = _($scope.queryItems).pluck('ExerciseId').uniq().valueOf();
$scope.exerciseAndCategories = [];
var createItem = function (id, exercise) {
return {
ExerciseId: id,
Exercise : exercise,
ExerciseCategories: []
};
};
// cycle through ids
_.forEach(exerciseIds, function (id) {
// get all the queryItems that match
var temp = _.where($scope.queryItems, {
'ExerciseId': id
});
// go to the next if nothing was found.
if (!temp.length) return;
// create a new (clean) item
var newItem = createItem(temp[0].ExerciseId, temp[0].Exercise);
// loop through the queryItems that matched
_.forEach(temp, function (i) {
// if the category has not been added , add it.
if (_.indexOf(newItem.ExerciseCategories, i.ExerciseCategory) < 0) {
newItem.ExerciseCategories.push(i.ExerciseCategory);
}
});
// Add the item to the collection
$scope.items.push(newItem);
});
$scope.$apply();
}
Here is how I add new data from controller:
adminCrudService.addExerciseAndCategories($scope.selectedCategories, { Name: $scope.NewName, Description: $scope.NewDesc });
So my question is, why list isn't updated in real time (when I hit save I must refresh page).
EDIT
Here is my querySuceeded
querySucceeded: function (data) {
items = [];
data.results.forEach(function(item) {
items.push(item);
});
return items;
}
EDIT 2
I believe I've narrowed my problem !
So PW Kad lost two hours with me trying to help me to fix this thing (ad I thank him very very very much for that), but unfortunately with no success. We mostly tried to fix my service, so when I returned to my PC, I've again tried to fix it. I believe my service is fine. (I've made some changes as Kad suggested in his answer).
I believe problem is in controller, I've logged $scope.items, and when I add new item they don't change, after that I've logged $scope.queryItems, and I've noticed that they change after adding new item (without refresh ofc.). So probably problem will be solved by somehow $watching $scope.queryItems after loading initial data, but at the moment I'm not quite sure how to do this.
Alright, I am going to post an answer that should guide you on how to tackle your issue. The issue does not appear to be with Breeze, nor with Angular, but the manner in which you have married the two up. I say this because it is important to understand what you are doing in order to understand the debug process.
Creating an entity adds it to the cache with an entityState of isAdded - that is a true statement, don't think otherwise.
Now for your code...
You don't have to chain your query execution with a promise, but in your case you are returning the data to your controller, and then passing it right back into some function in your service, which wasn't listed in your question. I added a function to replicate what yours probably looks like.
getAllIncluding: function(controllerAction, including) {
var query = breeze.EntityQuery.from(controllerAction).expand(including);
return manager.executeQuery(query).then(querySucceeded).fail(getFailed);
function querySucceeded(data) {
return data.results;
}
},
Now in your controller simply handle the results -
$scope.getAllExercisesAndCategories = function() {
adminCrudService.getAllIncluding("ExercisesAndCategories", "Exercise,ExerciseCategory")
.then(querySucceeded)
.fail(queryFailed);
};
function querySucceeded(data) {
// Set your object directly to the data.results, because that is what we are returning from the service
$scope.queryItems = data;
$scope.exerciseAndCategories = [];
Last, let's add the properties we create the entity and see if that gives Angular a chance to bind up properly -
_.forEach(data, function(item) {
var e = manager.createEntity("ExerciseAndCategory");
e.Exercise = addedExercise; e.Category: item.Category;
});
So I've managed to solve my problem ! Not sure if this is right solution but it works now.
I've moved everything to my service, which now looks like this:
function addCategoriesToExercise(tempdata) {
var dataToReturn = [];
var exerciseIds = _(tempdata).pluck('ExerciseId').uniq().valueOf();
var createItem = function (id, exercise) {
return {
ExerciseId: id,
Exercise: exercise,
ExerciseCategories: []
};
};
// cycle through ids
_.forEach(exerciseIds, function (id) {
// get all the queryItems that match
var temp = _.where(tempdata, {
'ExerciseId': id
});
// go to the next if nothing was found.
if (!temp.length) return;
// create a new (clean) item
var newItem = createItem(temp[0].ExerciseId, temp[0].Exercise);
// loop through the queryItems that matched
_.forEach(temp, function (i) {
// if the category has not been added , add it.
if (_.indexOf(newItem.ExerciseCategories, i.ExerciseCategory) < 0) {
newItem.ExerciseCategories.push(i.ExerciseCategory);
}
});
// Add the item to the collection
dataToReturn.push(newItem);
});
return dataToReturn;
}
addExerciseAndCategories: function (data, initialValues) {
newItems = [];
var addedExercise = manager.createEntity("Exercise", initialValues);
_.forEach(data, function (item) {
var entity = manager.createEntity("ExerciseAndCategory", { ExerciseId: addedExercise._backingStore.ExerciseId, CategoryId: item.CategoryId });
items.push(entity);
newItems.push(entity);
});
saveChanges().fail(addFailed);
var itemsToAdd = addCategoriesToExercise(newItems);
_.forEach(itemsToAdd, function (item) {
exerciseAndCategories.push(item);
});
function addFailed() {
removeItem(items, item);
}
}
getAllExercisesAndCategories: function () {
var query = breeze.EntityQuery.from("ExercisesAndCategories").expand("Exercise,ExerciseCategory");
return manager.executeQuery(query).then(getSuceeded).fail(getFailed);
},
function getSuceeded(data) {
items = [];
data.results.forEach(function (item) {
items.push(item);
});
exerciseAndCategories = addCategoriesToExercise(items);
return exerciseAndCategories;
}
And in controller I have only this:
$scope.getAllExercisesAndCategories = function () {
adminExerciseService.getAllExercisesAndCategories()
.then(querySucceeded)
.fail(queryFailed);
};
function querySucceeded(data) {
$scope.items = data;
$scope.$apply();
}