What is wrong with my JavaScript append function? - javascript

In the below method, an object o is appended to a list of objects qs. The commented part does not work, the now uncommented part does work. What is wrong with the commented part?
onCreate(o) {
// This works (using lodash)
this.setState({ qs: _.concat(this.state.qs, { id: this.getNextID(), ...o }) });
// Is this not the same like the above?
// let newQuestionnaire = {id: this.getNextID(), title: o.title, description: o.description};
// let questionnaires = this.state.qs.push(newQuestionnaire);
// this.setState({
// qs: questionnaires,
// });
}
Edit: Maybe it helps somebody: the first thing coming up on Google is push:
--> Dont do that.

Array Push return
The new length property of the object upon which the method was called
try this
let newQuestionnaire = {id: this.getNextID(), title: o.title, description: o.description};
this.setState({qs: [...this.state.qs, thisquestionnaires]})

Related

Sequelize "object" does not have increment function

I am using generate sequelize tables from Django generated models with sequelize-auto in my project. so far so good. I wrote the code to update the rank if I see a url again.
const findLink = async (link) =>
Link.findOne({
where: {
url: link,
},
raw: true,
});
// eslint-disable-next-line no-use-before-define
const insertEvent = async (link, tweetText) => {
// Sync Database table before reading
await sequelize.sync();
findLink(link).then((url) => {
if (url) {
url.increment("rank", {by: 1}).then(()=>{
Event.create({
url_id: url.id,
tweet_text: tweetText,
created_at: new Date(),
updated_at: new Date(),
})
});
} else {
Link.create({
url: link,
rank: 0,
created_at: new Date(),
updated_at: new Date(),
}).then((newLink) => {
Event.create({
url_id: newLink.id,
tweet_text: tweetText,
created_at: new Date(),
updated_at: new Date(),
});
});
}
});
};
But the problem is that when It execute url.increment("rank", {by: 1}) it says that url does not have increment function.
But according to documentation it is clearly stated here. Please let me know if I am doing something wrong? I have searched the internet but I could not find any thing relative. I can update the value with duplicate look up but I am looking for a way If I could update the already found object instead of searching it again.
You are using raw queries
const findLink = async (link) =>
Link.findOne({
where: {
url: link,
},
raw: true,
});
It doesn't return an instance of the Model
See https://sequelize.org/master/manual/raw-queries.html
Edit:
By default the function will return two arguments - a results array, and an object containing metadata (such as amount of affected rows, etc).
A second option is the model. If you pass a model the returned data
will be instances of that model.
// Callee is the model definition. This allows you to easily map a query to a predefined model
const projects = await sequelize.query('SELECT * FROM projects', {
model: Projects,
mapToModel: true // pass true here if you have any mapped fields
});
// Each element of `projects` is now an instance of Project
So the mapToModel option might also work

Can't get state to update array inside of an object correctly in REACT/REDUX

I am going to break this down step by step for what I want to happen so hopefully people can understand what I am wanting.
Using React/Redux, Lodash
I have many post that are sent from a back end api as an array. Each post has an _id. When I call on the action getAllPost() it gives me back that array with all the post. This is working just fine.
I then dispatch type GET_ALL_POSTS and it triggers the reducer reducer_posts to change/update the state.
reducer:
export default function(state = {}, action) {
switch(action.type) {
case GET_ALL_POSTS:
const postsState = _.mapKeys(action.payload.data, '_id');
//const newPostsState = _.map(postsState, post => {
//const newComments = _.mapKeys(post.comments, '_id');
//});
return postsState;
break;
default:
return state;
break;
}
}
As you can see I change the array into one giant object that contains many post as objects with keys that are equal to their '_id'. This works just fine and returning this part of the state also works fine.
As I mentioned each of these posts has a comments value that is an array. I would like to change the comments array into one large object that holds each comment as an object with a key that is equal to their '_id' just like I did in the post.
Now I need to do this all at once and return the newly created state with One large object that contains all the post as objects and on each of those post there should be a comments object that contains all the comments as objects. I will try to write some example code to show what I am trying to do.
Example:
BigPostsObject {
1: SinglePostObject{},
2: SinglePostObject{},
3: SinglePostObject {
_id: '3',
author: 'Mike',
comments: BigCommentObject{1: SingleCommentObject{}, 2: SingleCommentObject{}}
}
}
I hope that the example kind of clears up what I am trying to do. If it still is confusing as to what I am doing then please ask and also please do not say things like use an array instead. I know I can use an array, but that is not helpful to this post as if others want to do it this way that is not helpful information.
Write a function that processes all the comments from the comments array for each post you have in the posts array:
function processComment(post) {
post.bigCommentsObject = _.mapKeys(post.comments, '_id');
// now the comments array is no longer needed
return _.omit(post, ['comments']);
}
Now use that function to turn each comments array into a big object with all the comments WHILE it still is in the array. Then afterwards turn the array itself in a big object:
const commentsProcessed = _.map(action.payload.data, procesComment);
const postsState = _.mapKeys(commentsProcessed, '_id');
I believe nowadays JS builtin function can do this without requiring external libraries. Anyway this should be the way to go. I will really encourage you getting back to js builtin functions.
var data = [
{
_id: '3',
title: 'Going on vaccation',
comments:[
{_id: 1, comment: 'hello'},
{_id: 2, comment: 'world'}
]
},
{
_id: '2',
title: 'Going to dinner',
comments:[
{_id: 1, comment: 'hello'},
{_id: 2, comment: 'world'}
]
}
]
//you can use JS builtin reduce for this
var transformedPost= _.reduce(data, function(posts, post) {
var newPost = Object.assign({}, post)
newPost._id=post._id
//you can use js builtin map for this
newPost.comments = _.mapKeys(post.comments, '_id')
// if you are using es6, replace the last three line with this
//return Object.assign({}, posts, {[newPost._id]: newPost})
var item = {}
item[newPost._id]=newPost
return Object.assign({}, posts, item)
},{});
console.log(transformedPost)
https://jsbin.com/suzifudiya/edit?js,console

Save object to array in another model

So I got two mongoose-models:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var eventSchema = new mongoose.Schema({
name: String,
date: String,
dogs: [{ type: Schema.Types.ObjectId, ref: 'Dog' }]
});
module.exports = mongoose.model('Event', eventSchema);
and
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var dogSchema = new mongoose.Schema({
name: String,
age: String,
gender: String,
});
module.exports = mongoose.model('Dog', dogSchema);
Event contains an array of dogs and im trying to figure out how to add/delete dogs to this array.
On the client I got this method:
$.ajax({
url: "http://localhost:3000/api/events/",
dataType: 'json',
type: 'POST', // Not sure if I should Post or Put...
data: {event_Id : this.props.choosenEvent._id, //Here I got the Id of the Event that i want to update by
dog_Id : this.props.events[dog]._id }, //adding this dog, which Id is here
success: function(data) {
}.bind(this),
});
},
On the server, NodeJs, I got my routes to the API. To me, it makes sense to use an PUT-method and start by getting the right Event with the event_Id passed as a param. Something like:
router.route('/events/:event_id')
.put(function(req, res) {
Event
.findById({ _id: req.param.event_id })
.populate('dogs')
});
But Im stuck at this point. Any help appreciated. Thanks!
Update!
Thank you! Your code helped a lot, you used lodash .remove to delete a dog from the array, is there a similar way to add an item with lodash?
I gave the add method a go like this:
router.route('/events')
.post(function(req, res) {
// Your data is inside req.body
Event
.findById({ _id: req.body.event_Id })
// execute the query
.exec(function(err, eventData) {
// Do some error handing
// Your dogs are inside eventData.dogs
eventData.dogs.push(req.body.dog_Id);
console.log(eventData)
});
// Update your eventDate here
Event.update({_id: req.body.event_id}, eventData)
.exec(function(err, update) {
// Do some error handing
// And send your response
});
});
When I hit the console.log(eventData) I can see that dog_id gets added to the array as it should. However it does not get saved to the db and the error says that eventData is not defined in Event.Update. I suspect this is a Js-scope-issue.
Onte thing that boggles me is this:
Obviously I would like to be able to add and remove dogs from the array and the
route is this: router.route('/events') .
But if both the add-method and the remove-method is on the same route, how can the code know which one I am going for?
There are a few mistakes you are making. First of all, you are making a POST request but your route accepts a PUT request. I have updated your code so it accepts a POST.
When posting objects, your data is inside req.body. req.params is used for url parameters. This is also the case when using a PUT request.
Populating dogs is not really necessary. You are sending your dog_id to your function so you can delete your item from your array which removes your dog from your event. This should do the trick. Please note that this does not remove your dog from your DB but only from your event.
Last but not least. I am using lodash. _.remove is a lodash function. You should definitely check it out, it will help you a lot.
Take a look at my code. It should get you going:
router.route('/events/:event_id')
// Since you are posting, you should use POST from JavaScript instead of PUT
.post(function(req, res) {
// Your data is inside req.body
Event
.findById({ _id: req.body.event_id })
// execute the query
.exec(function(err, eventData) {
// Do some error handing
// Your dogs are inside eventData.dogs
_.remove(eventData.dogs, function(d) {
return d._id === req.body.dog_Id;
});
// Update your eventDate here
Event.update({_id: req.body.event_id}, eventData)
.exec(function(err, update) {
// Do some error handing
// And send your response
});
});
});
UPDATE:
I do not think there is a way to add items to an array with lodash but you can simply use push like you did in your code example. That works just fine.
Your update is not working because your are executing the findById and update at the same time. You will have to find the item first, add the id and THEN update the item :) Move your update function inside the callback of your findById function and that should be fixed. So it looks like this:
router.route('/events')
.post(function(req, res) {
// Your data is inside req.body
Event
.findById({ _id: req.body.event_Id })
// execute the query
.exec(function(err, eventData) {
// Do some error handing
// Your dogs are inside eventData.dogs
eventData.dogs.push(req.body.dog_Id);
console.log(eventData)
// Update your eventDate here
Event.update({_id: req.body.event_id}, eventData)
.exec(function(err, update) {
// Do some error handing
// And send your response
});
});
});
You can add different functions on the same route as long as the method is different from the others. Take a look at REST at this answer. You can have a GET, POST, PUT & DELETE on /events. This is defined by this rule:
router.route('/events').post();

How to Observe changes in an array of objects

Javascript now implements Object.observe and Array.observe, however I cannot seem to find a way to merge the functionality.
What I am trying to do is to have an array of objects. When any property of one of the objects changes, I would like to be notified.
Object.observe allows me to be notified when a property of a specific object changes.
Array.observe allows me to be notified when an array level change occurs.
Unless I specifically observe each element of an array, I have no way to know when a specific element property changes.
For example:
var model = [
{
data: 'Buy some Milk',
completed: false
},
{
data: 'Eat some Food',
completed: false
},
{
data: 'Sleep in a Bed',
completed: false
},
{
data: 'Make Love not War',
completed: false
}
];
Array.observe(model, function(changeRecords) {
console.log('Array observe', changeRecords);
});
model[0].data = 'Teach Me to code';
model[1].completed = true;
model.splice(1,1);
model.push({data: "It's a new one!",completed: true});
gives a console output of:
Array observe [Object, Object]
0: Object
addedCount: 0
index: 1
object: Array[4]
removed: Array[1]
type: "splice"
__proto__: Object
1: Object
addedCount: 1
index: 3
object: Array[4]
removed: Array[0]
type: "splice"
__proto__: Object
length: 2
__proto__: Array[0]
These two notifications relate specifically to:
model.splice(1,1);
and
model.push({data: "It's a new one!",completed: true});
but completely ignore
model[0].data = 'Teach Me to code';
and
model[1].completed = true;
Is there a way to observe every change, no matter whether it is an array level or object level change?
I know there are libraries that may be able to do this for me, however I would like to understand how to implement this directly in my own code.
EDIT: OK, So it seems I wasn't missing any magic functionality, and the only true option is to observe the individual elements of the array.
So to expand upon the original question, what is the most efficient method of adapting arrays to handle element observations?
Array observe observes array changes! You need to observe each object inside Array too using Object.Observe!
See this
function ObserveMyArray(myArray){
var arr=myArray||[];
for(var i=0;i<arr.length;i++){
var item=arr[i];
Object.observe(item , function(changes){
changes.forEach(function(change) {
console.log(change.type, change.name, change.oldValue);
});
});
}
Array.observe(arr, function(changeRecords) {
console.log('Array observe', changeRecords);
});
}

Dojo - error trying remove and add item to store (assertion failed in ItemFileWriteStore)

I have store (and grid which displays its content), users could remove and add item but unfortunately one item after deleting could not be again added. I figure out problem is same id which was previously in store.
I use Dojo 1.6.
In firebug console I got:
Error: assertion failed in ItemFileWriteStore
Here is demo on jsFiddle: http://jsfiddle.net/MBBnE/
and here code:
dojo.require("dojo.data.ItemFileWriteStore");
dojo.addOnLoad(function() {
var d = {
items: [
{
id: 23,
x: 2},
],
identifier: "id",
};
var _store = new dojo.data.ItemFileWriteStore({
data: d,
});
var it = null;
_store.fetch({
query: {
id: "23*"
},
onItem: function(i) {
it = i;
}
})
_store.deleteItem(it);
console.info(it);
_store.newItem({id: 23, x: 3});
});
Hopefully I didn't misunderstand your question, but when you remove an item from a store if you want to re-add another item with the same id, you should save the store then re-add the item. Saving the store will clear all dirty items and allow the id to be reuse.
When you insert same value in Itemfilewritestore it will give you error 'assertion failed in ItemFileWriteStore'
To overcome this problem insert new or unique value in ItemFileWriteStore
_store.newItem({id: 24, x: 3});
I hope this will help you.
Finally I did a little workaround - create new store and copy all items to it:
oldStore.fetch({
onItem: function(it){
var newItem = {
id: it.id[0],
valueX: it.valueX[0],
(...)
};
newStore.newItem(newItem);
}
});

Categories