update an object with a new object - arrays

i have an array that is been already loaded on to view, i need to update a specific object in array
modified_data(){
this.nativeStorage.getItem("modifiedData").then((data)=>{
console.log("modified_data fun", data);
// console.log(this.dailyDays);
var array = this.dailyDays;
for (var i = 0; i < array.length; i++) {
var element = array[i];
// console.log("in aloop",element.day);
if (element.day === data.day) {
console.log("got same da", element);
this.dailyDays.push({
day: data.day,
month: this.currentDate.getMonth(),
year: this.currentDate.getFullYear(),
price: data.price,
brand: data.selectedBrand,
howManyDay: data.selectedDay,
quantity: data.selectedQuantity
});
} else {
}
}
})
}
By using the above code a new object gets added up at the bottom of the array in html,
The array in the view have a date listed if i find the same date then that date should be updated with the new object
some one help me

From what I understand, the logic should look something like this. It looks for an existing object in the array, if it finds a match, returns the index, if not, returns -1. Based on that, you can perform
modified_data(){
this.nativeStorage.getItem("modifiedData").then((data)=>{
console.log("modified_data fun", data);
// console.log(this.dailyDays);
// var array = this.dailyDays;
let updateItem = this.dailyDays.find(this.findIndexToUpdate, data.day);
let index = this.dailyDays.indexOf(updateItem);
if(index > -1){
// Add whatever logic you need to update existing object
// below line will replace the whole object
this.dailyDays[index] = data;
}
else{
this.dailyDays.push({
day: data.day,
month: this.currentDate.getMonth(),
year: this.currentDate.getFullYear(),
price: data.price,
brand: data.selectedBrand,
howManyDay: data.selectedDay,
quantity: data.selectedQuantity
})
}
})
findIndexToUpdate(data) {
return data.day === this;
}

Related

Setting nested array inside object in ReactJS

I have a Post like application, where a user can add comments with emojis to the post, which I have a method for:
addEmoji = (newEmoji) =>{
// mark if new emoji is already in the array or not
let containsNewEmoji = false;
let authors = []
authors.push(this.props.comment.author.name)
console.log(this.props.comment.author.name)
console.log(authors)
// recreate emojis array
let newEmojis = this.state.emojis.map(emoji => {
// if emoji already there, simply increment count
if (emoji.id === newEmoji.id) {
containsNewEmoji = true;
return {
...newEmoji,
...emoji,
count: emoji.count + 1,
authors: [...authors, authors]
};
}
// otherwise return a copy of previous emoji
return {
...emoji
};
});
console.log(authors)
// if newEmoji was not in the array previously, add it freshly
if (!containsNewEmoji) {
newEmojis = [...newEmojis, {...newEmoji, count: 1, authors: [...authors, authors]}];
}
// set new state
this.setState({ emojis: newEmojis,
showEmoji: true});
}
As shown in the method comments to the code, each emoji-only displays once, otherwise, a count variable will increment, to be shown below each comment.
I would like to add the feature, to save an array of the given username of the person, who added the emoji.
the username is given in as a prop
this.props.comment.author.name
so I have tried making an array to add the names 7
let authors = []
authors.push(this.props.comment.author.name)
the issue is that it's being overwritten each time a new emoji instance is being passed, I tried saving it to the object
return {
...newEmoji,
...emoji,
count: emoji.count + 1,
authors: [...authors, authors] // i want to save the old copy of authors and pass the new name
};
newEmojis = [...newEmojis, {...newEmoji, count: 1, authors: [...authors, authors]}]; // and then set the object in the end
As of now, the array is being overwritten each time, but could I set the parameter inside the object?
This is coming from setting the author field to an empty array early on in the code,
let authors = []
Instead it has to be set to the authors earlier on, as in:
authors: [..emoji.authors, author];
You should also consider using function of setState when dealing with setState.
addEmoji = (newEmoji) => {
const author = this.props.comment.author.name;
this.setState(({ emojis: prevEmojis }) => {
let containsNewEmoji = true;
const newEmojis = prevEmojis.map((emoji)=>{
if(newEmoji.id === emoji.id) {
containsNewEmoji = false;
return {
...emoji,
count: emoji.count + 1,
authors: [..emoji.authors, author];
}
} else {
return {
...emoji,
}
}
});
if(containsNewEmojis) {
newEmojis.push({
...newEmoji,
count: 1,
authors: [author],
});
}
return {
emojis: newEmojis,
}
});
}
I have reversed the containsNewEmoji variable so that it fits the context.
Yes, in the addEmoji method you're currently recreating the authors array each time addEmoji is called. Instead of defining a new authors array, push the new author into the existing authors property of the emoji.
Without knowing how the emoji object is initially created I can't give a definitive answer, but hopefully the following is a start. The solution assumes the emoji object has an authors property of type array.
addEmoji = (newEmoji) => {
// mark if new emoji is already in the array or not
let containsNewEmoji = false;
// recreate emojis array
let newEmojis = this.state.emojis.map(emoji => {
// if emoji already there, simply increment count
if (emoji.id === newEmoji.id) {
containsNewEmoji = true;
return {
...emoji,
count: emoji.count + 1,
authors: [...emoji.authors, this.props.comment.author.name]
};
}
// otherwise return a copy of the previous emoji
return emoji;
});
};

excluding from an object angular ng-change

Hello guys i am trying to clear my ng-model when i fire my change function but my problem that i don't want to delete all i want to exclude one item in the object.
function change() {
if (vm.location.type) {
angular.forEach(vm.location, function (value, index) {
delete vm.location;
});
}
}
so i don't want to delete the
vm.location.type
my
vm.location
has
vm.location.boundaries;
vm.location.region;
vm.location.address;
vm.location.name;
vm.location.nonVisitingRadius;
vm.location.visitingRadius;
See the code below,
var obj = { a:123, b:123, c:123 }
delete obj.a;
Hence obj will be like this {b:123, c:123}
Note: Dont need any for loop to delete property from object
Updated Answer:
var obj= {
a: 'aaa',
b: 'bbb',
c: 'ccc',
d: 'ddd'
};
var removeObj = function(obj, props) {
for(var i = 0; i < props.length; i++) {
if(obj.hasOwnProperty(props[i])) {
delete obj[props[i]];
}
}
};
removeObj (obj, ["a", "d"]);
i don't know if i understand correctly what you're asking, but if you want to clear all the fields of your object preserving only type and preserving the reference of the object with plain javascirpt (no libraries), loop over the fields and check if the i field is equal to type.
for(var i in model.location){
if(i !== 'type')
delete model[i];
}
with underscore.js you could define a default model like:
var defaultModel = {
location: {
region: '',
address: '',
name: '',
nonVisitingRadius: '',
visitingRadius: '',
type: 'defaultvalue'
}
}
and when ng-change is triggered inside the function
_.extend(model, defaultModel);
that will keep the default value for type and clear all the others.
You can do it this with a temporary object :
let tempLocation = {};
tempLocation.type = $scope.location.type;
$scope.location = tempLocation;

Backbone model#destroy thru Collection#each does not iterate through all models correctly

My model
app.Item = Backbone.Model.extend({
defaults: {
title: '',
checked: false,
price: 0
}
});
Collection
app.ItemCollection = Backbone.Collection.extend({
model: app.Item,
localStorage: new Store('itaaatems')
});
I create a simple collection that has the model 'Item'.
app.itemCollection = new app.ItemCollection([
new app.Item({title: "webb dev", checked: true, price: 100}),
new app.Item({title: "drawing", price: 200}),
new app.Item({title: "corn harvesting", price: 750}),
new app.Item({title: "pen spinning", price: 50}),
new app.Item({title: "pen spiddnning", price: 50}),
new app.Item({title: "shark riding", price: 2000})
]);
I save each of them and see the success callback.
app.itemCollection.each(function (item){
item.save(null, {success: function () {
console.log('good');
}
});
});
Everything looks good as I see each item as a model
app.itemCollection.each(function (item){
console.log(item);
});
But when I try to delete them and for some reason after deleting the 3rd item, it hits a undefined. The 4th item is not defined for some reason while the first 3 I get success callbacks.
app.itemCollection.each(function (item){
item.destroy({success: function (model, response) {
console.log(response);
}
});
});
The problem is that you're iterating over an array and modifying it at the same time. Your app.itemCollection.each is little more than:
for(var i = 0; i < app.itemCollection.models.length; ++i)
app.itemCollection.models[i].destroy({ ... });
in disguise and each destroy call will change the app.itemCollection.models array behind your back. If you keep an eye on the collection as you're deleting things:
app.itemCollection.each(function(item) {
console.log(app.itemCollection.toJSON());
item.destroy({ ... });
});
you should see the iteration appear to skip items.
You could iterate backwards and use Collection#at and a for-loop:
for(i = app.itemCollection.length - 1; i >= 0; --i)
app.itemCollection.at(i).destroy({ ... });
or use toArray to get a copy of the underlying array of models and iterate over that:
app.itemCollection.toArray().forEach(function(item) {
item.destroy({ ... });
});

Nodejs async data duplication

I'm having some problems with one async process on nodejs.
I'm getting some data from a remote JSON and adding it in my array, this JSON have some duplicated values, and I need check if it already exists on my array before add it to avoid data duplication.
My problem is when I start the loop between the JSON values, the loop call the next value before the latest one be process be finished, so, my array is filled with duplicated data instead of maintain only one item per type.
Look my current code:
BookRegistration.prototype.process_new_books_list = function(data, callback) {
var i = 0,
self = this;
_.each(data, function(book) {
i++;
console.log('\n\n ------------------------------------------------------------ \n\n');
console.log('BOOK: ' + book.volumeInfo.title);
self.process_author(book, function() { console.log('in author'); });
console.log('\n\n ------------------------------------------------------------');
if(i == data.length) callback();
})
}
BookRegistration.prototype.process_author = function(book, callback) {
if(book.volumeInfo.authors) {
var author = { name: book.volumeInfo.authors[0].toLowerCase() };
if(!this.in_array(this.authors, author)) {
this.authors.push(author);
callback();
}
}
}
BookRegistration.prototype.in_array = function(list, obj) {
for(i in list) { if(list[i] === obj) return true; }
return false;
}
The result is:
[{name: author1 }, {name: author2}, {name: author1}]
And I need:
[{name: author1 }, {name: author2}]
UPDATED:
The solution suggested by #Zub works fine with arrays, but not with sequelize and mysql database.
When I try to save my authors list on the database, the data is duplicated, because the system started to save another array element before finish to save the last one.
What is the correct pattern on this case?
My code using database is:
BookRegistration.prototype.process_author = function(book, callback) {
if(book.volumeInfo.authors) {
var author = { name: book.volumeInfo.authors[0].toLowerCase() };
var self = this;
models.Author.count({ where: { name: book.volumeInfo.authors[0].toLowerCase() }}).success(function(count) {
if(count < 1) {
models.Author.create(author).success(function(author) {
console.log('SALVANDO AUTHOR');
self.process_publisher({ book:book, author:author }, callback);
});
} else {
models.Author.find({where: { name: book.volumeInfo.authors[0].toLowerCase() }}).success(function(author) {
console.log('FIND AUTHOR');
self.process_publisher({ book:book, author:author }, callback);
});
}
});
// if(!this.in_array(this.authors, 'name', author)) {
// this.authors.push(author);
// console.log('AQUI NO AUTHOR');
// this.process_publisher(book, callback);
// }
}
}
How can I avoid data duplication in an async process?
This is because you are comparing different objects and result is always false.
Just for experiment type in the console:
var obj1 = {a:1};
var obj2 = {a:1};
obj1 == obj2; //false
When comparing objects (as well as arrays) it only results true when obj1 links to obj2:
var obj1 = {a:1};
var obj2 = obj1;
obj1 == obj2; //true
Since you create new author objects in each process_author call you always get false when comparing.
In your case the solution would be to compare name property for each book:
BookRegistration.prototype.in_array = function(list, obj) {
for(i in list) { if(list[i].name === obj.name) return true; }
return false;
}
EDIT (related to your comment question):
I would rewrite process_new_books_list method as follows:
BookRegistration.prototype.process_new_books_list = function(data, callback) {
var i = 0,
self = this;
(function nextBook() {
var book = data[i];
if (!book) {
callback();
return;
}
self.process_author(book, function() {
i++;
nextBook();
});
})();
}
In this case next process_author is being called not immediately (like with _.each), but after callback is executed, so you have consequence in your program.
Not sure is this works though.
Sorry for my English, I'm not a native English speaker

Check input value against an array

I am using this plugin for my autocomplete form:
http://www.planbox.com/blog/news/updates/jquery-autocomplete-plugin-for-backbone-js.html
Instead of checking only one item, as in the code below (if (inputVal == 'bakaxel')),
I would like to check the selected value against the entire collection
var collection = new Backbone.Collection([
{id:"AB", name:"Alberta"},
{id:"AD", name:"Album"},
{id:"BA", name:"barn"},
{id:"BC", name:"bak"},
{id:"BD", name:"baby"},
{id:"BE", name:"band"},
{id:"BF", name:"bakaxel"},
{id:"BG", name:"batteri"},
{id:"BH", name:"barbie"},
{id:"MB", name:"Manitoba"},
{id:"AP", name:"Armed Forces Pacific"}
]);
$('input.search').autocomplete({
collection: collection,
attr: 'name',
noCase: true,
ul_class: 'search_options tr_list',
ul_css: {'z-index':1234}
});
$('input.search').each(function(){
$(this).blur(function(){
var inputVal = $('input.search').val();
if (inputVal == 'bakaxel') {
$('#search_result_page').load('searchResult.html');
$('#searchPage').addClass('hidden');
}
});
});
I tried this, but I'd rather not create the ar array again, just use the backbone collection:
$('input.search').each(function(){
$(this).blur(function(){
var inputVal = $('input.search').val();
var ar = ["Alberta", "Album", "barn", "bak", "baby", "band", "bakaxel", "batteri", "barbie", "Manitoba", "Armed Forces Pacific"];
if (jQuery.inArray(inputVal, ar) != -1) {
$('#search_result_page').load('searchResult.html');
$('#searchPage').addClass('hidden');
}
});
});
Backbone proxies Underscore functions and most notably in your case http://underscorejs.org/#where
where _.where(list, properties)
Looks through each value in the list, returning an array of all the values that contain all of the
key-value pairs listed in properties.
Your test could be written as
var matches = collection.where({
name: inputVal
});
if (matches.length>0) {
...
}
Or as #mu suggested in the comments, you could just check the existence of the input with http://underscorejs.org/#find
var found = collection.find(function(model) {
return model.get('name') === inputVal
});
if (found) {
...
}

Resources