This one's been giving me problems for a week, cross my fingers one of you can help me here...
This application was built on Laravel and the front scaffolded using Vue.
Thing is I have an array of objects that is supposed to be sent to the backend in order for it to be stored in a database. Thing is this is an editor and the idea is not reload the page every time something is changed, so here comes my problem...
The way of getting the information is through window.postMessage(), so it seems the information lingers on even after saving, since the page behavior is for it to not reload, I have tried emptying the array after firing the save function. Now it works the first time because the array is empty so there's nothing to compare it to, it also works the second time, but from the third time on, it duplicates some of the objects inside and stores them in DB.
Here's my code:
saveNewSettings() {
//THIS IS THE ARRAY I NEED TO EMPTY (ALREADY DECLARED IN THE DATA OBJECT)
/* this.newItems = [
{ id="123", name="a", otherProps="someProps" },
{ id="456", name="ab, otherProps="someProps" },
{ id="789", name="c", otherProps="someProps" },
]
*/
//THIS IS THE AN EMPTY ARRAY I'M USING TO COMPARE LATER ON... (ALREADY DECLARED IN THE DATA OBJECT)
// this.newlyCreatedItems = [];
if ( !this.newlyCreatedItems.length ) {
this.newlyCreatedItems = this.newItems;
} else {
for ( let i = 0; i < this.newItems.length; i++ ) {
for ( let j = 0; j < this.newlyCreatedItems.length; j++ ) {
if ( this.newItems[i].id == this.newlyCreatedItems[j].id ) {
this.newItems.splice( i, 1 );
}
}
}
}
//THIS IS THE SERVICE I USE TO SEND THE INFO TO THE BACK END
//THIS ONE HAS BEEN IMPORTED FROM AN SERVICE FILE
settingsService.save( this.newItems )
.then(response => {
//WHAT TO DO AFTER THE RESPONSE GOES HERE
});
}
So here's the thing, firing the function for the first time, since it's the first, doesn't duplicate anything in the database... For the second time, it works well and it only saves the new item, from the third time on, it starts duplicating.
If you need me to elaborate more, just let me know, I thank you all in advance...
Quick and dirty using jQuery:
var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
var uniqueNames = [];
$.each(names, function(i, el){
if($.inArray(el, uniqueNames) === -1) uniqueNames.push(el);
});
You tagged vue.js but this problem statement is more like from JavaScript side. Basically, You are doing shallow copy of the newItems array into the newlyCreatedItems array which causing the updation issue as both are referencing to the same pointer address.
You can resolve this issue by deep copying with the help of structuredClone() method.
Live Demo :
let newItems = [
{ id: "123", name: "a", otherProps: "someProps" },
{ id: "456", name: "ab", otherProps: "someProps" },
{ id: "789", name: "c", otherProps: "someProps" }
];
let newlyCreatedItems = [];
function saveNewSettings() {
if (!newlyCreatedItems.length ) {
newlyCreatedItems = structuredClone(newItems);
} else {
for ( let i = 0; i < newItems.length; i++ ) {
for ( let j = 0; j < newlyCreatedItems.length; j++ ) {
if ( newItems[i].id == newlyCreatedItems[j].id ) {
newItems.splice( i, 1 );
}
}
}
}
}
saveNewSettings();
console.log(newlyCreatedItems);
console.log(newItems);
console.log('-------');
saveNewSettings();
console.log(newlyCreatedItems);
console.log(newItems);
I'm working on a NodeJS/VueJS app and I encounter some strange behavior and I am not sure if it is something I am doing wrong or something else.
I have 2 arrays, one array of objects that contains campaigns and one array of objects that contains all promotions associated to all campaigns.
Each Campaign object contains, at this point, an empty array called promos, where I want to push all the promotions for each campaign.
for (var i = 0; i < campaigns.length; i++) {
for (var j = 0; j < campaignsPromo.length; j++) {
if (campaignsPromo.length > 0) {
if (campaigns[i].IDCampaign == campaignsPromo[j].IDCampaign) {
if ((campaignsPromo[j].associated == 1) && (campaignsPromo[j].validated == 1)) {
campaigns[i].promos.push(campaignsPromo[j]);
console.log("Validated Campaign ID " + campaigns[i].IDCampaign);
console.log("Promo ID " + campaignsPromo[j].IDPromo);
} else if ((campaignsPromo[j].associated == 1) && (campaignsPromo[j].validated == 0)) {
campaigns[i].unvalidatedPromos++;
console.log("Unvalidated Campaign ID " + campaigns[i].IDCampaign);
console.log("Promo ID " + campaignsPromo[j].IDPromo);
}
}
} else {
console.log("No promos!");
}
}
}
At first, the code seems to be doing what is supposed to do and it checks out with my test data set.
However, in the end, all campaigns end up having the same promotions.
Campaigns With No Promos: [{"IDCampaign":7,"campaignName":"dadsadafds","startDate":"2022-02-03","endDate":"2022-02-28","unvalidatedPromos":0,"promos":[]},{"IDCampaign":3,"campaignName":"Tarzan 3","startDate":"2022-02-02","endDate":"2022-02-06","unvalidatedPromos":0,"promos":[]},{"IDCampaign":1,"campaignName":"Tarzan","startDate":"2022-02-01","endDate":"2022-03-01","unvalidatedPromos":0,"promos":[]},{"IDCampaign":2,"campaignName":"Tarzan 2","startDate":"2022-02-01","endDate":"2022-02-08","unvalidatedPromos":0,"promos":[]},{"IDCampaign":4,"campaignName":"Tarzan 4","startDate":"2022-02-01","endDate":"2022-02-05","unvalidatedPromos":0,"promos":[]},{"IDCampaign":5,"campaignName":"Jabe 1","startDate":"2022-02-01","endDate":"2022-02-05","unvalidatedPromos":0,"promos":[]},{"IDCampaign":6,"campaignName":"dadsada","startDate":"2022-02-01","endDate":"2022-02-08","unvalidatedPromos":0,"promos":[]},{"IDCampaign":8,"campaignName":"Black Friday","startDate":"2022-02-01","endDate":"2022-02-28","unvalidatedPromos":0,"promos":[]}]
Validated Campaign ID 1
Promo ID 1119
Unvalidated Campaign ID 1
Promo ID 107
Campaigns With Promos: [{"IDCampaign":7,"campaignName":"dadsadafds","startDate":"2022-02-03","endDate":"2022-02-28","unvalidatedPromos":0,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]},{"IDCampaign":3,"campaignName":"Tarzan 3","startDate":"2022-02-02","endDate":"2022-02-06","unvalidatedPromos":0,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]},{"IDCampaign":1,"campaignName":"Tarzan","startDate":"2022-02-01","endDate":"2022-03-01","unvalidatedPromos":1,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]},{"IDCampaign":2,"campaignName":"Tarzan 2","startDate":"2022-02-01","endDate":"2022-02-08","unvalidatedPromos":0,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]},{"IDCampaign":4,"campaignName":"Tarzan 4","startDate":"2022-02-01","endDate":"2022-02-05","unvalidatedPromos":0,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]},{"IDCampaign":5,"campaignName":"Jabe 1","startDate":"2022-02-01","endDate":"2022-02-05","unvalidatedPromos":0,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]},{"IDCampaign":6,"campaignName":"dadsada","startDate":"2022-02-01","endDate":"2022-02-08","unvalidatedPromos":0,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]},{"IDCampaign":8,"campaignName":"Black Friday","startDate":"2022-02-01","endDate":"2022-02-28","unvalidatedPromos":0,"promos":[{"IDCampaign":1,"IDPromo":1119,"promoType":"CHRISTMASS","associated":1,"validated":1,"promoName":"Test Promo 1","beginDate":"2020-11-26","endingDate":"2020-11-29"}]}]
This is the content of campaignsPromo:
[ { IDCampaign: 1,
IDPromo: 1119,
promoType: 'CHRISTMASS',
associated: 1,
validated: 1,
promoName: 'Test Promo 1',
beginDate: '2020-11-26',
endingDate: '2020-11-29' },
{ IDCampaign: 1,
IDPromo: 107,
promoType: 'CHRISTMASS',
associated: 1,
validated: 0,
promoName: 'Test Promo 2',
beginDate: '2019-12-21',
endingDate: '2019-12-23' } ]
Any ideas? From where I'm standing, I am not doing anything wrong but it wouldn't be the first time I'm missing the obvious.
PS: Please ignore the fact my campaigns are called "Tarzan".
You didn't share the offending code, so I'll give a generic answer.
When the symptom is that a bunch of all objects seem to have a property that is the same array of items, it is likely caused by exactly that. Each object may be sharing the same array instance.
A typical mistake is something like the following:
var items = [];
var containers = [];
for (let i = 0; i < 3; ++i) {
items.push(i);
let container = {};
container.items = items;
containers.push(container);
}
console.log(containers);
Although one might expect, or even have intended to get 3 objects like this:
[
{ items: [ 0 ] },
{ items: [ 0, 1 ] },
{ items: [ 0, 1, 2 ] }
]
The items array is actually the same instance of an array. And what you actually get is more like:
[
{ items: [ 0, 1, 2 ] },
{ items: [ 0, 1, 2 ] },
{ items: [ 0, 1, 2 ] }
]
In fact, the stack snippet visualizer actually does a better job visualizing this because it outputs:
[
{
"items": [
/**id:3**/
0,
1,
2
]
},
{
"items": /**ref:3**/
},
{
"items": /**ref:3**/
}
]
In this way, it tries to inform you that it is actually the same array by giving it a ref:3 label and just marking the values of the other properties with the same ref:3 label as a comment.
Causes I see typically stem from a misunderstanding of what it means to assign an array to a property. Doing so does not create a copy of the array. Both objects refer to the same array.
This can be strange because: it can appear to be correct in a debugger by inspecting the contents of your array as your are stepping through a loop. Even if we had added log messages like console.log(items) or even console.log(container) inside the loop, we'd probably still not have enough of a clue that something went wrong because the contents of that one array instance change with each iteration of the loop and we can dump versions of it as text that appear to be correct, but then unwittingly change the contents of the array on the next iteration.
But if we log the entire containers array after the loop, you'll find that each object has the same instance of the array. Assining an array isn't bad if it's only one object that gets the array assigned to it, but if you assign the same array to properties of multiple objects, or in a loop, you may run into this problem.
One possible habit-breaker you can try is to inspect all objects in a second loop after your primary loop rather than sneaking your logging code directly into the first loop. It's less efficient, but if you're often making these kinds of mistakes, it can help you find problems and achieve correctness.
Another habit breaker is to console.log(JSON.stringify(foo)) rather than console.log(foo) because console.log in the browser actually remembers the reference of the object and shows you its current contents, rather than its contents at the time it was logged. This is different depending on the platform, where node.js will log as text instead of by reference.
Good luck and be careful!
I'm trying to load some JSON data from a JSON file and carrying out some data manipulation on it for an app I'm trying to build. However, when looping through the data, I'm getting an undefined error which makes it seem that property is missing from the JSON object when I use a looping variable to access the objects. However, when I index the JSON array with a hardcoded number, the property loads fine. I am wondering if someone can help me out with this. I've attached an example of the code and the JSON to this.
I have tried stringifying the JSON and parsing it again and tried both accessing the JSON using square brackets as well as the full stop and they all lead to the same result.
Code to access:
import ontology from '../../data/ontology.json'
const totalAnswerList = ontology.answers
for (var i = 0; i <= totalAnswerList.length; i++) {
var wordID = totalAnswerList[i] // wordID.id returns undefined
var wordID2 = totalAnswerList[0] // wordID2.id works
alert(JSON.stringify(wordID) + JSON.stringify(wordID2) + '\nWord ID hardcoded: ' + wordID2.id)
}
//ontology.json
{
"answers": [
{
"id": "examination",
"category_id": "examination",
"synonyms": ["examination"]
}, ...
], ...
}
The code you provided works as expected, but the issue is the last element is undefined because of your for loop constraints. You likely want i < totalAnswerList.length and not <=. Because if the array is 5 elements long, you want to loop through 0,1,2,3,4 (and not 5, which will be undefined).
import ontology from "./ontology.json";
const totalAnswerList = ontology.answers;
for (var i = 0; i < totalAnswerList.length; i++) {
// ...
}
I am working on scraping part and i am getting the data well, but when I am iterating the array and trying to get the data throwing me
TypeError: Cannot read property '3' of undefined
My code is:
$('table#blob1 tr.insRow').filter(function(){
var data = $(this);
i = i + 1;
bow_arr[i] = new Array(6);
bow_arr[i][1] = data.children(1).text();
bow_arr[i][2] = data.children(2).text();
bow_arr[i][3] = data.children(3).text();
bow_arr[i][4] = data.children(4).text();
bow_arr[i][5] = data.children(5).text();
bow_arr[i][6] = data.children(6).text();
})
Here i am creating two dimensional array and inserting the data into it. and i am able to get all the children values correctly and i have inserted all those data into the two dimensional array.
The filter function runs for 5 times since it is encountered five times.
for(i=0;i<1;i++){
console.log(bow_arr[i][3]+" - "+bow_arr[i][4]);
}
The above code i am just trying to print the values but i am getting TypeError like this.
TypeError: Cannot read property '3' of undefined
According your code, your iterator loop is written in a wrong way.
In your code you have
i = i + 1;
Which makes your array look like this :
bow_arr[0] === undefined; // equals true
bow_arr[1] === [ 'text from child 1', 'text from child 2' ... ]
bow_arr[2] === [ 'text from child 1', 'text from child 2' ... ]
And your iterator
for(i=0;i<1;i++) { ... }
Will iterate only 0 one time.
You have two possibilities. To fix your code or to fix your iterator
I choose to fix your iterator, which should look like :
for(i=1;i<bow_arr.length;i++){
console.log(bow_arr[i][3]+" - "+bow_arr[i][4]);
}
Just to make sure you can also include a check to see if this item in the array is undefined.
for(i=1;i<bow_arr.length;i++) {
if ( !bow_arr[i] || !bow_arr[i][3] || !bow_arr[i][4] ) continue;
console.log(bow_arr[i][3]+" - "+bow_arr[i][4]);
}
As VisioN says you are indexing 0 but you have not entered anything into that post. Initiate i as 0 and you should be fine :). Move incrementation to end of filter function.
var i = 0;
$('table#blob1 tr.insRow').filter(function(){
var data = $(this);
bow_arr[i] = new Array(6);
bow_arr[i][1] = data.children(1).text();
bow_arr[i][2] = data.children(2).text();
bow_arr[i][3] = data.children(3).text();
bow_arr[i][4] = data.children(4).text();
bow_arr[i][5] = data.children(5).text();
bow_arr[i][6] = data.children(6).text();
i = i + 1;
})
Fyi: You loop ONCE in the code below = What's the point of having a loop? :)
for(i=0;i<1;i++){
console.log(bow_arr[i][3]+" - "+bow_arr[i][4]);
}
I'm clueless. I have a JSON string like this which I need to check for a supplied "property" (postsome in the following example):
var index_file =
[{
"indexAB":[
{ "postsome": ["keyword_abc", "keyword_def"] },
{ "testsome": ["keyword_111", "keyword_222"] }
]
},{
"index_random": [
{ "postsome": ["keyword_abc"] }
]
}]
There my be any number of indices ("indexAB", "index_random") with n objects inside.
I need to "find" my property postsome but I cannot get it to work, because I'm struggling with the correct way of accessing the object.
So:
for (var i = 0, l = indices.length; i < l; i += 1) {
doc._id = "postsome",
index_name = "indexAB";
indices[i]["indexAB"]; // ok, returns object on correct iteration
indices[i][index_name]; // undefined
indices[i].indexAB[0][doc._id] // ok, returns undefined or keywords
indices[i][index_name][0][doc._id] // undefined
}
Question:
How can I access a nested object in loop using a variable name index_name?
This is not a direct answer to your question but I believe that it may actually help you more than giving you a complicated way to access values in your object.
If instead of this JSON object:
var index_file =
[{
"indexAB":[
{ "postsome": ["keyword_abc", "keyword_def"] },
{ "testsome": ["keyword_111", "keyword_222"] }
]
},{
"index_random": [
{ "postsome": ["keyword_abc"] }
]
}];
you would have this much simpler data structure:
var index_file =
{
"indexAB": {
"postsome": ["keyword_abc", "keyword_def"],
"testsome": ["keyword_111", "keyword_222"]
},
"index_random": {
"postsome": ["keyword_abc"]
}
};
then it would be much easier to access, using just:
var value = index_file.indexAB.postsome[0]; // no loops, no nothing
// value == "keyword_abc"
See: DEMO
I think that what you should change is your data model because currently it is something that is very far from the idea of JSON and it will always be very hard do access data in it.
A couple of issues
"indexAB" only exists on the first element in the array
you cannot have dots inside variable names.
I suggest you test whether indexAB is a property of the object before deferencing it further. See example below:
Fixed
var indices = index_file;
for (var i = 0, l = indices.length; i < l; i++) {
var doc_id = "postsome";
var index_name = "indexAB";
indices[i]["indexAB"]; // ok, returns object on correct iteration
indices[i][index_name]; // undefined
if ("indexAB" in indices[i]) {
indices[i].indexAB[0][doc_id] // ok, returns undefined or keywords
indices[i][index_name][0][doc_id] // undefined
}
}
index_name is undefined because the line prior to that raises an error
doc._id = "postname" // this causes an error
Just use a simple string
doc = "postname"