I am using a Model like this:
var SidebarCategory = Backbone.Model.extend({
urlRoot: 'sidebar',
defaults : {
title : '',
items: ''
}
});
And fetching this JSON via GET:
{"id":"foo","title":"TITLE","items":"bar baz"}
But the Model itself does not take the incoming data.
var foo = new SidebarCategory({id: 'foo'});
foo.fetch();
console.log(foo.toJSON());
Just taking the id and ignore the rest.
Did I miss something?
What could be the problem?
As #CD pointed it out , the fetch is asynchronous so you have 2 options for a call back like this :
foo.fetch({
success : function(data){
console.log(JSON.stringify(data));
}
});
OR
foo.fetch();
foo.on('reset',function(data){
console.log(JSON.stringify(data));
},this);
You could use either one of the above to deal with the asynchronous call.
fetch performs an asynchronous HTTP (Ajax) request, so you should pass fetch a success callback:
foo.fetch({
success: function(){
console.log(foo.toJSON());
}
});
Related
I've been trying to make a request to a NodeJS API. For the client, I am using the Mithril framework. I used their first example to make the request and obtain data:
var Model = {
getAll: function() {
return m.request({method: "GET", url: "http://localhost:3000/store/all"});
}
};
var Component = {
controller: function() {
var stores = Model.getAll();
alert(stores); // The alert box shows exactly this: function (){return arguments.length&&(a=arguments[0]),a}
alert(stores()); // Alert box: undefined
},
view: function(controller) {
...
}
};
After running this I noticed through Chrome Developer Tools that the API is responding correctly with the following:
[{"name":"Mike"},{"name":"Zeza"}]
I can't find a way to obtain this data into the controller. They mentioned that using this method, the var may hold undefined until the request is completed, so I followed the next example by adding:
var stores = m.prop([]);
Before the model and changing the request to:
return m.request({method: "GET", url: "http://localhost:3000/store/all"}).then(stores);
I might be doing something wrong because I get the same result.
The objective is to get the data from the response and send it to the view to iterate.
Explanation:
m.request is a function, m.request.then() too, that is why "store" value is:
"function (){return arguments.length&&(a=arguments[0]),a}"
"stores()" is undefined, because you do an async ajax request, so you cannot get the result immediately, need to wait a bit. If you try to run "stores()" after some delay, your data will be there. That is why you basically need promises("then" feature). Function that is passed as a parameter of "then(param)" is executed when response is ready.
Working sample:
You can start playing with this sample, and implement what you need:
var Model = {
getAll: function() {
return m.request({method: "GET", url: "http://www.w3schools.com/angular/customers.php"});
}
};
var Component = {
controller: function() {
var records = Model.getAll();
return {
records: records
}
},
view: function(ctrl) {
return m("div", [
ctrl.records().records.map(function(record) {
return m("div", record.Name);
})
]);
}
};
m.mount(document.body, Component);
If you have more questions, feel free to ask here.
I simply want a single $.get call to satisfy a particular model. I can't seem to find any documentation that clearly shows how to go about doing this?
i.e. I have an application controller as:
App.ApplicationController = Ember.ObjectController.extend({
username: '',
firstname: '',
lastname: ''
});
How do I set the username with data from a $.get? I know there is Ember Data and other libraries that do this, but I'd like to do this without those libraries and furthermore better understand how Ember works with Asynchronous data.. Their guides unfortunately didn't help much :/
Thanks for any help :)
UPDATE
Thanks guys for the answers so far, but I don't think I explained my problem sufficiently.
I have application.hbs:
<div class="medium-8 columns">
<dl class="account-menu right">
<dd><p>Welcome, {{username}}</p></dd>
<dd><p>Customer Support</p></dd>
<dd>Log Out</dd>
</dl><!-- .acccount-menu -->
</div>
I have Model:
App.User = Ember.Object.extend({
id : '',
firstName : '',
lastName : '',
username : '',
init: function(){
console.log(App.Account.get('username');
},
fullName: function(){
return this.get('firstName') + ' ' + this.get('lastName');
}.property('firstName', 'lastName'),
}).reopenClass({
loadAccount: function(){
return $.get( "http://localhost:8080", { id: 1, request: "account" }).then(function(response){
App.Account = App.User.create({'username': response.username});
});
}
});
The Controller is the same as above. I am successfully Creating a new App.Account from App.User.create and successfully triggering the App.User abstract class? init method.. Problem is {{username}} never gets updated? I know I'm missing something simple here! Thanks again for all your help
You would set the model of your ApplicationRoute to the JSON you fetch:
App.ApplicationRoute = Ember.Route.extend({
model: function() {
return $.getJSON('your_url_goes_here');
}
})
This way every time the route is entered the model (and thus implicitly the content of your controller) will be set to the JSON returned by your AJAX call.
The model is set with the model hook of the associated route. In your case:
App.ApplicationRoute = Ember.Route.extend({
model: function(){
return $.get.......
}
});
The model hook will accept an asynchronous call, but ember will not continue to render the view until the model hook promise is complete.
Guys thanks so much for your help.. Turns out it was a simple oversight...
I was not returning the Object Model promise 'App.User' that I had created in the loadAccount method, which is called by the ApplicationRouter model hook.
Bad Code
loadAccount: function(){
return $.get( "http://localhost:8080", { id: 1, request: "account" }).then(function(response){
App.Account = App.User.create({'username': response.username});
});
Good Code
loadAccount: function(){
return $.get( "http://localhost:8080", { id: 1, request: "account" }).then(function(response){
return App.User.create({'username': response.username});
});
It makes sense. The $.get method returns a promise to my model that I never delivered on with a return value inside the .then() method
Thank you all for you answers and attention to the matter
Code
MyClass = Backbone.Model.extend({
url: '/apiurl/'+sessionValue+'',
defaults: {
data1: '',
data2: 1
}
});
var myobj = new MyClass ();
var myobjvalue = {
data1: "myvalue"
};
myobj.save(myobjvalue , {
success: function (myobj , response) {
alert("success");
},
error : function (myobj , response) {
var data = JSON.stringify(response);
console.log(data);
}
})
in the above code, save function successfully calls the REST api. (200 OK). However even after that it enters in error block.
value printed in console
{"readyState":4,"responseText":"Success","status":200,"statusText":"OK"}
What should I be doing?
===================================
What worked
Instead of string, I had to return actual object as part of REST API. apprently, backbone expects class object along with HTTP status. so responseText contained full myobj.
What worked
Instead of string, I had to return actual object as part of REST API. apprently, backbone expects class object along with HTTP status. so responseText contained full myobj.
Using a backbone collection I am trying to fetch JSON from a page. However browsing to this page does give me a JSON, using the collection.fetch does not.
Looking in Firebug I see a:
"GET http://survey/api/list_surveys 200 OK 4ms"
This text however is in red and the Response tab is empty.
The Model:
var SurveyList = Backbone.Model.extend({
defaults: {
"sid": "",
"title": '',
"surveyUrl": ""
},
initialize: function() {
console.log('MODEL AANGESPROKEN');
}
});
The collection:
var Surveys = Backbone.Collection.extend({
model: BGGZ.SurveyList,
url: 'http://survey/api/list_surveys'
});
The JSON:
[{
"sid":"12345",
"surveyls_title":"test 1",
"survey_url":"http://survey/index.php?newtest=Y&sid=12345"
},
{
"sid":"54321",
"surveyls_title":"Test 2",
"survey_url":"http://survey/index.php?newtest=Y&sid=54321"
}]
Does anyone has a solution?
I already tried a parse in the collection, but this didn't help.
Might this has something to do with json with padding?
If so How can I resolve this?
So I found the solution here.
As this is a remote server I am getting the json from I can use JSONP.
In the collection.fetch() Backbone uses jQuery's $.ajax() method to get the data.
So you can place your $.ajax settings in the fetch:
myCollection = new Surveys();
myCollection.fetch({
dataType: "jsonp",
success: function(data) {
console.log(data);
},
error: function() {
console.log('error');
}
});
Now this will not work if your API doesn't expect a JSONP.
JSONP will give a callback parameter to your API. So did your API call first looked like this:
http://survey/api/list_surveys
with JSONP it will now look like this:
http://survey/api/list_surveys?callback=jQuery12654876544
Your API should not return the standard JSON, because jQuery / backbone is expecting the data in a callback function.
if the JSON first looked like this:
{
"sid":"12345",
"surveyls_title":"test 1",
"survey_url":"http://survey/index.php?newtest=Y&sid=12345"
}
you must now add the API to this callback function:
jQuery12654876544({
"sid":"12345",
"surveyls_title":"test 1",
"survey_url":"http://survey/index.php?newtest=Y&sid=12345"
})
Now you're done.
I have a rails controller which sends a mash-up of models as a global json object. Something like this
{
dogs : { species: {}, ...},
cats : { food: {}, ...},
foxes : { },
...,
...
}
On my client side, I have all these entities neatly segregated out into different backbone models and backbone collections.
On some onchange event, I need to send a mashup of some model attributes back to the server as a HTTP POST request and the server sends a response which again spans values across a few models.
How do I setup Backbone.sync to deal with such an ajax scenario? I do not want to change the rails backend because its quite a steady implementation. Or do I make vanilla $.ajax requests through jQuery in one of my backbone views and handle it in a callback on ajax success/failure?
I think there are a couple of ways to do this via backbone. I think I'd start out with a model to represent the mashup:
var MashupModel = Backbone.Model.extend({
});
Then you can pass in any models like you would normally (or a collection for that matter):
var my_mash = new MashupModel({
dog: dogModel.toJSON(),
cat: catModel.toJSON(),
foxes: foxCollection.toJSON()
});
// do stuff if you need...
Then do what you want when the response comes back like normal:
my_mash.save({}, {
success: function(model, response) {
// do stuff here to put new data into the proper models / collections
},
error: function() { alert("I FAIL!"); }
});
That's all well and good... however, I think it would be better to push the above down into the MashupModel object instead of at the request level. Again, several ways:
var MashupModel = Backbone.Model.extend({
initialize: function(attrs) {
// can't remember the actual code, but something along the lines of:
_.each( attrs.keys, function(key) {
this.set(key, attrs.key.toJSON();
});
},
save: function(attrs, opts) {
var callback = opts.success;
opts.success = function(model, response) {
// do your conversion from json data to models / collections
callback(model, response);
};
// now call 'super'
// (ala: http://documentcloud.github.com/backbone/#Model-extend)
Backbone.Model.prototype.set.call(this, attrs, opts);
}
});
Or you could override toJSON (since backbone calls that to get the attrs ready for ajax):
// class definition like above, no initilize...
...
toJSON: function() {
// again, this is pseudocode-y
var attrs = {};
_.each( this.attributes.keys, function() {
attrs.key = this.attributes.key.toJSON();
});
return attrs;
}
...
// save: would be the same as above, cept you'd be updating the models
// directly through this.get('dogs').whatever...
Now, you can just do:
var my_mash = new MashupModel({
dog: dogModel,
cat: catModel,
foxes: foxCollection
});
// do some stuff...
my_mash.save({}, {
success: function(model, response) {
// now only do stuff specific to this save action, like update some views...
},
error: function() { alert("I FAIL!"); }
it would be possible, but may be difficult to modify backbone.sync to work with this structure. i'd recommend going with plain old jquery $.ajax requests. then on success, pull the info apart and populate your collections.
$.get("/whatever", function(data){
catCollection.reset(data.cats);
dogCollection.reset(data.dogs);
// etc
});
data = {};
data.cats = catCollection.toJSON();
data.dogs = dogCollection.toJSON();
// etc
$.post("/whatever", data);