Parse React - Observe Objects created by Parse.User.current() - javascript

I'm using the excellent parse-react library to get Parse and ReactJS to work together nicely (n.b I've only been playing around for a few hours so apologies if I've misunderstood any of the basics of reactjs).
All was going well until I wanted to query a table for all objects created by the current user (Parse.user.current())
The observe method works correctly on load and the view is rendered with the correct objects (the objects created by the current user). However if I mutate the data and add a new object then the view doesn't re-render.
Abstracted code:
module.exports = React.createClass({
mixins: [ParseReact.Mixin],
getInitialState: function() {
return {
selected: null
};
},
observe: function() {
return {
places: (new Parse.Query('Place'))
.equalTo('user', Parse.User.current())
.descending('createdAt')
};
},
clickHandler: function(event) {
var id = event.target.id;
if (id === 'new') {
ParseReact.Mutation.Create('Place', {
name: 'New Place',
user: Parse.User.current()
}).dispatch();
} else if(id.indexOf('Place:') === 0) {
this.setState({
selected: id.substring(6)
});
}
},
render: function() {
var that = this;
var navItems = this.data.places.map(function(place) {
return (
<UserNavItem id={place.id} key={place.id} label={place.name} selected={that.state.selected === place.objectId} onClick={that.clickHandler}/>
);
});
return (
<ul>
{navItems}
<UserNavItem id='new' label='+ New Place' onClick={this.clickHandler} />
</ul>
);
}
});
If I remove the part of the query that specifies the user:
.equalTo('user', Parse.User.current())
Then it works; new place objects appear in the list when added.
Has anyone got any idea what I'm doing wrong?
Am I using Parse queries incorrectly? It always seems strange that getting the data pertaining to the current user is a bit of a pain when this seems like such a common use case?
Thanks!

The solution is to call the .refreshQueries() method of the component when the new object is successfully created in Parse as described here.
My updated example:
ParseReact.Mutation.Create('Place', {
name: 'New Place',
user: Parse.User.current()
})
.dispatch()
.then(function() {
this.refreshQueries();
}.bind(this));
Thanks very much to Joshua Sierles over on the ParseReact github repo for pointing me to the solution. If you are on SO Joshua I'll give you the credit if you post your answer here :D

Related

pouchdb put is still rejected with _rev

I'm using pouchDB for the first time, and as indicated in the docs I'm using put() so it will automatically handle revisions. However, when the code is running and there's an existing item with the same ID, it's still rejecting even when including a _rev.
Here's my code:
var db = new PouchDB('blog')
...
function saveCategory(category) {
var savedCategory = {
_id: 'category' + category.id,
_rev: '2-' + String(new Date().toISOString()),
name: category.name,
nicename: category.slug,
post_count: category.count,
description: category.description,
link: category.link,
parent: category.parent
}
return db.put(savedCategory).then((response) => {
$log.log(response)
}).catch((error) => {
$log.error('error saving category ',error)
})
}
This is not the purpose of the _rev field. It is always generated by the server and not by your code. To update a document you must pull the entire document (including the _rev field), update the desired fields, and then put the document. The value of _rev should be the same as when you got it from the server.
If you have a new record, you do not need to set _rev.
The pocketDB guide has a very useful section about this.

Meteor User table value axtracting

How do I pick the email address value from meteor Mongo user table?
I have written below query to pick the element:
users=Meteor.users.find({},{emails:1})
This the code I have written to fetch the email address, but I don't know how much it's affecting performance in the code:
users = Meteor.users.find({})
users.forEach(function(key,option){
key.emails.forEach(function (key,option){
console.log(key.address)
});
});
In meteor, you should call:
users = Meteor.users.find({}, { fields: { emails: 1 } })
Reference in docs
EDIT
Please remember users is a cursor object. Cursor objects can be handled directly in templates, and must be the return of publications. You can't iterate a cursor directly in a javascript loop.
Example: (remember authorization in production publications)
Meteor.publish('user-emails', function() {
return Meteor.users.find({}, { fields: { emails: 1 } });
});
If you want to directly access the user instances, for example to iterate them in a javascript code, you need to fetch the cursor (reference in docs).
Example:
var users = Meteor.users.find({}, { fields: { emails: 1 } }).fetch();
Now users is an array of users. Feel free to iterate them.
Example (I'm using underscore.js):
var users = Meteor.users.find({}, { fields: { emails: 1 } }).fetch();
_.each(users, function(user) {
console.log(user.emails);
});
Now, if you need a vector only with emails, one on each index, you can pluck the emails from a fetched array with underscore.js (reference of pluck)
var emails = _.pluck(Meteor.users.find({}, { fields: { emails: 1 } }).fetch(), 'emails');
Hope it works :)
if its not working, dont forget to return
return users

How to add a new object to an array nested inside an object?

I'm trying to get a handle on using $resource in angularjs and I keep referencing this answer AngularJS $resource RESTful example for good examples. Fetching a record and creating a record work fine, but now i'm trying to add a "section" to an existing mongo record but can't figure it out.
documents collection
{
_id: 'theid',
name: 'My name",
sections: [
{
title: 'First title'
},
{
title: 'Second title'
}
]
}
angular controller snippet
var document = documentService.get({_id: 'theid'});
// TRYING TO ADD $scope.section TO THE SECTIONS ARRAY IN THE VARIABLE document.
//document.sections.push($scope.section); <-- This does NOT work
//document.new_section($scope.section); <-- could do this and then parse it out and insert it in my backend code, but this solution seems hacky and terrible to me.
document.$save(function(section) {
//$scope.document.push(section);
});
documentService
return $resource(SETTINGS.base + '/documents/:id', { id: '#id' },
{
update: { method: 'PUT' }
});
From the link i posted above, If I was just updating the name field, I could just do something like this:
var document = documentService.get({_id: 'theid'});
document.name = "My new name";
document.$save(function(section) {
//$scope.document.push(section);
});
I'm just trying to add an object to a nested array of objects.
Try this:
documentService.get({_id: 'theid'}, function(document) {
document.sections.push($scope.section);
document.$save();
});

Ember js - Hasmany relationships breaks after updating other tables

I am using Ember.js with local-storage-adapter. I have a weird problem while updating records.
I have a post and comments model with hasMany relationships:
App.Post = DS.Model.extend({
title: DS.attr('string'),
comments: DS.hasMany('comment', {
async: true
})
});
App.Comment = DS.Model.extend({
message: DS.attr('string')
});
These are my post and comments controllers:
App.PostsController = Ember.ArrayController.extend({
newTitle: '',
actions: {
create: function() {
var title = this.get('newTitle');
var post = this.store.createRecord('post', {
title: title
});
this.set('newTitle', '');
post.save();
}
}
});
App.CommentsController = Ember.ArrayController.extend({
needs: "post",
post: Ember.computed.alias("controllers.post.model"),
newMessage: '',
actions: {
create: function() {
var message = this.get('newMessage');
var comment = this.store.createRecord('comment', {
message: message
});
var post = this.get('post');
var comments = post.get('comments');
if (comments.get('content') == null) comments.set('content', []);
comments.pushObject(comment);
comment.save();
post.save();
}
}
});
While creating records hasMany relations updated correctly.
{
"App.Post": {
"records": {
"0v66j": {
"id": "0v66j",
"title": "post1",
"comments": ["p31al", "tgjtj"]
}
}
},
"App.Comment": {
"records": {
"p31al": {
"id": "p31al",
"message": "comment 1"
},
"tgjtj": {
"id": "tgjtj",
"message": "comment 2"
}
}
}
}
The problem occured while editing post. The relationships are gone after editing the post record. I did some searching and found this code:
DS.JSONSerializer.reopen({
serializeHasMany: function(record, json, relationship) {
var key = relationship.key;
var relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship);
// alert(relationshipType);
if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany' || relationshipType === 'manyToOne') {
json[key] = Ember.get(record, key).mapBy('id');
// TODO support for polymorphic manyToNone and manyToMany
// relationships
}
}
});
This did the trick and it worked fine. But now I have another problem. If I edit any other record, all the id references are replaced by whole object like this:
{"App.Post":{"records":{"0v66j":{"id":"0v66j","title":"post2","comments":[**{"message":"comment 1"},
{"message":"comment 2"}**]},"8nihs":{"id":"8nihs","title":"post3","comments":["b4v2b","dbki4"]}}},
"App.Comment":{"records":{"p31al":{"id":"p31al","message":"comment 1"},"tgjtj":{"id":"tgjtj","message":"comment 2"},
"b4v2b":{"id":"b4v2b","message":"comments3"},"dbki4":{"id":"dbki4",
"message":"comments4"}}}}
Comment refrences should be comments":["p31al","tgjtj"] like this. but the ids are replaced as "comments":[{"message":"comment 1"},{"message":"comment 2"}]
When using ApplicationSerializer which extends LSSerializer, it seems to work.
Maybe it got fixed since asked?
I've noticed a few things in my path with Ember... and especially Ember-Data.
One of them is when dealing with associations I've had to manually re-add in the associations saving and having to re-save, and use addObject to in-memory associations as you're using a bit here. :)
Note that this usually only happens when I'm updating more than one new object at once. For example, if your post is new, and your comment is also new.
I'm a little worried to see the following code in your codebase, because it shouldn't need to be there. You shouldn't ever have null or non-array objects in your associations. I'm not sure what hackery you did with the Adapter and why it was necessary, but I hope that wasn't the reason:
if(comments.get('content') == null)
comments.set('content', []);
Anyway, the following code is how I would probably write your create action. It might help. I hope it does.
create: function() {
// get the post for association on the new comment
var post = this.get('post');
// get the message to store on the new comment
var message = this.get('newMessage');
var comment = this.store.createRecord('comment', {
message : message,
post : post
});
comment.save().then(function(savedComment) {
post.get('comments').addObject(savedComment);
});
}
Note that it's a lot simpler. Generally if you're doing tricky complicated things, something's amiss and it's time to go back to basics and add one thing at a time, testing thoroughly between additions. :)
Good luck!

Meteor Iron Router : Passing data between routes

How do I pass data between two different routes and templates?
I have a javascript file on the front end (client folder) that simply calls Router.go() passing in the post ID as one of my parameters.
Below are the three main culprits (I believe). I've removed most of the code to make it easier to read. I can change to the PostDetail page with no problems. I can also retrieve the PostId on the PostDetail page from the Router. My problem is, the database entry (POLL) that is retrieved does not get rendered on the template. Hence {{Question}} is always blank even though the database entry is being returned.
Let me know if I should post more information.
FrontEnd.js
Template.PostTiles.events({
// When a choice is selected
'click .pin' : function(event, template) {
Router.go('Post', {_PostId: this.PostId});
}
});
post-detail.html
<template name="PostDetail">
<h3>{{Question}}</p>
</template>
Shared.js
Router.map( function() {
this.route('Home', {
path: '/',
template: 'PostTiles',
data: {
// Here we can return DB data instead of attaching
// a helper method to the Template object
QuestionsList: function() {
return POLL.find().fetch();
}
}
});
this.route('Post', {
template: 'PostDetail',
path: '/Post/:_PostId',
data: function() {
return POLL.findOne(this.params._PostId);
},
renderTemplates: {
'disqus': {to: 'comments'}
}
});
});
----- Update -----
I think I've narrowed down the issue to simply being able to render only one Database entry, instead of a list of them using the {{#each SomeList}} syntax.
Looks like you found the answer / resolved this, but just in case, I think it's in your findOne statement:
data: function() {
return POLL.findOne(this.params._PostId);
},
should read:
data: function() {
return POLL.findOne({_id:this.params._PostId});
},
(assuming that POLL has your posts listed by _id.
Hope that helps.
Could you pass the info in the Session? the docs for that are here http://docs.meteor.com/#session. That's what I'm planning on doing.

Categories

Resources