I am having a little problem when trying to add a new object to an array of objects which is stored in state.
Below is a example of the object which is stored in state (scratchTickers):
id : uuid.v1(),
area : 'Scratch',
name : 'Untitled',
status : "",
size : "",
created : {
name : "username",
time : new Date()
},
modified : {
name : "username",
time : new Date()
},
content: [{
content: "Dummy content",
TowerRed: "",
TowerText: "Headlines"
}]
I need to dynamically add new objects in the content array, an object is structured like this:
{
content: "Dummy content",
TowerRed: "",
TowerText: "Headlines"
}
I am trying to use React's immutability helpers to accomplish this but It doesn't seem to be working as it should.
here is my function to add a new object to the content array and update the state:
_createTickerItem: function (id) {
var tickerID = id;
var key = null;
for (var i = 0; i < this.state.scratchTickers.length; i++) {
if(this.state.scratchTickers[i].id == tickerID) {
var ticker = this.state.scratchTickers[i];
var key = i;
}
}
var blankContent = ({
content: "Ticker Content",
TowerRed: "",
TowerText: "Headlines"
});
var oldContent = this.state.scratchTickers[key];
var newContent = update(oldContent, {
content : {
$push : [blankContent]
}
});
this.setState({
scratchTickers: newContent
});
},
So when i clicl the button tun run the _createTickerItem function the component re-renders and the main object has disappeared entirely.
Edit* Ok so I am now 1 step further making sure to set 'newContent' as an array during set state now adds new objects to the content array and renders them correctly.
this.setState({
scratchTickers: [newContent]
});
However if there were multiple objects in state, this will replace them all with juts a single object. So how would it work if I had say to parent objects in state but wanted to just modify the content array of object 1?
Edit 2: i should add that scratchTickers is an array of objects, so the for loop is needed to make sure i modify the correct object.
You're replacing the entire scratchTickers array with only the last updated object.
You have to update the entire array first.
var updates = {};
updates[key] = { $set: newContent }
var newScratchTickers = update(this.state.scratchTickers, updates);
this.setState({
scratchTickers: newScratchTickers
});
Related
I have an array of objects:
var subcategories = [{name:'gloves', tag:'wool'}, {name:'boots', tag: 'leather'}]
All I want to do is to find the index of the object to change a name or a tag. I use this function:
function setSubcat(val, index, lang){
var newArr = []
var obj = {
'name': val
}
subcategories.map((val, i)=>{
if(index === i){
var newObj = Object.assign(val, obj)
newArr.push(newObj)
}
newArr.push(val)
})
setSubcategories(newArr)
}
The error happens at var newObj = Object.assign(val, obj)
I thought the error means I can't mutate the state directly and so I have to make a copy. I thought that mapping through subcategories and push it into a local newArr means I made a copy of the array. But it wasn't working when I wanted to change a value of object in it so I used Object.assign which I thought would deep copy the particular object from the array, but it's not working either.
What am I missing here?
As pointed in comments:
the code you posted does not show how you created object with unmodifiable property
you can create a new object and not use Object.assign to get rid of the error
use map function in more idiomatic way
interface TaggedItem {
name: string,
tag: string
}
var subcategories = [{name:'gloves', tag:'wool'}, {name:'boots', tag: 'leather'}];
function setSubcat(val: string, index: number, _lang: any){
var obj: Partial<TaggedItem> = {
'name': val
}
var newArr: TaggedItem[] = subcategories.map((val, i)=>{
if(index === i){
return {
...val,
...obj
}
} else {
return {...val};
// or return val; if you don't need a full copy
}
})
console.log(newArr);
}
setSubcat('newName', 0, undefined);
Playground link
This question already has answers here:
Why can't you modify the data returned by a Mongoose Query (ex: findById)
(3 answers)
Closed 4 years ago.
I am returning an array of document objects from a Mongoose query. The array is populated with expected results.
[{
_id: 1,
name: 'Mayonnaise'
},
{
_id: 2,
name: 'Gravy'
}]
I am trying to add a new property on to certain objects only where a criteria is met. I've tested this element and the conditional logic is also performing as expected. I loop through the array above and another, larger array to find matching ids. When a match is found, I need to add a property, for example:
{isArchived: true}
to the object in the array returned by the find() query. So I should end up with:
[{
_id: 1,
name: 'Mayonnaise'
},
{
_id: 2,
name: 'Gravy',
isArchived: true
}]
The problem is that no matter what I try I cannot get the new property added onto the specific object within the array.
I have tried just about every 'Add property to an object' answer on here, so am just about ready to start throwing things!!
Thanks for any and all help!
EDIT: The entire router code is as follows:
router.get('/edit/:id', ensureAuthenticated, (req, res) => {
Menu.findOne({ _id: req.params.id })
.populate('recipes')
.then(menu => {
Recipe.find({user: req.user.id}, function (err, allRecipes) {
if(menu.user != req.user.id){
req.flash('error_msg', 'Not Authorised!');
res.redirect('/menus');
} else {
//use momentjs to format dates to YYYY-MM-DD
const vFromDate = moment(menu.validFrom).format('YYYY-DD-MM');
const vToDate = moment(menu.validTo).format('YYYY-DD-MM');
const selectedRecipeIds = menu.recipes.map(id => id._id);
for (var i = 0; i < allRecipes.length; i++){
for (var j = 0; j < selectedRecipeIds.length; j++){
if (JSON.stringify(allRecipes[i]._id) == JSON.stringify(selectedRecipeIds[j]._id)) {
allRecipes[i].isSelected = true
}
}
}
res.render('menus/edit', {
menu,
vFromDate,
vToDate,
allRecipes
});
}
});
})
});
a = [{
_id: 1,
name: 'Mayonnaise'
},
{
_id: 2,
name: 'Gravy'
}]
a[0].isArchived = true
I think you are trying to mutate the original objects that came from the response.
Try to operate on a copy, like this:
const allRecipiesCopy = [...allRecipies]
And then loop over this array, and mutate these objects, not original ones.
I'm trying to transform my object to list dynamically, so I'm building at view instead of declaring at controller.
I don't want to declare like this: custom_fields.title_field.type_text_field = [] because the title_field is built dynamic, it could be any kind of text like full_name
My json as is:
"custom_fields":{
"title_dynamic_generate_field":{
"type_text_field":{
"name":"John",
"first_name":"Wick"
},
"type_boolean_field":{
"is_badass": true,
"is_good_movie": true
},
"type_select_field": {
"this_select": 1,
"i_got_this": "nope i didnt got this"
}
},
And to be:
"custom_fields":{
"title_dynamic_generate_field":{
"type_text_field":[{
"name":"John",
"first_name":"Wick"
}],
"type_boolean_field":[{
"is_badass": true,
"is_good_movie": true
}],
"type_select_field": [{
"this_select": 1,
"i_got_this": "nope i didnt got this"
}]
},
the object I'm trying to transform into array is type_text_field which can be dynamic too, like type_date_field or type_select_field and so on.
My ng-model is like this:
ng-model="objectApp.application.applicant.custom_fields[layout.dynamic_title][input.type][input.variable]"
the [input.type] is that I'm trying to transform into array, how can I achieve this? I tried to use $index, but got strange results.
We can do it by 2 solutions:
There is a question about your task:
? how you want handle if we have more than one type_text_field in title_dynamic_generate_field? because you want to convert it to "type_text_field":[{},...]
however my answers about the question are:
If we know what's the dynamic params which we want to send theme as json, i mean if we know what is the key of title_dynamic_generate_field or type_text_field, we do as this sample:
var data = {
"custom_fields": {
dynamicParamIs1: 'title_dynamic_generate_field',
dynamicParamIs2: 'type_text_field',
"title_dynamic_generate_field": {
"type_text_field": {
"name": "John",
"first_name": "Wick"
}
}
}
}
var paramHelper1 = json.custom_fields[json.custom_fields.dynamicParamIs1];
var paramHelper2 = json.custom_fields.dynamicParamIs2;
var solutionA = function (object, as) {
var array = [];
for (var key in object) {
var newObject = object[key];
array.push(newObject);
}
object[as] = array;
}
solutionA(paramHelper1, paramHelper2);
We changed a model of our json which can help us to detect (find) the keys
If we don't know what is the dynamic params are, we do as this:
var data = {
"custom_fields": {
"title_dynamic_generate_field": {
"type_text_field": {
"name": "John",
"first_name": "Wick"
}
}
}
}
var solutionB = function (json) {
var array = [];
for (var key in json) {
var j1 = json[key];
for (var key2 in j1) {
var j2 = j1[key2];
for (var key3 in j2) {
var fullObject = j2[key3];
array.push(fullObject);
j2[key3] = array;
}
}
}
}
solutionB(data);
This sample is manual which we use nested for to detect the keys name
I am displaying a list of tables and each row is also expandable. I want to filter the list using the property of expandable table. For example if the main table show the general info of student and expandable table shows the marks of subject for that student. I want to filter the complete table by marks column. So the filtering should display the parent table with matched marks.
var students = [{
name: "neha",
address: "abc"
marks: [{
subject: "english",
marks: 80
}, {
subject: "hindi",
marks: 60
}]
}, {
name: "sneha",
address: "xyz"
marks: [{
subject: "english",
marks: 70
}, {
subject: "math",
marks: 50
}]
}
For this
I am using custom filter to filter the list. Inside custom filter I am using "filterFilter" to filter the marks array.
filterBy is the property which keeps track of property against which the value will be tested.
For example the values can be
1) filterBy = {property: "marks.subject", value: "hindi"} //filter on nested table
2) filterBy = {property: "name": value: "neha"} //filter on parent table
var app = angular.module("MyApp", []);
app.filter("filterTable", function(filterFilter) {
return function(list, filterBy) {
var filteredList = [],
len,
i,
j,
property,
present,
tempList,
listCopy,
properties = [];
//creating a copy as filter will update the list and rest filter will not work properly
listCopy = angular.copy(list);
len = listCopy.length;
if(filterBy.value) {
properties = filterBy.property.split(".");
//if filter on nested table
if(properties.length > 1) {
property = properties[1];
for ( i = 0; i < len; i++) {
tempList = {};
//using filterFilter defined by angularjs
listCopy[i].disks = filterFilter(list[i].disks, { [property] : filterBy.value });
console.log(list[i].disks);
if(listCopy[i].disks.length) {
filteredList.push(listCopy[i]);
}
}
} else {
property = filterBy.property;
for ( i = 0; i < len; i++) {
if(list[i][property].indexOf(filterBy.value) > 0) {
filteredList.push(list[i]);
}
}
}
return filteredList;
} else {
return list;
}
};
});
But this is going into infinite digest cycle. I have spent a long time on this and still not able to resolve. Please help me with it.
Thanks in advance.
This happens because you are deep copy array.
Angular's ngRepeat doesn't realize that those objects are equal because ngRepeat tracks them by identity. New object leads to new identity. This makes Angular think that something has changed since the last check, which means that Angular should run another check (aka digest).
Try update logic of filter without angular.copy()
Update:
Instead of angular.copy use flat copy:
var newArray= oldArray.slice(); // clones the array and returns the reference to the new array.
I'm trying to write a JSON object that contains both first-level data along with arrays into MongoDB.
What happens instead is all first-level data is stored, but anything contained in an array isn't. When logging the data the server receives, I see the entire object, which leads me to believe there's something wrong with my Mongoose code.
So for example if I send something like this:
issueId: "test1",
issueTitle: "testtest",
rows: [
{order:1,data: [object]},
{order:2,data: [object]},
]
Only the following gets stored:
issueId: "test1",
issueTitle: "testtest",
lastUpdated: Date,
I have the following model for Mongo:
//model.js
var mongoose = require('mongoose');
var model = mongoose.Schema({
issueId : String,
issueTitle : String,
lastUpdated : {type: Date, default : Date.now},
rows : [{
order : Number,
data : [
{
title : String,
text : String,
link : String,
}
]
}]
});
module.exports = mongoose.model('Model', model);
And the routing code, where I believe the problem likely is:
//routes.js
const mongoose = require('mongoose');
const Model = require('./model.js');
...
app.post('/api/data/update', function(req, res) {
let theData = req.body.dataToInsert;
console.log(JSON.stringify(theData,null,4));
Model.findOneAndUpdate(
{issueId : theData.issueId},
{theData},
{upsert: true},
function(err,doc){
if(err) throw err;
console.log(doc);
});
});
As well, here's the part of the Angular controller storing the data. I don't think there's any problem here.
pushToServer = function() {
$http.post('/api/data/update',{
dataToInsert : $scope.dataObject,
}).then(function successCallback(res){
console.log("all good", JSON.stringify(res,null,3));
}, function errorCallback(res){
console.log("arg" + res);
});
}
Look at the first question in the mongoose FAQ:
http://mongoosejs.com/docs/faq.html
Mongoose doesn't create getters/setters for array indexes; without them mongoose never gets notified of the change and so doesn't know to persist the new value. The work-around is to use MongooseArray#set available in Mongoose >= 3.2.0.
// query the document you want to update
// set the individual indexes you want to update
// save the document
doc.array.set(3, 'changed');
doc.save();
EDIT
I think this would work to update all of the rows. I'd be interested to know if it does work.
let rowQueries = [];
theData.rows.forEach(row => {
let query = Model.findOneAndUpdate({
issueId: theData.issueId,
'row._id': row._id
}, {
$set: {
'row.$': row
}
});
rowQueries.push(query.exec());
});
Promise.all(rowQueries).then(updatedDocs => {
// updated
});