Pass attributes or options to backbone model - backbone.js

I'm not getting any attributes or options in model. I need to pass a route number to it in order to build a url. anyone see what im missing or how I should be doing this? I tried setting the attribute I want on the model but it's not in the model when I try to grab it.
view
define([
'text!html/tplDirection.html',
'models/direction',
'core'
], function (template, Direction) {
return Backbone.View.extend({
el: '',
template: _.template(template),
initialize: function (options) {
this.model = new Direction();
this.model.set({rtnm: options.routeNumber});
console.log(this.model);
},
setup: function (routeNumber) {
var self = this;
// self.model.set({rtnm: routeNumber});
$.when(self.model.fetch())
.done(function () {
console.log(self.model.toJSON());
self.render();
})
.fail(function (response) {
console.log(response);
console.log('request for data has failed');
});
},
render: function () {
var data = {
model: this.model.toJSON()
};
this.$el.html(_.template(template, data));
},
Model
define([
'core'
], function () {
return Backbone.Model.extend({
initialize: function (attributes, options) {
console.log(attributes);
},
/* model: Routes,*/
//url: '/apiproxy.php?method=getdirections&rt=',
parse: function (data) {
var parsed = [];
$(data).find('dir').each(function (index) {
var dir = $(this).find('dir').text();
parsed.push({
dir: dir,
});
});
return parsed;
},
fetch: function (options) {
options = options || {};
options.dataType = "xml";
return Backbone.Model.prototype.fetch.call(this, options);
}
});
});

Solved by passing options to model on instantiating. What confused me is that they come through as attributes and not options in the model. How come?
view:
initialize: function (options) {
this.model = new Direction(options);
},
model:
initialize: function (attributes, options) {
console.log(attributes);
},
url: function () {
//'this' now contains attributes
var route = this.get("routeNumber);
//var route = this.attributes.routeNumber;
return '/apiproxy.php?method=getdirections&rt=' + route;
},

Related

Fetch data did not render in template

This is one of question from a Backbone newbie.
So, I was trying to use this.model.bind and this.model.on('change', this.render), but it could not work for my model. I checked my console & my model function getStoreByName. This is returning an array, but render function is rendering before the fetch array, that's why I want to bind model to view when model change.
Here is how far I have gotten so far.
This is Backbone view:
var storeTemplate = Backbone.View.extend({
initialize: function () {
console.log('view inti is running');
this.template = template;
this.model = new storeModel();
this.model.getStoreByName();
this.stores = this.model.get('stores');
this.model.on('change', this.render);
console.log(this.stores);
console.log('ready to call this.render()');
this.render();
console.log('end to call this.render()');
console.log('view init end');
},
render: function () {
console.log('render is start');
this.logger.log(Logger.LOG_LEVELS.TRACE, "Entering render.");
console.log(this.model.stores);
this.$el.html(_.template(this.template, { stores: this.model.get('stores') }));
return this;
}
});
return storesTemplate;
});
and this is my Backbone Model
var store= Backbone.Model.extend({
initialize: function () {
console.log('init models is running');
this.stores = [];
this.set({ 'stores': this.stores});
console.log(this.get('stores'));
this.service = Service;
},
getStoreByName: function () {
console.log('getting store');
stores = [];
this.service.getStoreByName(function (xml) {
$(xml).find("element").each(
function () {
var store = {
"storeID": $(this).find("ID").text(),
"storeType": $(this).find("Type").text(),
"storeName": $(this).find("Name").text(),
};
if (xml !== null) {
stores.push(store);
}
else {
this.model.set({ stores: [] });
}
}
);
that.set('stores', store)
},
);
},
})
return store;
});
Try this.listenTo(this.model,'change:stores', this.render);
If that doesn't work use promises. Update model like this:
getStoreByName: function() {
var deferred = $.Deferred();
var stores = [];
return this.service.getStoreByName(function(xml) {
if (xml === null) {
return Deferred.resolve([]);
}
$(xml).find("element").each(function() {
var store = {
"storeID": $(this).find("ID").text(),
"storeType": $(this).find("Type").text(),
"storeName": $(this).find("Name").text(),
};
stores.push(store);
});
return Deferred.resolve(stores);
});
this.model.set('stores', stores);
return deferred.promise();
}
and in the view you can do this.model.getStoreByName().then(this.render);

Uncaught TypeError: _.create is not a function at Function.extend backbonejs

var node = Backbone.Model.extend({
defaults: function () {
return {
tag: null,
value: null
};
}
});
var elements = Backbone.Collection.extend({
model: node,
url: "/api/xml/get",
parse: function (data) {
var $xml = $(data);
return $xml.map(function () {
var tag = $(this).each(function () {
$(this).tagName;
});
return { tag: tag };
}).get();
},
fetch: function (options) {
options = options || {};
options.dataType = "xml";
return Backbone.Collection.prototype.fetch.call(this, options);
}
});
var elementsView = Backbone.View.extend({
initialize: function () {
this.listenTo(this.collection, "sync", this.render);
},
render: function () {
console.log(this.collection.toJSON());
}
});
var eles = new elements();
new elementsView({ collection: eles });
eles.fetch();
First line errors out with the subject line using Backbone.js latest. Trying to get a simple demo working with it unable to resolve this myself. underscore.js is referenced.
This method was added in underscore version 1.8.3. You probably have an old version.

Rendering a CollectionView

This question has been asked at length yet I can't seem to get any of the examples to fit my code. My model and collection populate and I get output from the console, but can;t seem to get the AppView.render to do anything other then print 'rendering view...'
var Foodtruck = Backbone.Model.extend({
defaults: {
'name': '',
'twitter': '',
'categories': [],
'coordinates': {
'latitude': 0,
'longitude': 0
}
}
});
var FoodTruckCollection = Backbone.Collection.extend({
model: Foodtruck,
url: 'http://api.mobilefeast.info/foodtrucks',
initialize: function(){
this.bind("render", function( model ){
alert("hey");
view.render( model );
})
},
parse: function(response) {
return response;
},
getData: function(){
var that = this;
that.fetch(
{
success: function () {
console.log('Data is fetched');
},
error: function() {
console.log('Failed to fetch!');
}
});
}
});
var AppView = Backbone.View.extend({
el:$('#container'),
initialize: function(){
console.log('initialize AppView');
this.foodtrucks = new FoodTruckCollection();
this.foodtrucks.getData();
},
render: function(){
console.log('rendering view...');
this.foodtrucks.each(function(model){
console.log(JSON.stringify(model));
});
}
});
new AppView().render();
tried this question: fetch after render
but no luck
Update
var AppView = Backbone.View.extend({
el:$('#container'),
initialize: function(){
console.log('Initialize');
this.foodtrucks = new FoodTruckCollection();
this.foodtrucks.fetch(
{
success: function () {
console.log('Data is fetched');
},
error: function() {
console.log('Failed to fetch!');
}
});
this.listenTo(this.foodtrucks, 'sync', this.render);
},
render: function(){
console.log('Rendering');
this.foodtrucks.each(function(model){
console.log(model.toJSON().name);
});
}
});

Backbone.js Fuse.js render filtered collection

Im trying to add a fuzzy search feature to filter objects in a collection. The console is showing that the Fuse is working correctly and returning the correct objects. Now the question is how do I pass the filtered collection to my view to be rendered.
Here is the collection:
define(["jquery", "backbone", "models/MachineModel"],
function($, Backbone, Model) {
var MachineCollection = Backbone.Collection.extend({
model: Model,
url: '/api/machines',
searchablefields: ['name', 'type', 'ips', 'dataset', 'cpus', 'datacenter', 'state'],
rebuildIndex: function(options) {
var _ref;
if (options == null) {
options = {
keys: this.searchablefields
};
}
return this._fuse = new Fuse(_.pluck(this.models, 'attributes'), options);
},
search: function(query) {
this.rebuildIndex();
var result = this._fuse.search(query);
console.log(result);
this.trigger('reset');
}
});
return MachineCollection;
});
and here is my view
define(["jquery", "backbone", "views/cloud/machines/SingleMachineView", "text!templates/cloud/machines/allMachines.html"],
function($, Backbone, SingleMachineView, template){
var AllMachinesView = Backbone.View.extend({
el: "#magic",
initialize: function() {
// Calls the view's render method
this.collection.on('add', this.addMachine, this);
this.collection.on('reset', this.onCollectionReset, this);
this.render();
},
// View Event Handlers
events: {
'keyup #filter': 'fuzzySearch'
},
// SUBVIEWS
// ========
onCollectionReset: function(collection) {
console.log('collection reset');
var that = this;
$(collection).each(function (model) {
that.addMachine(model);
});
},
addMachine: function(model) {
var machineHTML = (new SingleMachineView({ model: model })).render().el;
$(machineHTML).prependTo('#machine-container');
},
// FUZZY SEARCH
// ============
fuzzySearch: function(e) {
var query = $(e.target).val();
this.collection.search(query);
},
// RENDER
// ======
render: function() {
this.template = _.template(template);
this.$el.html(this.template);
return this;
}
});
return AllMachinesView;
});
any insight would be greatly appreciated.

Backbone view doesn't render template passed to it

I need to be able to pass different template IDs to different routes.
(function() {
window.App = {
Models: {},
Collections: {},
Views: {},
Router: {}
};
var vent = _.extend({}, Backbone.Events);
_.templateSettings.interpolate = /\[\[(.+?)\]\]/g;
App.Router = Backbone.Router.extend({
routes: {
'' : 'index',
'send-message' : 'sendMessage',
'*other' : 'other'
},
index: function() {
t = new (App.Collections.Tables.extend({ url: 'main-contact'}))();
tables = App.Views.Tables({ collection: t, template: 'mainContactTemplate' });
$('#web-leads').html(tables.el);
},
sendMessage: function() {
// t = new (App.Collections.Tables.extend({ url: 'send-message'}))();
// tables = new App.Views.Tables.extend({ collection: t, template: template('sendMessageTemplate')});
// $('#web-leads').html(tables.el);
},
other: function() {
}
});
// Main Contact
App.Models.Table = Backbone.Model.extend({});
App.Collections.Tables = Backbone.Collection.extend({
model: App.Models.Table,
initialize: function(models, options) {
this.fetch({
success: function(data) {
//console.log(data.models);
}
});
if (options) {
this.url = this.url || options.url;
}
}
});
App.Views.Tables = Backbone.View.extend({
tagName: 'ul',
initialize: function() {
this.collection.on('reset', this.render, this);
},
render: function() {
return this.collection.each(this.addOne, this);
},
addOne: function(model) {
var t = new App.Views.Table({ model: model});
this.$el.append(t.render().el);
return this;
}
});
App.Views.Table = Backbone.View.extend({
tagName: 'li',
initialize: function(options) {
this.template = options.template;
console.log(this.options);
},
retrieveTemplate: function(model) {
return _.template($('#' + this.template).html(), model);
},
render: function() {
this.$el.html(this.retrieveTemplate(this.model.toJSON()));
return this;
}
});
new App.Router();
Backbone.history.start();
})();
But I get an error than n is undefined. I think I need to pass this.template into my retrieveTemplate function. But shouldn't it already be set? This code works, by the way, if I hard code in the name of the template ID in the retrieveTemplate function.
EDIT: the template isn't being passed from the call in the router. That's where this is breaking down.
EDIT: I took out the call to extend in the second line of the index route and now I get this._configure is not a function
WORKING VERSION:
(function() {
window.App = {
Models: {},
Collections: {},
Views: {},
Router: {}
};
var vent = _.extend({}, Backbone.Events);
_.templateSettings.interpolate = /\[\[(.+?)\]\]/g;
App.Router = Backbone.Router.extend({
routes: {
'' : 'index',
'send-message' : 'sendMessage',
'*other' : 'other'
},
index: function() {
var t = new (App.Collections.Tables.extend({ url: 'main-contact'}))();
var tables = new (App.Views.Tables.extend({ collection: t, options: {template: 'mainContactTemplate' }}))();
$('#web-leads').html(tables.render().el);
},
sendMessage: function() {
// t = new (App.Collections.Tables.extend({ url: 'send-message'}))();
// tables = new App.Views.Tables.extend({ collection: t, template: template('sendMessageTemplate')});
// $('#web-leads').html(tables.el);
},
other: function() {
}
});
// Main Contact
App.Models.Table = Backbone.Model.extend({});
App.Collections.Tables = Backbone.Collection.extend({
model: App.Models.Table,
initialize: function(models, options) {
this.fetch({
success: function(data) {
//console.log(data.models);
}
});
if (options) {
this.url = this.url || options.url;
}
}
});
App.Views.Tables = Backbone.View.extend({
tagName: 'ul',
initialize: function(options) {
this.collection.on('reset', this.render, this);
this.template = this.options.template;
},
render: function() {
this.collection.each(this.addOne, this);
return this;
},
addOne: function(model, options) {
//console.log(model);
var t = new App.Views.Table({ model: model, template: this.options.template});
this.$el.append(t.render().el);
return this;
}
});
App.Views.Table = Backbone.View.extend({
tagName: 'li',
initialize: function(options) {
//console.log(this.options);
this.template = this.options.template;
},
retrieveTemplate: function(model) {
return _.template($('#' + this.template).html(), model);
},
render: function() {
//console.log(this);
this.$el.html(this.retrieveTemplate(this.model.toJSON()));
return this;
}
});
new App.Router();
Backbone.history.start();
})();
Your router says this:
tables = App.Views.Tables({ collection: t, template: 'mainContactTemplate' });
So you're giving a template: '...' to App.Views.Tables. The initialize in App.Views.Tables looks like this:
initialize: function() {
this.collection.on('reset', this.render, this);
}
so it ignores the template option. If we look at App.Views.Table (singular!), we see this:
initialize: function(options) {
this.template = options.template;
console.log(this.options);
}
but App.Views.Table is instantiated without a template option:
var t = new App.Views.Table({ model: model});
You need to fix how you use App.Views.Table. Backbone will put a view's constructor options in this.options for you so you just need to say:
var t = new App.Views.Table({ model: model, template: this.options.template });
A couple other things to consider:
You have some accidental globals in your router's index method, you should have var t and var tables rather than just t and tables.
A view's render method conventionally returns this so that you can say $x.append(v.render().el) so you might want to adjust your render methods to match the convention.
You probably need to bind the context. Underscore can help you with that.
.bindAll or .bind should do it.
I typically just use _.bindAll during initialization as shown below.
...
initialize: function(options) {
_.bindAll(this); // apply appropriate context
this.template = options.template;
},
...
Hope this helped, best of luck.

Resources