Repeating issue in Parse.com - JavaScript SDK - javascript

Parse.com with JavaScript SDK - unnecessary duplictions
Every time I create a Parse object of "message", it duplicates that object in my Parse Core. It is so bizarre. The first time I run the code, everything is fine and Parse will create only one object. But when I run the code again, it will duplicate the most recent object twice. If I run it a third time, it will duplicate the most recent object five times. The number of duplications increases based upon how many objects have already been created. Does anyone have any idea how to make sure that it create one object in my Parse Core backend? Thank you so much!!! I wish I could post a picture, but I am a newbie and stackoverflow wont let me
This is where I create the Parse object:
App.Models.Message = Parse.Object.extend({
className: 'Message',
idAttribute: 'objectId',
defaults: {
name : '',
email : '',
subject : '',
message : ''
}
});
This is where I create an instance of the Parse object, and where I save it to Parse:
App.Views.Contact = Parse.View.extend({
el : '#middle',
template : _.template($('#contactTemp').html()),
events: {
'click .submit' : 'submit',
},
initialize : function () {
this.render();
},
render : function () {
this.$el.html(this.template);
},
submit : function (e) {
e.preventDefault();
var message = new App.Models.Message({
name: $('.nameVal').val(),
email: $('.emailVal').val(),
subject: $('.subVal').val(),
message:$('.messVal').val(),
});
message.save(null, {
success:function() {
console.log("Success");
},
error:function(e) {
alert('There was an error in sending the message');
}
});
}
});

Yes! So I figured out the problem with the help of Hector Ramos from the Parse Developers Google group.
https://groups.google.com/forum/#!topic/parse-developers/2y-mI4TgpLc
It was my client-side code. Instead of creating an event attached to my App.Views.Contact(); a.k.a. - an instance of Parse.View.extend({}), I went ahead and created a 'click' event using jquery within the sendMessage function that I recently defined. If you declare an event in the events object within the Parse view, it will recur over itself if the view wasn't re-initialized or destroyed and recreated properly.
So what happened with me was the submit function that I declared in the events object kept recuring over itself and making duplicate calls to Parse.com. My view was static, it wasn't destroyed properly, re-initialized, or reloaded. You will see what I did below:
Originally I had this:
events: {
'click .submit' : 'submit',
},
& this
submit : function (e) {
e.preventDefault();
var message = new App.Models.Message({
name: $('.nameVal').val(),
email: $('.emailVal').val(),
subject: $('.subVal').val(),
message:$('.messVal').val(),
});
message.save(null, {
success:function() {
console.log("Success");
},
error:function(e) {
alert('There was an error in sending the message');
}
});
} /*end of submit*/
Now I have I completely removed the events object that I had and declared a sendMessage function:
initialize : function () {
this.render();
},
render : function () {
this.$el.html(this.template);
this.sendMessage();
},
sendMessage : function () {
$('.submit').on('click', function(){
var message = new App.Models.Message({
name: $('.nameVal').val(),
email: $('.emailVal').val(),
subject: $('.subVal').val(),
message:$('.messVal').val(),
});
message.save(null, {
success:function() {
console.log("Success");
},
error:function() {
alert('There was an error in sending the message');
}
});
}); /*end of jquery submit*/
}/*end of send message function*/,
And now it works perfectly fine. Credit is due Hector Ramos who is a Parse.com Developer and who helped me realize that the problem was the actual event. If you guys have any easy way of stoping an event from making several duplicate calls to the back or from reoccurring several times, then please let me know.

Related

How to process two sets from different models in one custom control

Aim:
I'd like to have two models(sets of data) passed to the custom control with a predefined search field, in which later on I can execute filtering.
I'm a newbie in OpenUi5, so I might be doing something wrong and stupid here. I've started with a simplified task of passing data from the frontend to my custom control and experiencing troubles.
Background of the simplified idea:
Create a custom control with an aggregation foo , the value to it will be provided from the view.
Also create another aggregation element _searchField which will be populated with the data provided from the view.
Fire the onSuggestTerm everytime user types in a _searchField.
Custom control code:
function (Control) {
var DropDownListInput = Control.extend('xx.control.DropDownListInput', {
metadata: {
defaultAggregation: 'foo',
aggregations: {
foo: { type: 'sap.m.SuggestionItem', multiple: true, singularName: 'suggestionItem' },
_searchField: { type: 'sap.m.SearchField', multiple: false, visibility: 'hidden' }
}
}
});
DropDownListInput.prototype.init = function () {
var that = this;
this.onSuggestTerm = function (event) {
var oSource = event.getSource();
var oBinding = that.getAggregation('foo');
oBinding.filter(new sap.ui.model.Filter({
filters: new sap.ui.model.Filter('DISEASE_TERM', sap.ui.model.FilterOperator.Contains, ' Other')
}));
oBinding.attachEventOnce('dataReceived', function () {
oSource.suggest();
});
};
this.setAggregation('_searchField', new sap.m.SearchField({
id: 'UNIQUEID1',
enableSuggestions: true,
suggestionItems: that.getAggregation('foo'),
suggest: that.onSuggestTerm
}));
};
return DropDownListInput;
}, /* bExport= */true);
I'm not providing Renderer function for control here, but it exists and this is the most important excerpt from it:
oRM.write('<div');
oRM.writeControlData(oControl);
oRM.write('>');
oRM.renderControl(oControl.getAggregation('_searchField'));
oRM.write('</div>');
Passing the data to this control from the xml frontend:
<xx:DropDownListInput
id="diseaseTermUNIQUE"
foo='{path: db2>/RC_DISEASE_TERM/}'>
<foo>
<SuggestionItem text="{db2>DISEASE_TERM}"
key="{db2>DISEASE_TERM}" />
</foo>
</xx:DropDownListInput>
The code fails to run with this error Cannot route to target: [object Object] -
and I have no idea what's wrong here..
The problem is that you forgot to provide single quotes in your path:
foo="{path: 'db2>/RC_DISEASE_TERM/'}"

Siesta Ext JS test not completing

I am testing an Ext JS frontend with Siesta.
Here is my login/logout test:
StartTest(function(t) {
t.diag("Login/Logout");
t.chain(
{ waitForCQ : '#loginPanel' },
function(next) {
t.cq1("#username").setValue();
t.cq1("#password").setValue();
next();
},
{ click: '>> #username' },
{ type: '******', target : '>> #username' },
{ type: '******', target : '>> #password' },
{ click: '>> #loginButton' },
{ waitForCQ: '#mainView' },
{ click: '>> #logoutButton' },
{ waitForCQ: 'messagebox #ok' },
function(next) {
t.waitForEvent(Ext.globalEvents, 'logoutComplete', function () {});
next();
},
{ click : '>> messagebox #ok' },
function() {
t.done();
}
);
});
The test inputs the username and password into the login panel, then clicks the login button. After the main view is loaded, it logs off.
For some reason, this test never finishes.
Every action in the chain is successful, but the test is still stuck running.
How can I fix this?
I am using siesta-3.0.2-lite with ExtJS 5.1.0.
1# First you can try to remove t.done() , it's not generally needed in the tests, unless you are really waiting for it. needDone in the harness settings has default value False.
2# You are using waitForEvent, this is usually done when you pass the callback there. So your function would look like this:
function(next) {
t.waitForEvent(Ext.globalEvents, 'logoutComplete', next);
},
But if you just want to know that the event was fired, you can use function firesOnce . Don't forget that you need to register checking the event before executing the actions which triggers it.
So your code could look like this:
function(next) {
t.firesOnce(Ext.globalEvents, 'logoutComplete','Logout completed!');
next();
},
{ click: '>> #logoutButton' },
{ waitForCQ: 'messagebox #ok' },
{ click : '>> messagebox #ok' },
But I have never used Ext.globalEvents to check the events, so I am not sure if it works.
Siesta developers on the forum suggested to solve this by setting overrideSetTimeout to false in your harness config.
Harness.configure({
...
overrideSetTimeout: false,
...
});
Siesta overrides the native "setTimeout" from the context of each test for asynchronous code tracking, but it seems to cause issues.
It worked for many users on the forum, tell me if it works for you, because it did not solve my issues.
Update:
The problem on my side turned out to be due to the logout itself, which uses window.location.reload(). This makes the browser act if there are two separate pages/applications.
Apparently, you need to set separateContext option in harness object to true. This option is available only in Standard (Commercial) package.

Meteor Iron Router, Pub Sub causing weird behavior

I am trying to make sing post page a route where it does a several things using iron:router
Uses the template postPage
Subscribes to publication of singlePost, userStatus (shows status and info of Author of single post page'), comments .
Grabs Comments documents that has field of postId : this.params._id
Increments Comments List by Session.get('commentLimit')
Here is the code I currently have.
Router.js
Router.route('/posts/:_id', {
name: 'postPage',
subscriptions: function() {
return [
Meteor.subscribe('singlePost', this.params._id),
Meteor.subscribe('userStatus'),
Meteor.subscribe('comments', {
limit: Number(Session.get('commentLimit'))
})
];
},
data: function() {
return Posts.findOne({_id:this.params._id});
},
});
Publications.js
Meteor.publish('singlePost', function(id) {
check(id, String);
return Posts.find(id);
});
Meteor.publish('comments', function(options) {
check(options, {
limit: Number
});
return Comments.find({}, options);
});
Template.postPage.onCreated
Template.onCreated( function () {
Session.set('commentLimit', 4);
});
Template.postPage.helpers
Template.postPage.helpers({
comments: function () {
var commentCursor = Number(Session.get('commentLimit'));
return Comments.find({postId: this._id}, {limit: commentCursor});
},
});
Template.postPage.events
Template.postPage.events({
'click a.load-more-comments': function (event) {
event.preventDefault();
Session.set('commentLimit', Number(Session.get('commentLimit')) + 4)
}
});
Everything works fine, but I found one thing to be inconsistent.
Here is the problem I am having...
User goes into single post page and adds comment (everything works fine).
User goes into a different single post page and adds comment (everything works fine).
Here is where the problem begins
The user at any time, goes into another route that is not the single post page.
User goes back into single post page
The comments are not showing.
New comments will be added into DB but still wont show
This problem only goes away when meteor reset or manual deletion of all comments in MongoDB is performed.
Is there a better way that I can code my routing and related code to stop this weird behavior from happening?
Or even if there is a better practice.
Your publish is publishing comments without any postId filter.
Your helper, filters by postId. Maybe the 4 comments that get published are the ones that do not belong to the current post that is open?
Could you try updating, your subscription to
Meteor.subscribe('comments', {
postId: this.params._id
}, {
limit: Number(Session.get('commentLimit'))
})
and your publication to
Meteor.publish('comments', function(filter, options) {
check(filter, {
postId: String
});
check(options, {
limit: Number
});
return Comments.find(filter, options);
});
so that only the same posts' comments are published?
I have figured it out. I have updated the following codes.
So far it is not showing weird behavior...
Publications.js
Meteor.publish('comments', function(postId, limit) {
check(postId, String);
check(limit, Number);
return Comments.find({postId:postId}, {limit:limit});
});
Router.js
Router.route('/posts/:_id', {
name: 'postPage',
subscriptions: function () {
return [
Meteor.subscribe('singlePost', this.params._id),
Meteor.subscribe('userStatus'),
Meteor.subscribe('comments', this.params._id, Number(Session.get('commentLimit')))
];
},
data: function() {
return Posts.findOne({_id:this.params._id});
},
});

Meteor - How to find out if Meteor.user() can be used without raising an error?

I'm looking for a way to determine if Meteor.user() is set in a function that can be called both from the server and client side, without raising an error when it is not.
In my specific case I use Meteor server's startup function to create some dummy data if none is set. Furthermore I use the Collection2-package's autoValue -functions to create some default attributes based on the currently logged in user's profile, if they are available.
So I have this in server-only code:
Meteor.startup(function() {
if (Tags.find().fetch().length === 0) {
Tags.insert({name: "Default tag"});
}
});
And in Tags-collection's schema:
creatorName: {
type: String,
optional: true,
autoValue: function() {
if (Meteor.user() && Meteor.user().profile.name)
return Meteor.user().profile.name;
return undefined;
}
}
Now when starting the server, if no tags exist, an error is thrown: Meteor.userId can only be invoked in method calls. Use this.userId in publish functions.
So in other words calling Meteor.user() on the server startup throws an error instead of returning undefined or null or something. Is there a way to determine whether it will do so prior to calling it?
I cannot solve this simply by wrapping the call with if (Meteor.isServer) within the autoValue function, as the autoValue functions are normally called from server side even when invoked by the user, and in these cases everything in my code works fine.
Note that this is related to How to get Meteor.user() to return on the server side?, but that does not address checking if Meteor.user() is available in cases where calling it might or might not result in an error.
On the server, Meteor.users can only be invoked within the context of a method. So it makes sense that it won't work in Meteor.startup. The warning message is, unfortunately, not very helpful. You have two options:
try/catch
You can modify your autoValue to catch the error if it's called from the wrong context:
autoValue: function() {
try {
var name = Meteor.user().profile.name;
return name;
} catch (_error) {
return undefined;
}
}
I suppose this makes sense if undefined is an acceptable name in your dummy data.
Skip generating automatic values
Because you know this autoValue will always fail (and even if it didn't, it won't add a useful value), you could skip generating automatic values for those inserts. If you need a real name for the creator, you could pick a random value from your existing database (assuming you had already populated some users).
Been stuck with this for two days, this is what finally got mine working:
Solution: Use a server-side session to get the userId to prevent
"Meteor.userId can only be invoked in method calls. Use this.userId in publish functions."
error since using this.userId returns null.
lib/schemas/schema_doc.js
//automatically appended to other schemas to prevent repetition
Schemas.Doc = new SimpleSchema({
createdBy: {
type: String,
autoValue: function () {
var userId = '';
try {
userId = Meteor.userId();
} catch (error) {
if (is.existy(ServerSession.get('documentOwner'))) {
userId = ServerSession.get('documentOwner');
} else {
userId = 'undefined';
}
}
if (this.isInsert) {
return userId;
} else if (this.isUpsert) {
return {$setOnInsert: userId};
} else {
this.unset();
}
},
denyUpdate: true
},
// Force value to be current date (on server) upon insert
// and prevent updates thereafter.
createdAt: {
type: Date,
autoValue: function () {
if (this.isInsert) {
return new Date;
} else if (this.isUpsert) {
return {$setOnInsert: new Date};
} else {
this.unset();
}
},
denyUpdate: true
},
//other fields here...
});
server/methods.js
Meteor.methods({
createPlant: function () {
ServerSession.set('documentOwner', documentOwner);
var insertFieldOptions = {
'name' : name,
'type' : type
};
Plants.insert(insertFieldOptions);
},
//other methods here...
});
Note that I'm using the ff:
https://github.com/matteodem/meteor-server-session/ (for
ServerSession)
http://arasatasaygin.github.io/is.js/ (for is.existy)

jquery.couchdb.js Ajax success/error not being called

I'm using jquery.couchdb.js to query my CouchDB database. The view I want to query has both map and reduce functions within. When sending the basic query as shown below:
$(document).ready(function() {
view_name = db_name+'/jobs_by_mod_stat'
options = {'group': 'true' , 'reduce': 'true' };
mod_stat = {};
$db.view(view_name , {
success: function(data) {
console.log(data)
for (i in data.rows) {
console.log(data.rows[i].value);
}
},
error: function(e) {
alert('Error loading from database: ' + e);
}
});
});
I see a sensible log for the data, indicating the query has been successful. However, changing the line:
$db.view(view_name , {
To
$db.view(view_name , options, {
I don't get a success outcome from the Ajax query, but an error message is not shown either. Firebug shows the query being sent, and the JSON data returned looks sensible:
{"rows":[
{"key":["template","completed"],"value":2},
{"key":["template","running"],"value":2},
{"key":["template","waiting"],"value":6}
]}
But the success function is not entered. Any ideas why I'm seeing this behaviour, I did wonder if it's a bug in jquery.couch.js (I have couchdb 1.1.0).
Cheers.
I've had a bit of trouble myself with the list function, until I went and looked through the source code of jquery.couch.js (the online documentation I found at http://bradley-holt.com/2011/07/couchdb-jquery-plugin-reference/ seems to be outdated).
Basically, the parameters for view and list are different, the list having an extra parameter for the options, instead of having everything under the same parameter as with views.
View:
$.couch.db('yourdb').view('couchapp/' + viewName, {
keys: ['keys here'],
success: function (data) {
}
});
List:
$.couch.db('yourdb').list('couchapp/' + listName, viewName, {
keys: ['keys here']
}, {
success: function (data) {
}
});

Categories