I have a weird problem.
First I retrieve several calls at the same time. And save the returned data in a variable called "values"
function PrefsService($resource,PrefsResource,$q) {
var initialize = function() {
return $q
.all(
[PrefsResource.get({key:"TwentyFourHourTime"}),
PrefsResource.get({key:"DecimalTime"}),
PrefsResource.get({key:"startDayOfWeek"}),
PrefsResource.get({key:"RoundingIncrement"}),
PrefsResource.get({key:"RoundingOption"})
]
)
.then(function(values) {
return values
})
I use this piece of code in controller to see the returned value:
PrefsService
.initialize()
.then(function(values) {
console.log("values",values);
console.log("values[0]",values[0]);
console.log("values[0].result",values[0].result);
})
I want to use "values[0].result" get the result object. But it always gives me a value of "undefined".
Why?
Thx
This syntax looks weird:
return {
values
}
Its basically an object literal with a property name, but no value. In any case what you are tagging on to the initial all is unnecessary:
.then(function(values) {
return {
values
}
})
Just remove that part.
The returned values are promises, use them as promises like you are supposed to:
PrefsService
.initialize()
.then(function(values) {
values.map(function(valuePromise) {
valuePromise.then(function(value) {
console.log(value);
});
});
});
The most straightforward way would be to return the actual values, not the promises:
function PrefsService($resource,PrefsResource,$q) {
var initialize = function() {
return $q
.all([
PrefsResource.get({key:"TwentyFourHourTime"}),
PrefsResource.get({key:"DecimalTime"}),
PrefsResource.get({key:"startDayOfWeek"}),
PrefsResource.get({key:"RoundingIncrement"}),
PrefsResource.get({key:"RoundingOption"})
])
.then(function(values) {
var returnValues = [];
values.forEach(function(v) {
v.then(function(a) {
returnValues.push(a);
})
});
return returnValues;
})
};
return {
initialize:initalize;
}
}
PrefsService
.initialize()
.then(function(values) {
console.log(values); //an array of the actual values, not the promises
})
Related
I have a computed property:
relateditems () {
return this.related.find((relation) => {
return relation.id === this.currentItem.id
})
},
with the following output:
relateditems:Object
-KQ1hiTWoqAU77hiKcBZ:true
-KQ1tTqLrtUvGnBTsL-M:true
id:"-KQ1if2Zv3R9FdkJz_1_"
I'm trying to create another computed property that then loops through the relateditems object and finds a relation with the matching ID for the first two keys.
The following doesn't work but I think it gives the idea:
relateditemsdata () {
let test = []
for (var key in this.relateditems) {
this.items.find((relateditem) => {
relateditem.id === key.id
test.push(relateditem)
})
}
return test
}
I think calling a computed property in another one is not a good way, so you could add a watcher property in order to watch the first computed property and update a data object property based on that one like :
data() {
return {
relateditemsdata: [],
}
},
computed: {
relateditems() {
return this.related.find(relation => {
return relation.id === this.currentItem.id
})
},
},
watch: {
relateditems(val) {
for (var key in this.relateditems) {
this.items.find(relateditem => {
relateditem.id === key.id
relateditemsdata.push(relateditem)
})
}
},
},
Seems like your problem is not related to Vue.
Your key.id is undefined in the for..in loop. You would have to use this.relateditems[key] to access the value or just key to access the key. Since you do not want filter your other array for the 'id' key, you should also filter your object-keys first.
E.g.
relatedItems() {
return this.related.find((item) => {
return this.item.id == this.currentItem.id;
});
} // returns first objects with the same id
relatedItemsData() {
// grabs all keys except 'id'
const keys = Object.keys(this.relateditems).filter((key) => key != 'id');
this.items.filter((item) => {
return keys.indexOf(item.id) != -1; // checks if item.id is inside the keys-array
});
} // returns again array of objects;
Instead of a nested loop, you can also just use the Array.prototype.filter() function, like above.
I am trying to get the value of the client using the client's name and for some reason I get back the full client object:
function createBank(clients) {
return {
clients: clients,
safeBoxValue: function() {
return this.clients.reduce(function(sum, client) {
return sum + client.value;
}, 0);
},
getclientValue: function(clientName) {
return this.clients.find(function(client) {
if (client.name === clientName) {
return client.value;
}
});
}
}
}
var clients = [
{name: "John", value: 349},
{name: "Jane", value: 9241},
{name: "Jill", value: 12734},
]
var bank = createBank(clients);
bank.safeBoxValue(); // 22324
bank.getclientValue('Jill'); // {"name":"Jill","value":12734}
Anybody knows why? Thanks!
array.find() works by passing in a function that returns a Boolean value to determine whether the object is the one you're looking for. Your function is working despite the code because you are returning a value that is 'truthy' when you return client.value.
The function would work exactly the same if you had just done this:
getclientValue: function(clientName) {
return this.clients.find(function(client) {
return client.name === clientName
});
}
It will go through the array until you return true and then pass you the element, in this case the whole object, you just found. To only get the value, you will need to return it separately:
getclientValue: function(clientName) {
var found = this.clients.find(function(client) {
return client.name === clientName
});
return found && found.value
}
Just remember find() only returns the first value found.
I used to have the following code:
function makeCall(userInfo) {
api.postUser(userInfo).then(response => {
utils.redirect(response.url);
})
// other logic
return somethingElse;
}
And I was able to write a test that looked like this:
const successPromise = Promise.resolve({ url: 'successUrl' })
beforeEach(function() {
sinon.stub(api.postUser).returns(successPromise);
}
afterEach(function() {
api.postUser.restore();
}
it "calls API properly and redirects" do
makeCall({});
expect(api.postUser).calledWith(userInfo).toBe(true);
successPromise.then(() => {
expect(utils.redirect.calledWith('successUrl')).toBe(true);
done();
}
emd
And everything was green.
Now, I had to add another promise to make another external call, before doing the api postUser call, so my code looks like this:
function makeCall(names) {
fetchUserData(names).then(userData => {
return api.postUser(userData).then(response => {
utils.redirect(response.url);
})
})
// other logic
return somethingElse;
}
where fetchUseData is a chain of many promises, such like:
function fetchNames(names) {
// some name regions
return Promise.all(names);
}
function fetchUserData(names) {
fetchUsersByNames(names).then(users => {
// For now we just choose first user
{
id: users[0].id,
name: users[0].name,
}
});
}
And the tests I had fail. I am trying to understand how to change my tests to make sure that I am still testing that I do the final API call properly and the redirect is also done. I want to stub what fetchUserData(names), to prevent doing that HTTP call.
You're not using promises correctly. Your code doesn't have a single return statement, when it should have several (or it should be using arrow functions in such a way that you don't need them, which you're not doing).
Fix your code:
function makeCall(names) {
// v---- return
return fetchUserData(names).then(userData => {
// v---- return
return api.postUser(userData).then(response => {
utils.redirect(response.url);
})
})
}
function fetchUserData(names) {
// v---- return
return fetchUsersByNames(names).then(users => {
// For now we just choose first user
// v---- return
return {
id: users[0].id,
name: users[0].name,
}
});
}
Once you've done that, you can have your test wait for all of the operations to finish.
Test code:
makeCall(['name']).then(() =>
expect(api.postUser).calledWith(userInfo).toBe(true);
expect(utils.redirect.calledWith('successUrl')).toBe(true);
done();
});
You should add a return statement, otherwise you are not returning promises nowhere:
function fetchNames(names) {
// some name regions
return Promise.all(names);
}
function fetchUserData(names) {
return fetchUsersByNames(names).then(users => {
// For now we just choose first user
{
id: users[0].id,
name: users[0].name,
}
});
}
So when you are using Promise.all(), then you will have as result of the promise an array with all the value returned by all the promises.
So then this method should look like this when called:
fetchNames(names).then((arrayOfResolvedPromises) => {
// here you will have all your promised resolved and the array holds all the results
});
So inside your test you can move your done inside the block where all the promises will be resolved.
In addition, I strongly suggest you to use a library as chai-as-promised for testing promises.
It has a lot of nice methods for testing your promises.
https://github.com/domenic/chai-as-promised
I am using bluebird & lodash and am trying to figure out how I can return a promise after iterating over an object? For example, I want to add a key/value pair to each object THEN after adding a key/value pair to each object, I want to print the result:
var cars = {
audi:[
{
model:'r8',
year:'2012'
},
{
model:'rs5',
year:'2013'
}
],
ford:[
{
model:'mustang',
year:'2012'
},
{
model:'fusion',
year:'2015'
}
],
kia:[
{
model:'optima',
year:'2012'
}
]
}
_.forOwn(cars, function(value, key) {
key.processed = true;
}).then(function(cars) {
//print modified cars object here
console.log(cars);
});
Can someone help?
Thanks in advance!
In general terms, you could do something like this (note: no lodash, because I don't use lodash, but the concept shown should be adaptable to lodash)
function someAsyncFunction(car) {
return new Promise(function(resolve) {
setTimeout(function() {
car.processed = true;
resolve(car);
}, 1000 * Math.random() + 1000);
});
}
Promise.all(Object.keys(cars).map(function(key) {
return someAsyncFunction(cars[key]);
})).then(function(results) { // results will be an array of the values resolved in the promises
console.log(cars);
});
This is how I'm doing it:
const Document = Parse.Object.extend('Document')
const query = new Parse.Query(Document)
let result = {}
query.get(id, {
success: function (object) {
result = object.toJSON()
console.log(result)
},
error: function (object, error) {
alert(`Error: ${error.code} ${error.message}`)
}
})
console.log(result)
return result
The first console.log(result) outputs the object:
Object {content: "trstrtrts", createdAt: "2016-01-17T11:20:30.694Z",
title: "Document 2", updatedAt: "2016-01-17T11:20:30.694Z", wordCount:
"3000"…}
But the second one returns nothing. What's the correct way of returning an object from a Parse query?
EDIT:
Based on Anon's answer I tried this:
store.js:
store.first = (id) => {
var query = new Parse.Query(Document)
return query.get(id)
}
export default store
main.js:
store.first(to.params.id).then((document) => {
console.log(document.toJSON())
return document.toJSON()
})
But I get the following error:
Uncaught TypeError: Object function ParsePromise() {
_classCallCheck(this, ParsePromise); this._resolved = false; this._rejected = false; this._resolvedCallbacks = [];
this._rejectedCallbacks = []; } has no method 'all'
The second
console.log(result)
take place before the first one.Query is an async operation.
The correct way of doing this is to use promises. For example you can do
function foo(id){
var Document = Parse.Object.extend('Document');
var query = new Parse.Query(Document);
return query.get(id);
}
and then use the function foo like this:
foo(objectID).then(function(object){
//do something with the object.
})
here is an example to show the async in js.
console.log('a');
setTimeOut(function(){console.log('b')},0);
console.log('c');
the order of the printing is
a
c
b
(we have time out 0 but the function of the timeout goes in the event loop and take place after the function done)
for more information you can read https://developer.mozilla.org/he/docs/Web/JavaScript/EventLoop
about the eventloop