Related
When user refresh a certain page, I want to set some initial values from the mongoDB database.
I tried using the onRendered method, which in the documentation states will run when the template that it is run on is inserted into the DOM. However, the database is not available at that instance?
When I try to access the database from the function:
Template.scienceMC.onRendered(function() {
var currentRad = radiationCollection.find().fetch()[0].rad;
}
I get the following error messages:
Exception from Tracker afterFlush function:
TypeError: Cannot read property 'rad' of undefined
However, when I run the line radiationCollection.find().fetch()[0].rad; in the console I can access the value?
How can I make sure that the copy of the mongoDB is available?
The best way for me was to use the waitOn function in the router. Thanks to #David Weldon for the tip.
Router.route('/templateName', {
waitOn: function () {
return Meteor.subscribe('collectionName');
},
action: function () {
// render all templates and regions for this route
this.render();
}
});
You need to setup a proper publication (it seems you did) and subscribe in the route parameters. If you want to make sure that you effectively have your data in the onRendered function, you need to add an extra step.
Here is an example of how to make it in your route definition:
this.templateController = RouteController.extend({
template: "YourTemplate",
action: function() {
if(this.isReady()) { this.render(); } else { this.render("yourTemplate"); this.render("loading");}
/*ACTION_FUNCTION*/
},
isReady: function() {
var subs = [
Meteor.subscribe("yoursubscription1"),
Meteor.subscribe("yoursubscription2")
];
var ready = true;
_.each(subs, function(sub) {
if(!sub.ready())
ready = false;
});
return ready;
},
data: function() {
return {
params: this.params || {}, //if you have params
yourData: radiationCollection.find()
};
}
});
In this example you get,in the onRendered function, your data both using this.data.yourData or radiationCollection.find()
EDIT: as #David Weldon stated in comment, you could also use an easier alternative: waitOn
I can't see your collection, so I can't guarantee that rad is a key in your collection, that said I believe your problem is that you collection isn't available yet. As #David Weldon says, you need to guard or wait on your subscription to be available (remember it has to load).
What I do in ironrouter is this:
data:function(){
var currentRad = radiationCollection.find().fetch()[0].rad;
if (typeof currentRad != 'undefined') {
// if typeof currentRad is not undefined
return currentRad;
}
}
I'm creating a backbone app that's connecting to a RESTful backend. When I call save() on a model, it sends the post data as stringified JSON:
{"firstName":"first","lastName":"last","Email":"email#gmail.com"}
but my server expects it to be formatted like a querystring:
firstName=first&lastName=last&Email=email#gmail.com
is there a way to have backbone send it differently?
Backbone doesn't provide anything like this out of the box.
But is easy to override and customize it to your needs.
Have a look to the source code:
http://documentcloud.github.com/backbone/docs/backbone.html
and check out that calling save, it will trigger a sync call in the background.
So what you need is to override Backbone.sync function with your own.
I would modify the part of:
if (!options.data && model && (method == 'create' || method == 'update')) {
params.contentType = 'application/json';
params.data = JSON.stringify(model.toJSON());
}
with
if (!options.data && model && (method == 'create' || method == 'update')) {
params.contentType = 'application/json';
params.data = $.param(model); // <-- CHANGED
}
Notice I'm using jQuery param
If you want to use a custom function, check this question:
Query-string encoding of a Javascript Object
[Update.]
No need to modify directly. Better override it with your own function 'Backbone.sync'
Check the "TODO" example of the Backbone repository. It has a localStorage.js file that overrides Backbone.sync function https://github.com/documentcloud/backbone/tree/master/examples
I ran into this problem at work and the Backbone.emulateJSON didn't work for me either. With some help I was able to come up with this workaround. We overrode the Backbone.ajax function and changed the contentType to "application/x-www-form-urlencoded" and used $.param to properly serialize the data.
Backbone.ajax = function() {
if(arguments[0].data && arguments[0].contentType == "application/json"){
arguments[0].data = $.param(JSON.parse(arguments[0].data));
arguments[0].contentType = "application/x-www-form-urlencoded";
}
return Backbone.$.ajax.apply(Backbone.$, arguments);
}
maybe this can help you,try:
http://backbonejs.org/#Sync-emulateJSON
I have done this by overriding model's sync function:
var MyModel = Backbone.Model.extend({
"sync": function(method, model, options) {
if (method == "update" || method == "create") {
options = options ? _.clone(options) : {};
options['data'] = $.param(this['attributes']);
}
var arguments = [method, model, options];
return Backbone.sync.apply(this, arguments);
}
});
I find solutions, see :
I use
Backbone.emulateJSON = true;
I write the "update" case:
options.url = "/user/"+Math.random(1, 1000);
options.type = "POST";
//.1/2 WORK
//options.data = (model instanceof Backbone.Model)?model.toJSON():{};
options.data = model.toJSON();
break;
Backbone.sync uses the jQuery.ajax function, so we can modify the jqXHR or data that is sended to the server (via beforeSend).
var oldSync = Backbone.Model.prototype.sync;
var SomeModel = Backbone.Model.extend({
url: 'test.json',
defaults: {
id: 1,
foo: 'test'
},
sync: function (method, model, options) {
// options are passed to the jQuery.ajax
_.extend(options, {
emulateHTTP: true,
emulateJSON: false,
beforeSend: function(xhr, settings) {
// settings.data is a body of our request.
if (_.isString(settings.data)) {
// settings.data is a JSON-string like '{"id":1, "foo":"test"}'
settings.data = Backbone.$.parseJSON(settings.data);
}
settings.data = Backbone.$.param(settings.data);
// settings.data is 'id=1&foo=test'
}
});
oldSync.apply(this, arguments);
}
});
var model = new SomeModel();
model.save();
Actually we can create a mixin! :)
I've tried to understand this post regarding this concept, however, I'm failing to get it. I have the following simple setup:
/server/test.js
Meteor.methods({
abc: function() {
var result = {};
result.foo = "Hello ";
result.bar = "World!";
return result;
}
});
/client/myapp.js
var q = Meteor.call('abc');
console.log(q);
This structure returns to the console undefined.
If I change the myapp.js file to:
Meteor.call('abc', function(err, data) {
!err ? console.log(data) : console.log(err);
}
I receive the Object in my console.
Ideally this is what I'd like to be able to do, but it doesn't work, stating in the console: Cannot read property 'greeting' of undefined
/client/myapp.js
var q = Meteor.call('abc');
Template.hello.greeting = function() {
return q.foo;
}
Any help in passing the data from the server object into the template would be greatly appreciated. I'm still learning JavaScript & Meteor.
Thanks!
From the Meteor.call documentation:
On the client, if you do not pass a callback and you are not inside a stub, call will return undefined, and you will have no way to get the return value of the method. That is because the client doesn't have fibers, so there is not actually any way it can block on the remote execution of a method.
So, you'll want to do it like this:
Meteor.call('abc', function(err, data) {
if (err)
console.log(err);
Session.set('q', data);
});
Template.hello.greeting = function() {
return Session.get('q').foo;
};
This will reactively update the template once the data is available.
This happens because Npm.require has Async behavior. That's the reason that you have to write a callback for Meteor.call.
But there is a solution, just use install(mrt add npm) and you'll get a function named Meteor.sync(//...) with this you can do both games: sync and async in your Meteor.call().
Reference: http://www.sitepoint.com/create-a-meteor-app-using-npm-module/
You can get the return value of a Meteor method for use in a template by using a reactive variable. Check out the working demonstration on Meteorpad
I went for a ghetto solution. But, it works for me, which is what matters, to me. Below is my code, which, in concept, I think, solves OP's problem.
In the client's main.js:
Meteor.setInterval(function() {
confirmLogin();
}, 5000);
This runs the confirmLogin() function every five seconds.
The confirmLogin function (in the client's main.js):
function confirmLogin() {
Meteor.call('loggedIn', function (error, result) {
Session.set("loggedIn", result);
});
}
The loggedIn method (in the server's main.js):
loggedIn: function () {
var toReturn = false;
var userDetails = Meteor.user();
if (typeof userDetails["services"] !== "undefined") {
if (typeof userDetails["services"]["facebook"] != "undefined") {
toReturn = true;
}
}
return toReturn;
},
The relevant helper:
loggedIn: function () {
return Session.get("loggedIn");
}
lets say I have a Backbone Model and I create an instance of a model like this:
var User = Backbone.Model.extend({ ... });
var John = new User({ name : 'John', age : 33 });
I wonder if it is possible when I use John.save() to target /user/create when I use John.save() on second time (update/PUT) to target /user/update when I use John.fetch() to target /user/get and when I use John.remove() to target /user/remove
I know that I could define John.url each time before I trigger any method but I'm wondering if it could be happen automatically some how without overriding any Backbone method.
I know that I could use one url like /user/handle and handle the request based on request method (GET/POST/PUT/DELETE) but I'm just wondering if there is a way to have different url per action in Backbone.
Thanks!
Methods .fetch(), .save() and .destroy() on Backbone.Model are checking if the model has .sync() defined and if yes it will get called otherwise Backbone.sync() will get called (see the last lines of the linked source code).
So one of the solutions is to implement .sync() method.
Example:
var User = Backbone.Model.extend({
// ...
methodToURL: {
'read': '/user/get',
'create': '/user/create',
'update': '/user/update',
'delete': '/user/remove'
},
sync: function(method, model, options) {
options = options || {};
options.url = model.methodToURL[method.toLowerCase()];
return Backbone.sync.apply(this, arguments);
}
}
To abstract dzejkej's solution one level further, you might wrap the Backbone.sync function to query the model for method-specific URLs.
function setDefaultUrlOptionByMethod(syncFunc)
return function sync (method, model, options) {
options = options || {};
if (!options.url)
options.url = _.result(model, method + 'Url'); // Let Backbone.sync handle model.url fallback value
return syncFunc.call(this, method, model, options);
}
}
Then you could define the model with:
var User = Backbone.Model.extend({
sync: setDefaultUrlOptionByMethod(Backbone.sync),
readUrl: '/user/get',
createUrl: '/user/create',
updateUrl: '/user/update',
deleteUrl: '/user/delete'
});
Are you dealing with a REST implementation that isn't to spec or needs some kind of workaround?
Instead, consider using the emulateHTTP option found here:
http://documentcloud.github.com/backbone/#Sync
Otherwise, you'll probably just need to override the default Backbone.sync method and you'll be good to go if you want to get real crazy with that... but I don't suggest that. It'd be best to just use a true RESTful interface.
No you can't do this by default with backbone. What you could to is to add to the model that will change the model url on every event the model trigger. But then you have always the problem that bckbone will use POST add the first time the model was saved and PUT for every call afterward. So you need to override the save() method or Backbone.sync as well.
After all it seems not a good idea to do this cause it break the REST pattern Backbone is build on.
I got inspired by this solution, where you just create your own ajax call for the methods that are not for fetching the model. Here is a trimmed down version of it:
var Backbone = require("backbone");
var $ = require("jquery");
var _ = require("underscore");
function _request(url, method, data, callback) {
$.ajax({
url: url,
contentType: "application/json",
dataType: "json",
type: method,
data: JSON.stringify( data ),
success: function (response) {
if ( !response.error ) {
if ( callback && _.isFunction(callback.success) ) {
callback.success(response);
}
} else {
if ( callback && _.isFunction(callback.error) ) {
callback.error(response);
}
}
},
error: function(mod, response){
if ( callback && _.isFunction(callback.error) ) {
callback.error(response);
}
}
});
}
var User = Backbone.Model.extend({
initialize: function() {
_.bindAll(this, "login", "logout", "signup");
},
login: function (data, callback) {
_request("api/auth/login", "POST", data, callback);
},
logout: function (callback) {
if (this.isLoggedIn()) {
_request("api/auth/logout", "GET", null, callback);
}
},
signup: function (data, callback) {
_request(url, "POST", data, callback);
},
url: "api/auth/user"
});
module.exports = User;
And then you can use it like this:
var user = new User();
// user signup
user.signup(data, {
success: function (response) {
// signup success
}
});
// user login
user.login(data, {
success: function (response) {
// login success
}
});
// user logout
user.login({
success: function (response) {
// logout success
}
});
// fetch user details
user.fetch({
success: function () {
// logged in, go to home
window.location.hash = "";
},
error: function () {
// logged out, go to signin
window.location.hash = "signin";
}
});
I'm trying to execute a stored function from mongodb-native/node.js environment.
I have several functions inside db.system.js.
It seems Db.executeCommand() is the function but I have no idea how can I pass the function name and the arguments.
I tried db.eval() as suggested but I got the following.
> db.eval('getValue()', {}, function(er,doc) {console.log(er);console.log(doc);});
{ stack: [Getter/Setter], arguments: [ 'send', undefined ], type: 'non_object_property_call', message: [Getter/Setter] }
null
getValue is a simple function that returns an integer.
Anyone has an idea? Thanks.
Assuming db is your open database handler:
db.eval("myFunction(param, param_n)", function(error, result) { });
Looks like you can pass the parameters in separately, too. https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/db.js
There you go:
function testDB(req,res) {
MongoClient.connect(url, function(err, db) {
if (err) {
console.log(err);
res.send('connection failed');
} else {
db.eval("testFunction()", function(err, output) {
if(err){
console.log("ERROR: "+err);
res.send(err);
return;
}else{
res.send(output);
return;
}
});
db.close();
}
});
}
I am assuming that you call it for a rest API.
You can change the function params based on your need.
Also I assume your URL has enough permissions to call the function.
If not, use a mongo tool like RoboMongo and change the permission to the user.
It's because you are thinking it will return value , This is asynchronous call , you must pass a callback function with (err,doc) to get the return value
db.eval('addNumbers(4,5)',function(er,doc){
console.log(doc);
})