I have a very curious problem that I'm sure someone in the world has figure out. Let's keep thing simple however. Ok, here we go.
So I have a plain array of objects. Let's say 5 objects for now.
[{id: 1, data: 'stuff'}, {id: 2, data: 'stuff'}, {id: 3, data: 'stuff'}, {id: 4, data: 'stuff'}, {id: 5, data: 'stuff'}]
What I then do is make 3 ajax requests which all, obviously, come back and different times. What I want to do is update this array based on the id's. For example I send off 3 ajax requests and receive new data for objects 1, 2 and 4. I'll need to update the data property in the respectives objects in the array. I'm using Array.splice to do the update. What I'm finding is that there are times, since the data comes in at different times, that things aren't updated correctly. I think this is because what splice does is actually remove the object from the array then re-inserts the new array in afterwards. It seems like there are instances when the splice method is in the middle of removing an object, then another response comes in and tries to remove another object, however, that object is not in the correct index, since the first object was removed and hasn't been inserted in yet. So the updating is off.
There's no reason you need to change the array at all, you are just trying to update objects within the array. Also, the index shouldn't matter because you are using the id property to uniquely identify each object, not the index in the array.
You should use whichever way is easiest for you to loop through the array, find the object with the corresponding id and update it.
This can be easily handled by looping over each object and keeping a reference to the object so that you can update each object as each request completes.
var promiseArr = dataArr.map(function (obj) {
return $http.get('/data/' + obj.id).then(function (result) {
obj.data = result.data;
});
});
// optional...
$q.all(promiseArr).then(function () {
console.log('all done!');
});
Related
so there the array coursesFollowing
and inside it objects like this for example:
objInside = {
username:"SweetWhite"
courseTitle:"TOMATOaaaaa"
progress:0
}
and I have a function that finds the right object index in the array of objects of that kind of object
and it seems to work in terms of index found and object, however my update request works weirdly when I execute it:
User.updateOne({username: req.body.username}, {coursesFollowing:{$slice: [removeIndex , 1]}}, function(err,result){
if(err){return next(err)}
})
it find the right user to put it in, and also the right field, however it does not remove the object in that removeIndex index, but deletes all the items in the array and puts only one object in, with the array named $slice with the removeIndex as first value and the second value is 1, judging from the data it has not deleted all the other objects but simply replaced them with itself, the operation $slice pushed itself into the array and did not execute I think? I am mildly confused.
anyways, how do I fix this? how do I delete an index of the array without pushing the weird $slice object array thingi?
Thanks!
If you notice your updated document you might realize that you are not updating anything in the array actually using your $slice operator. Instead you are setting a new value for the array. And that is why you see the first element as $slice something and the second as 1.
$slice operator is used with $push and is used to limit the number of elements in the array field finally. The doc doesn't mention removing an array element with this, given its index.
According to this answer there is no simple way to do this.
There is $pull, but it does not work with the given index. It works based on a query condition for the object in the array. So if you are first figuring out the element index and then using it in the update query. You can do that directly.
If you want to use a JS function you can use splice, which does in-place updates. Use the $function
User.updateOne({username: req.body.username}, [{ $set:
{ "coursesFollowing": { $function: { body: function(coursesFollowing) { coursesFollowing.splice(removeIndex, 1); return coursesFollowing; }, args: ["$coursesFollowing"], lang: "js" }} }
}], function(err,result){
if(err){return next(err)}
})
I'm trying to render a table using data from an array of objects. These have been created with a constructor which has a number of prototype methods. All the methods work correctly outside of the specific problem I'm having.
The table needs to be rendered dynamically, eventually with user input selecting which columns they want rendered and in which order. As such I'm trying to use a separate array to house the selected fields (filled in manually for now).
Below I have an example of the object, the prototype, the array, and the array of objects forEach method containing a simple console.log.
const jsonResultTotal = {
new_stats: [
{
revenue: 'US$200.00',
cost: 'US$4.09',
}]
};
jsonResultTotal.prototype = {
...jsonResultTotal.prototype,
roas: function() {
return (Number(this.revenue.replace(/[^0-9.]/g, '')) / Number(this.cost.replace(/[^0-9.]/g,''))).toFixed(
2);
},
const rowCellContent = [
'revenue',
'cost',
roas(),
'roas()'
roas
'roas'
];
jsonResultTotal.new_stats.forEach(function(e) {
for (i=0; i<=5;i++){
console.log(e[rowCellContent[i]])
}
}
The result of the above code is
'US$200.00'
'US$4.09'
undefined
Well, actually that specific rowCellContent array will result in roas() is not defined, but the point is that none of the methods will work.
If I console.log(e.roas()) then it works, so accessing the method seems to be fine. I've tried arrow functions in the rowCellContent array, as well as full functions with a return of this.roas(), I've tried to used bind on the e[rowCellContent[i]]
There doesn't seem to be any issues calling the properties through the array, or calling the prototype methods directly, I just can't get the methods via the array to work.
Any help would be appreciated.
I have a request_json which will get updated different levels.
Example:
request_json = {"filter":""};
// I was updating it like(some where in script)..
request_json.filter = {div_id_1:[1,2,3]};
// Second time updating(some another place in script) is not working
request_json.filter = {div_id_2: ['abc','def']}; //not working.
Expected output:
request_json = {"filter":{div_id_1:[1,2,3], div_id_2: ['abc','def']}}
Actual output:
request_json = {"filter":{div_id_2: ['abc','def']}}
Tried:(not working)
request_json.filter.div_id_1 = {div_id_2: ['abc','def'];'def']}; //not working.
How to update this?
JSON
First, a minor note. You will get a lot of pushback around here using "JSON" to refer to arbitrary JS objects, even if people know what you mean. JSON is a string format used to represent data objects passed between systems. It is not the object format itself. Thus I will use "request" rather than "request_json" below.
Why your code doesn't work
request = {filter: ''};
// ... later
request.filter = {div_id_1: [1, 2, 3]};
// ... later still
request.filter = {div_id_2: ['abc', 'def']};
In each step of that, you set the filter value of your object. On the first line, you set it to the empty string. On the second line you set it to the object {div_id_1: [1, 2, 3]}, and on the third line you set it to the object {div_id_2: ['abc', 'def']}. You have never told it to combine those objects into one. If that's what you want it to do, you need to tell it so.
The simplest fix
You can just change the third line to update the filter object with a new property:
request = {filter: ''};
// ... later
request.filter = {div_id_1: [1, 2, 3]};
// ... later still
request.filter.div_id_2 = ['abc', 'def'];
If you know that the lines will always run in this order, and that this is all you need to do with the filter, this will work fine.
Updating multiple times
But if your problem is more general, if, for instance, you want to be able to update the filter a number of times, but you're not sure which one might do so first, then it could help to write a function to handle the testing of whether the filter is already there and is an object.
It might look like this:
const addToFilter = (request, key, val) =>
request .filter = Object .assign (request .filter || {}, {[key]: val})
const request = {filter: ''}
// ... later
addToFilter (request, 'div_id_1', [1, 2, 3])
// ... later still
addToFilter (request, 'div_id_2', ['abc', 'def'])
console .log (request)
Updating multiple properties at once
If in a single call, you might want to add multiple properties to your filter, the code can be even simpler:
const addToFilter = (request, obj) =>
request .filter = Object .assign (request .filter || {}, obj)
const request = {filter: ''}
// ... later
addToFilter (request, {div_id_1: [1, 2, 3]})
// ... later still
addToFilter (request, {div_id_2: ['abc', 'def'], meaningOfLife: 42})
console .log (request)
Initial assignment
In each of these, I started with an empty string for the filter property. If you need that for an external system -- if perhaps the system uses an empty string to say there is no filter but an object holding values otherwise -- then this is tolerable. But it's far from ideal. I would suggest that if you can, you should start without the filter property or with an empty object for filter.
Mutation
This is still not code I would be proud of. It does the job for now. But I prefer to work with immutable data and here we continually mutate the request object and its filter property. There are probably techniques that would let you do something functionally equivalent without mutating your data, but that's probably taking us too far afield, and would take much more knowledge of your code than I currently have. But you might want to keep in mind techniques using immutable data.
So I have an interesting issue I am not sure how to follow, I need to use lodash to search two arrays in an object, looking to see if x already exists, lets look at a console out put:
There are two keys I am interested in: questChains and singleQuests, I want to write two seperate functions using lodash to say: find me id x in the array of objects where questChains questChainID is equal to x.
The second function would say: Find me a quest in the array of objects where singleQuests questTitle equals y
So if we give an example, you can see that questChainId is a 1 so if I pass in a 1 to said function I would get true back, I don't actually care about the object its self, else I would get false.
The same goes for singleQuests, If I pass in hello (case insensitive) I would get back true because there is a quest with the questTitle of 'Hello'. Again I don't care about the object coming back.
The way I would write this is something like:
_.find(theArray, function(questObject){
_.find(questObject.questChains, function(questChain){
if (questChain.questChainId === 1) {
return true;
}
});
});
This is just for the quest chain id comparison. This seems super messy, why? Because I am nesting lodash find, I am also nesting if. It gets a bit difficult to read.
Is this the only way to do this? or is there a better way?
Yeah it can be expressed more simply.
Try something like this:
var exampleArray = [{
questChains: [{
questChainId: 1,
name: 'foo'
}, {
questChainId: 2,
name: 'bar'
}],
singleQuests: [{
questTitle: 'hello world'
}]
}, {
questChains: [{
questChainId: 77,
name: 'kappa'
}]
}];
var result = _.chain(exampleArray)
.pluck('questChains')
.flatten()
.findWhere({ questChainId: 2 })
.value();
console.log('result', result);
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.5.0/lodash.min.js"></script>
Using chain and value is optional. They just let you chain together multiple lodash methods more succinctly.
pluck grabs a property from each object in an array and returns a new array of those properties.
flatten takes a nested array structure and flattens it into flat array structure.
findWhere will return the first element which matches the property name/value provided.
Combining all of these results in us fetching all questChain arrays from exampleArray, flattening them into a single array which can be more easily iterated upon, and then performing a search for the desired value.
Case-insensitive matching will be slightly more challenging. You'd either need to either replace findWhere with a method which accepts a matching function (i.e. find) or sanitize your input ahead of time. Either way you're going to need to call toLower, toUpper, or some variant on your names to standardize your search.
I need a user to be able to perform these actions:
Click an "Add" button. This will add a JavaScript object to either an array, or another JavaScript object.
Click a dynamic "Remove" button. This will remove the JavaScript object from the array, or object, whose ID matches the button click.
Submit the complete array, or object, of desired objects server-side for processing.
Using an array, am I able to get a handle via ID on a specific element and remove it with a "pop"-like function? If not, am I able to do so using a JavaScript object?
This question is related to this post, but there isn't much context in the original to answer my question. Thanks!
You can append an element to an array using the push method, like this:
var someArray = []; //Start with an empty array
//Later,
someArray.push({ name: 'value' });
It may actually be better to use an object rather than an array. This will allow you to name each object you send back to the server.
var dataObject = {};
function addData(name, data1, data2, data3) {
dataObject[name] = {
data1: data1,
data2: data2,
data3: data3
};
}
function removeData(name) {
delete dataObject[name];
}