I'm trying to chain two http calls. The first one returns a set of records and then I need to get finance data for each of them.
flightRecordService.query().$promise.then(function (flightRecords) {
$scope.flightRecords = flightRecords;
for (var i = 0; i < $scope.flightRecords.length; i++) {
$scope.flightRecords[i].financeDocument =
financeDocumentService
.isReferencedDocumentIdCompensated({
id: $scope.flightRecords[i].id
}).$promise.then(
function (data) {
return ({
'isCompensated': data.headers['compensated']
});
}
);
console.log($scope.flightRecords);
}
});
This is the FlightRecord object:
$$hashKey: "object:27"
aircraft: {id: 100, registration: "LV-OEE", model: "152", status: "ACTIVE", brand: "Cessna", …}
amountOfHours: 1
canceled: false
closed: false
crew: [Object] (1)
destiny: null
endFlight: "2017-01-06T20:54:05.296"
financeDocument: d
--> $$state: {status: 1, value: {isCompensated: "false"}}
--> d prototipo
id: 100
landings: 0
nature: "LDI"
opened: true
origin: null
purpose: "VP"
startFlight: "2017-01-06T19:44:05.296"
status: "OPENED"
type: "ENT"
financeDocument object has not the structure I expect... I need a the following format:
...
endFlight: "2017-01-06T20:54:05.296"
financeDocument: { isCompensated: "false" }
id: 100
...
What I need to change to get that?
Thanks a lot!!
What you'll want to do is modify each "flight record" entry when you've retrieved the extra details. You'll also probably want to use $q.all to signal to the caller that the operation is complete.
const promise = flightRecordService.query().$promise.then(flightRecords => {
return $q.all(flightRecords.map(flightRecord => {
return financeDocumentService.isReferencedDocumentIdCompensated({
id: flightRecord.id
}).$promise.then(data => Object.assign(flightRecord, {
isCompensated: data.headers.compensated
}))
}))
})
promise.then(flightRecords => {
$scope.flightRecords = flightRecords
})
Why not just set it on the original object?
flightRecordService.query().$promise.then(function (flightRecords) {
$scope.flightRecords = flightRecords;
for (var i = 0; i < $scope.flightRecords.length; i++) {
(function(record) {
financeDocumentService
.isReferencedDocumentIdCompensated({
id: $scope.flightRecords[record].id
}).$promise.then(
function (data) {
$scope.flightRecords[record].financeDocument = {
'isCompensated': data.headers['compensated']
}
});
})(i)
console.log($scope.flightRecords);
}
});
You are trying to set the financeDocument property synchronously using a Promise. You need to set the variable in the success callback of the promise.
Related
I am having difficulty getting my for loop to add a new key-value pair to an object. It has no problem changing a current value of a key that already exists but for some reason, it will not add a new one
async function test(messagesWithSomeContent) {
for (i = 0; i < messagesWithSomeContent.length; i++) {
messagesWithSomeContent[i]["photo"] = 'please add this'; // this does not add a new key value pair
messagesWithSomeContent[i]["sender"] = 'change this'; // this works
console.log(messagesWithSomeContent[i]);
}
return win(await Promise.all(messagesWithSomeContent));
}
async function win(yay) {
console.log('yay');
}
messageWithSomeContent
[ { _id: 5e8f5a6a2582bf629998c3fe,
sender: '5e8f8d6be541b07ab8d8770b',
content: { content: 'Welcome to' },
__v: 0 },
{ _id: 5e8f594768fdda61d4f2ef6d,
sender: '5e8f86852c2a5174f3ca5e8c',
content: { content: 'hello test' },
__v: 0 },
{ _id: 5e8f585ee3eaa06136048b5c,
sender: '5e8f883627154676347fe286',
content: { lol: 'yeesh' },
__v: 0 } ]
I looked at some similar posts and their solutions are not working.
i can't add comment to you so i want to comment on this answer
what the output you want ?
async function test(messagesWithSomeContent) {
for (i = 0; i < messagesWithSomeContent.length; i++) {
messagesWithSomeContent[i]["photo"] = 'please add this';
messagesWithSomeContent[i]["sender"] = 'change this';
}
return win(await Promise.all(messagesWithSomeContent));
}
async function win(yay) {
const u = await yay; // tried add this to see the result
console.log(u)
}
tried console.log on here => https://repl.it/repls/RealisticExtralargeAstronomy
With the limited code added here, Try using the spread operator, although using JSFiddle I was able to get yours to work with my own made up sample data.
async function test(messagesWithSomeContent) {
for (i = 0; i < messagesWithSomeContent.length; i++) {
messagesWithSomeContent[i] = Object.assign({}, messagesWithSomeContent[i], {photo: 'please add this', sender: 'change this'})
console.log(messagesWithSomeContent[i]);
}
return win(await Promise.all(messagesWithSomeContent));
}
Promise.all must receive an array of promises. A way of doing this is using map over the array of parameters, calling the function on the callback.
Promise.all(parameters.map(parameter => myAsyncFunction(parameter)));
var messages = [
{_id: '5e8f5a6a2582bf629998c3fe', sender: '5e8f8d6be541b07ab8d8770b', content: { content: 'Welcome to' }, __v: 0},
{_id: '5e8f594768fdda61d4f2ef6d', sender: '5e8f86852c2a5174f3ca5e8c', content: { content: 'hello test' }, __v: 0},
{ _id: '5e8f585ee3eaa06136048b5c', sender: '5e8f883627154676347fe286', content: { lol: 'yeesh' }, __v: 0}];
async function test() {
for (var i = 0; i < messages.length; i++) {
messages[i]["photo"] = 'please add this';
messages[i]["sender"] = 'change this';
}
var result = await Promise.all(messages.map(el => win(el)));
console.log(result); // Should contain an array with all responses
}
async function win(param) {
console.log(param);
return param.photo;
}
test();
I am trying to add an object to an array but it is not working with me, the program can't read the property push
I defined an array in <script>:
Data: function() {
return {
Projects: [
{
name: '',
id: 0,
subscribers: 0,
products: {name:'',color:''},
}
],
}
And in the function:
GetAllWorkspaces: function(){
var app = this;
const instance = axios.create({
timeout: 1000,
headers: {
........
}
});
instance.get("XXXXXXX")
.then( function(response) {
console.log(response);
Object.keys(response.data.result).forEach( function (product) {
var subscribersCounter = 0;
let example = {
name: response.data.result[product].name,
id: response.data.result[product].id,
subscribers: response.data.result[product].subscribers,
products: response.data.result[product].products,
};
let uploadedExample = {
name: '',
id: '',
subscribers: '',
products: {name:'',color:''},
};
uploadedExample.name = example.name;
uploadedExample.id = example.id;
if ( example.subscribers ) {
Object.keys(example.subscribers).forEach(function (key) {
subscribersCounter++;
});
}
uploadedExample.subscribers = subscribersCounter;
if ( example.products ) {
Object.keys(example.products).forEach(function (Pkeys) {
uploadedExample.products.name = Pkeys;
Object.keys(example.products[Pkeys]).forEach(function (key) {
if (key == 'color') {
uploadedExample.products.color = example.products[Pkeys][key];
}
});
});
}
//add the new workspace to the list of workspaces.
app.Projects.push(uploadedExample);
});
})
.catch(function(error) {
console.log(error);
});
My problem is with this line
app.Projects.push(uploadedExample);
where when I try to push an object into the array, the error message is shown:
TypeError: Cannot read property 'push' of undefined
As the error says, the problem is that app.Projects is undefined. This happens because 'this' refers to the function scope inside GetAllWorkspaces and not to the component scope (you can try it by console.logging 'this' - anyway- it is a good practice under all circumstances because 'this' can change from context to context). If you want to keep the component scope inside the method, you should use an arrow function like this:
GetAllWorkspaces: () => {
// do all your stuff
}
I have been stuck with this issues for 2 hours now and I really can't seem to get it work.
const app = new Vue({
el: '#book-search',
data: {
searchInput: 'a',
books: {},
},
methods: {
foo: function () {
axios.get('https://www.googleapis.com/books/v1/volumes', {
params: {
q: this.searchInput
}
})
.then(function (response) {
var items = response.data.items
for (i = 0; i < items.length; i++) {
var item = items[i].volumeInfo;
Vue.set(this.books[i], 'title', item.title);
}
})
.catch(function (error) {
console.log(error);
});
}
}
});
When I initiate search and the API call I want the values to be passed to data so the final structure looks similar to the one below.
data: {
searchInput: '',
books: {
"0": {
title: "Book 1"
},
"1": {
title: "Book 2"
}
},
Currently I get Cannot read property '0' of undefined.
Problem lies here:
Vue.set(this.books[i], 'title', item.title);
You are inside the callback context and the value of this is not the Vue object as you might expect it to be. One way to solve this is to save the value of this beforehand and use it in the callback function.
Also instead of using Vue.set(), try updating the books object directly.
const app = new Vue({
el: '#book-search',
data: {
searchInput: 'a',
books: {},
},
methods: {
foo: function () {
var self = this;
//--^^^^^^^^^^^^ Save this
axios.get('https://www.googleapis.com/books/v1/volumes', {
params: {
q: self.searchInput
//-^^^^--- use self instead of this
}
})
.then(function (response) {
var items = response.data.items
var books = {};
for (i = 0; i < items.length; i++) {
var item = items[i].volumeInfo;
books[i] = { 'title' : item.title };
}
self.books = books;
})
.catch(function (error) {
console.log(error);
});
}
}
});
Or if you want to use Vue.set() then use this:
Vue.set(self.books, i, {
'title': item.title
});
Hope this helps.
yep, the problem is about context. "this" returns not what you expect it to return.
you can use
let self = this;
or you can use bind
function(){this.method}.bind(this);
the second method is better.
Also google something like "how to define context in js", "bind call apply js" - it will help you to understand what is going wrong.
// update component's data with some object's fields
// bad idea, use at your own risk
Object
.keys(patch)
.forEach(key => this.$data[key] = patch[key])
I'm having a small issue using RxJS and Angular (not Angular 2) that I'm sure indicates I'm just doing something wrong, but I'm not sure exactly what.
I have a function that creates an rx.Observable stream that I would like to test. A simplified version of the function is below:
ResourceCollection.prototype.rxFetch = function() {
var scheduler = this.injectedScheduler;
var result = functionThatReturnsAnObservable(theseParams).concatMap(function(items) {
var promises = _.map(readFromExternal(items), function(promise) {
// results of this promise should be ignored
return Rx.Observable.fromPromise(promise, scheduler);
});
promises = promises.concat(_.map(items, function(item) {
// callEvent returns EventResult, these values should be passed on
return Rx.Observable.fromPromise(callEvent(item), scheduler);
}));
return promises;
}).concatMap(function(x) { return x; }).filter(function(res) {
return (res instanceOf EventResult);
}).toArray();
return result;
});
My test function looks like this:
describe('query', function() {
var customers;
var scheduler;
beforeEach(function() {
scheduler = new Rx.TestScheduler();
customers = new ResourceCollection({
url: '/api/customers',
keyName: 'CustomerId',
globalActions: {
rxQuery: { method: 'GET', isArray: true }
}
});
$httpBackend.whenGET('/api/customers/rxQuery').
respond(function() {
return [200, [
{ CustomerId: 1, Name: 'Brian', Region: 'North' },
{ CustomerId: 2, Name: 'Ravi', Region: 'East' },
{ CustomerId: 3, Name: 'Ritch', Region: 'East' },
{ CustomerId: 4, Name: 'Jeff', Region: 'West' },
{ CustomerId: 5, Name: 'Brandon', Region: 'West' }
]];
});
});
it('rxFetch customers', function(done) {
var vals;
customers.injectedScheduler = scheduler
var result = customers.rxFetch();
result.subscribe(function(values) {
vals = values;
});
$httpBackend.flush();
// my question is here - what can I do to get rid of this loop?
while (vals == null) {
scheduler.advanceBy(100);
$rootScope.$apply();
}
scheduler.start();
expect(vals.length).toEqual(5);
expect(vals[0]).toBe(customers[0]);
done();
});
});
The issue is a simple one - while the while loop in the test is in there, the test will produce the correct results (which is an array that contains the results of all the callEvent functions). Replace the while loop with a scheduler.scheduleAbsolute (or some other such call) combined with a $rootScope.$apply, and only one of the promises from the callEvent function will complete. Call it twice, and two of them will complete, etc (hence the while loop).
But the while loop is pretty ugly - and I'm sure there has to be an cleaner way to get this test to pass. Many thanks to anyone who can point me in the correct direction.
Im trying to write a function that 1. adds an item to an observable array and 2. replaces the item if it already exists in the array
self.addNotification = function (name, availability, note) {
//see if we already have a line for this product
var matchingItem = self.notifications.indexOf(name);
if (matchingItem !== undefined) {
self.notifications.replace(self.notifications()[index(matchingItem)],
new Notification(self, name, availability, note));
}
else {
self.notifications.push(new Notification(self, name, availability, note));
}
};
What am I doing wrong?
Regards Anders
Here is my answer: fiddle
Hit F12 in Chrome or use FireBug in FireFox to see console log output.
var notifications = {
notifs: [],
updateNotifications: function(notification) {
'use strict';
var matchIndex;
for (matchIndex = 0; matchIndex < this.notifs.length; matchIndex += 1) {
if (this.notifs[matchIndex].name === notification.name) {
break;
}
}
if (matchIndex < this.notifs.length) {
this.notifs.splice(matchIndex, 1, notification);
} else {
this.notifs.push(notification);
}
}
};
notifications.updateNotifications({
name: 'John',
available: false,
note: "Huzzah!"
});
notifications.updateNotifications({
name: 'Jane',
available: true,
note: "Shazam!"
});
notifications.updateNotifications({
name: 'Jack',
available: true,
note: "Bonzai!"
});
notifications.updateNotifications({
name: 'Jane',
available: false,
note: "Redone!"
});
console.log(notifications);
Well, Array.prototype.indexOf never returns undefined. Its either -1 (not found) or any number starting with 0 for the array index.