this is a two part question from a JS newbie.
So, I was trying to create a backbone application using requireJS by following Thomas Davis's tutorial.
How do I go create Backbone collections out of an ajax call to a server that provides data in XML? collections.fetch() seem to be expecting a JSON backend.
while trying some things, I ended up with the following code, in which the page doesn't refresh upon populating the collection "bookStore" from within Ajax success-callback.
Here is how far I have gotten so far.
var bookListView = Backbone.View.extend({
el: $("#books"),
initialize: function () {
thisView = this;
$.ajax({
type: "GET",
url: "books.xml",
dataType: "xml",
success: function (data) {
console.log(data);
$(data).find('book').each(function (index) {
var bookTitle = $(this).find('name').text();
bookStore.add({ title: bookTitle });
console.log(seid);
});
thisView.collection = bookStore;
thisView.collection.bind('add', thisView.tryBind);
}
}).done(function (msg) {
alert("Data retrieved: " + msg);
});
this.collection = bookStore;
this.collection.bind("add", this.exampleBind);
this.collection.bind("refresh", function () { thisView.render(); });
/*
// This one works!
bookStore.add({ name: "book1" });
bookStore.add({ name: "book2" });
bookStore.add({ name: "book3" });
*/
},
tryBind: function (model) {
console.log(model);
},
render: function () {
var data = {
books: this.collection.models,
};
var compiledTemplate = _.template(bookListTemplate, data);
$("#books").html(compiledTemplate);
}
});
Here, the success call-back in the "initialize" function seems to be processing the data properly and adding to the collection. However, the page doesn't refreshed.
While I was stepping through the Firebug console, the page gets refreshed however. How do I solve this problem?
You can override the default parse function to provide XML support. It should return the data transformed into JSON http://backbonejs.org/#Collection-parse
Bind the render to a reset event instead of refresh for Backbone<1.0 or to a sync event for Backbone>=1.0
It could look like this
var Book = Backbone.Model.extend();
var Books = Backbone.Collection.extend({
model: Book,
url: "books.xml",
parse: function (data) {
var $xml = $(data);
return $xml.find('book').map(function () {
var bookTitle = $(this).find('name').text();
return {title: bookTitle};
}).get();
},
fetch: function (options) {
options = options || {};
options.dataType = "xml";
return Backbone.Collection.prototype.fetch.call(this, options);
}
});
var bookListView = Backbone.View.extend({
initialize: function () {
this.listenTo(this.collection, "sync", this.render);
},
render: function () {
console.log(this.collection.toJSON());
}
});
var bks = new Books();
new bookListView({collection: bks});
bks.fetch();
And a demo http://jsfiddle.net/ULK7q/73/
Related
I use backbone to fetch restful api.
Switch collection and fetch data is not work.
I have a view with two collections(as below), while View detect the change change trigger switchModel.
I use console.log display. that.collection.fetch don't run successfully or error. My server show 500 Internet Server error. I don't know how to fix it... can anyone help me thx.
view
var view = Backbone.View.extend({
initialize: function() {
this.A_info = ACollection;
this.B_info = BCollection;
*//I do not bind any collection in thi function.*
},
events: {
"change #some_name": "switchModel"
},
switchModel: function(ev) {
var that = this;
var data = {};
if(that.VENDOR_TYPE==that.A_TYPE){
that.collection = that.A_info;
}
else{
that.collection = that.B_info;
}
that.collection.reset();
that.collection.fetch({
type: 'GET',
dataType: "json",
data: data,
success: function() {
var _parent = that;
_parent.filter();
//console.log("successfully!!");
}
error{
//console.log("error!!");
}
return view;
});
ACollection
var collection = Backbone.Collection.extend({
url: function() {
return "/api/a_info"
},
},
model: AInfoModel
});
return new collection();
});
BCollection
var collection = Backbone.Collection.extend({
url: function() {
return "/api/b_info"
},
},
model: BInfoModel
});
return new collection();
});
{model : {"firstName":"David","lastName":"Bawa","state":"AL"}}
{"allStates":[{"id":1,"value":"AL","text":"ALABAMA"},{"id":2,"value":"AK","text":"ALASKA"}}
<select name="state" data-bind="options: allStates,optionsValue : 'value', optionsText: 'text' ,value: model.state,optionsCaption: 'Choose...'" id="ddlState"></select>
var registrationModel = {
staticData: function () {
var self = this;
self.allStates = ko.observableArray();
self.hearUsAll = ko.observableArray();
registrationService.getAllStates().done(function (result) {
if (result != null) {
$.each(result.List, function (i, v) {
self.allStates.push(v);
});
}
});
}
}
and my registration service is
var registrationService = {
getAllStates: function () {
return service.staticService.get('GetAllStates');
}}
and my static service is
var service={
staticService: {
get: function (method) {
var results = store.fetch(method);
if (results) {
var dfd = new $.Deferred();
dfd.resolve(results);
return dfd.promise();
}
return $.ajax({
type: 'GET',
url: "http://xxxx/Service1.svc/" + method,
dataType: "json",
success: function (result) { if (result) { store.save(method,result) } }
}).promise();
}
states are populating from server through ajax, it works fine if I wait for allstates to be fetched and then apply bindings.
as you can see I am getting a pre-selected value of state in model. But when I do not wait for states to be populated and call apply bindings it will not work. it changes my state variable to null. I am getting my view model from mapping plugin.
Please help.
I have a site developed in cakephp where I'm using a simple app in backbone.
Now I would like to save data from backbone but doesn't work, return always inside callback error, and it doens't take the right value to save inside table.
This is my simple app:
TaskModel = Backbone.Model.extend({
url: function(){
return "/step_task/ajax_save";
}
});
TaskCollection = Backbone.Collection.extend({
model: TaskModel,
initData: function(data){
return data;
}
});
var TaskView = Backbone.View.extend({
template: _.template($("#task-template").html()),
initialize: function(){
this.task = new TaskCollection(<?php echo json_encode($step['StepTask']); ?>);
this.render();
},
render: function(){
taskModel = new TaskModel({
'id': '1',
'user_id': '1'
});
//--------------------------- here I would like to save inside my table ----------------
taskModel.save(null, {
success: function(model, response) {
console.log('success');
console.log(model);
console.log(response);
},
error: function(model, response) {
console.log('error');
console.log(model);
console.log(response);
},
wait: true // Add this
});
$(this.el).html(this.template({tasks: this.task.models}));
}
});
and this is my funciton inside StepTaskController.php
public function ajax_save(){
$this->autoRender = false;
$this->StepTask->save($this->request->data);
}
How can I solve it?
Try to change the url in your model to urlRoot :
TaskModel = Backbone.Model.extend({
urlRoot: '/step_task/ajax_save'
});
I need to find a way to fetch a Youtube JSON url and print the titles and descriptions. The code I have here succeeds when I try to fetch, but the array it receives is empty when I try to see it in console.
Do you know why this may happen?
You can find the code here:
http://jsfiddle.net/BHrmC/73/
var Item = Backbone.Model.extend();
var List = Backbone.Collection.extend({
model: Item,
url: "https://gdata.youtube.com/feeds/api/playlists/67DEB98D8D9CF0F7?v=2&alt=json-in-script&max-results=6",
parse: function(response) {
return response.results;
},
sync: function(method, model, options) {
var that = this;
var params = _.extend({
type: 'GET',
dataType: 'jsonp',
url: that.url,
processData: false
}, options);
return $.ajax(params);
}
});
var ListView = Backbone.View.extend({
el: $('#test'),
events: {
'click button#add': 'getPost'
},
initialize: function() {
_.bindAll(this, 'render', 'getPost');
this.collection = new List();
this.render();
},
render: function() {
var self = this;
$(this.el).append("<button id='add'>get</button>");
},
getPost: function() {
var that = this;
this.collection.fetch({
success: function(response) {
console.log(that.collection.toJSON());
console.log("working");
},
error: function() {
console.log('Failed to fetch!');
}
});
}
});
// **listView instance**: Instantiate main app view.
var listView = new ListView();
Make up your mind on the data representation you want to use. The code shown here uses an XML to JSON conversion (alt=json-in-script) while the URL in you Fiddle points to a much simpler representation, a JSON-C feed (alt=jsonc). See https://developers.google.com/youtube/2.0/developers_guide_jsonc#Comparing_JSON_and_JSONC for more info.
Assuming you meant to use a JSON-C representation, the items definitions are under data.items
parse: function(response) {
return response.data.items;
}
The video data for each object is under a video attribute. Assuming you want your Item instances to directly reflect the videos, you will have to unwrap them with _.pluck for example:
parse: function(response) {
var items = response.data.items;
return _.pluck(items, 'video');
}
And an updated Fiddle http://jsfiddle.net/BHrmC/80/
I have been using knockout.js for a while now, and haven't encountered this problem before. Usually, when I try to push a new js object to an observableArray, it works without an issue, but for some reason, this time around I'm getting this error:
TypeError: self.Students.push is not a function
Here is a snippet of my code:
window.ApiClient = {
ServiceUrl: "/api/students",
Start: function () {
var viewModel = ApiClient.ViewModel(ngon.ClientViewModel);
ko.applyBindings(viewModel);
viewModel.get();
}
};
ApiClient.ViewModel = function(data) {
var self = this;
ko.mapping.fromJS(data, {}, this);
this.get = function (id) {
if (id == undefined) {
return ApiClient.Service.get(self.PageSize(), self.PageNumber(), function (data) {
self.Students(data);
});
}
}
this.post = function () {
return ApiClient.Service.post(self.DetailedStudent, function (data) {
self.Students.push(data);
});
}
return this;
}
ApiClient.Service = function () {
var _get = function (pageSize, pageNumber, callback) {
sv.shouldShowLoading = false;
var queryParams = String.format("?pageSize={0}&pageNumber={1}", pageSize, pageNumber);
$.ajax(ApiClient.ServiceUrl + queryParams, {
dataType: "json",
type: "get",
success: callback
});
}
var _post = function (student, callback) {
$.ajax(ApiClient.ServiceUrl, {
data: ko.mapping.toJSON(student),
type: "post",
contentType: "application/json; charset-utf-8",
statusCode: {
201 /*Created*/: callback,
400 /*BadRequest*/: function (jqxhr) {
var validationResult = $.parseJSON(jqxhr.responseText);
alert(jqxhr.responseText);
}
}
});
}
return {
get: _get,
post: _post
};
}();
$(document).ready(function () {
ApiClient.Start();
});
My student object is a very simple C# object that has Id, FirstName, LastName. The get() function works without any issues, it's just the callback function from the post() that cannot push the resulting data. Also, the data being returned back from the server looks correct:
{"Id":"rea","FirstName":"asdf","MiddleName":null,"LastName":"rrr"}
I solved this! It's because the initial viewModel, when being instantiated by the page's view model object had 'null' for its Students property.
knockout.js requires non-null values for all fields that are to be auto mapped.