backbone.js update one view based on events in another? - javascript

I have the following HTML code:
<ul id='item-list'></ul>
<button id='add-item'>Add Item</button>
<script type='text/template' id='item-template'>
<li><%= title %></li>
</script>
and the following javascript / backbone js code:
var Item = Backbone.Model.extend({});
var ItemCollection = Backbone.Collection.extend({
model: Item
});
var ItemListView = Backbone.View.extend({
el : $("#item-list"),
initialize(options) {
this.item_collection = new ItemCollection();
},
appendItem: function() {
new_item = new Item({'title' : 'New Item'});
this.item_collection.add(new_item);
item_template = $("#item-template");
item_html = _.template(item_template,new_item.toJSON());
this.el.append(item_html);
}
});
var AddItemView = Backbone.View.extend({
el: $("add-item"),
events: {
"click" : "addItem"
},
addItem: function() {
// ?
}
});
item_list_view = new ListItemView();
add_item_view = new AddItemView();
How can I add a new item to the item list view and collection from an event in the addItemView View? also, should the creation of the model, appending it to the collection, and appending it to the view all take place in the ListItemView.addItem() function, or should I instead have it binded to the add event of the ItemCollection ? I am still having some trouble wrapping my head around the way bindings and the interactions between various views, models, and collections should work.

here's an example of events between 2 views working with a model/collection. Basically, use collectionName.bind('add',yourFunction,this);
<script type="text/template" id="item-template">
<div class="nonedit"><span ><%= name %> (<%= age %>)</span> <a class="delete" href="#">X</a>
<div class="edit"><input /></div>
</script>
<body>
<ul class="1"></ul>
<div class="count">
<div></div>
<input id="name" placeholder="enter a name"/>
<input id="age" placeholder="enter age"/>
</div>
</body>
var Person = Backbone.Model.extend({
defaults:function(){
return {
name:'unknown',
age:0
};
}
});
var People = Backbone.Collection.extend({
model:Person
});
var people = new People;
var Li = Backbone.View.extend({
tag:'li',
class:'name',
template:_.template($('#item-template').html()),
events:{
'click a.delete':'remove'
},
initialize:function(){
this.model.bind('change',this.render,this);
$(this.el).html(this.template(this.model.attributes));
},
render:function(){
$(this.el).html(this.template(this.model.attributes));
},
remove:function(){
this.model.destroy();
$(this.el).fadeOut(300);
setTimeout(function(){$(this.el).remove()},400);
},
modify:function(){
$(this.el).addClass('edit');
}
});
var Ul = Backbone.View.extend({
el:$('ul'),
events:{
},
initialize:function(){
people.bind('add',this.add,this);
},
render:function(){
},
add:function(model){
var li = new Li({model:model});
this.el.append(li.el);
}
});
var ul = new Ul;
var Div = Backbone.View.extend({
el:$('.count'),
nameInput:$('#name'),
ageInput:$('#age'),
events:{
'keypress input#name':'keypress',
'keypress input#age':'keypress',
},
initialize:function(){
people.bind('add',this.add,this);
},
render:function(){
},
add:function(e){
this.el.find('div').html(people.length);
},
keypress:function(event){
if(event.which == 13){
people.add({name:this.nameInput.val(),age:this.ageInput.val()});
}
}
});
var div = new Div;

Related

Adding item to knock out view model , is not updating the view

I have a ViewModel which I am binding to view list item.
var MyViewModel = function() {
var self = this;
self.addItems = function(vm) {
vm.inventoryItems.push('New Item');
}
};
var myVM= new MyViewModel();
ko.applyBindings(myVM);
The view model has a property called inventoryItems (which is from a service).
I am bidning that to view using ,
<ul data-bind="foreach:inventoryItems">
<li>
<input class="form-control" type="text" data-bind="value: $data" />
</li>
</ul>
<div class="text-right">
<a data-bind="click: $parent.addItems">+ Add more</a>
</div>
Now, the items that are already in the collection , inventoryItems are getting rendered fine.
When I am adding a new item using, I can see the items being added via console, but the view is not getting updated!
self.addItems = function(vm) {
vm.inventoryItems.push('New Item');
}
The below code snippet will make your inventoryItems observable
var MyViewModel = function () {
var self = this;
self.inventoryItems = ko.observableArray();
self.addItems = function (vm) {
vm.inventories.push('New Item');
self.inventoryItems(vm.inventories);
}
};
var myVM = new MyViewModel();
ko.applyBindings(myVM);

Backbone dropdown change doesn't update model in a collection

I'm new to Backbone and I have this problem while learning, which I was trying to solve it for some time and it get's annoying. I'm rendering one dropdown for each of the attributes in the model. When I change the selected value, I would like to update the model. When I try to catch the change event in OrderView, it does not work. If I do that in the OrderingView, it works, but then I need to search for the current model.
What am I doing wrong here?
The situation: I have this model:
var Order = Backbone.Model.extend({
defaults:{
column: '',
order: ''
}
});
and corresponding collection having Order as model. The Views:
var orderView = Backbone.View.extend({
model: new Order(),
initialize: function(){
this.template = _.template(order_template);
},
render: function(){
var temp = this.template({model:this.model.toJSON(),order_columns:this.order_columns});
this.$el.html(temp);
return this;
},
events: {
'change .order_columns': 'change_column'
},
change_column: function(){
console.log('column changed..');
}
});
var orderingView = Backbone.View.extend({
model: new OrderCollection(),
initialize: function(){
var that = this;
_(this.options.orderings).each(function(or){
that.model.add(new Order({column: or.column, order: or.order}));
});
this.model.on('add', this.render, this);
this.model.on('change', this.changed_item,this);
},
render: function(){
var that = this;
that.$el.html('');
var temp_order = '';
_.each(this.model.toArray(), function(ordering, i){
var obj = new orderView({model: ordering, order_columns: that.options.order_columns}).render().$el.html();
temp_order += obj;
});
var temp = _.template(ordering_template,{element: temp_order});
that.$el.html(temp);
$(document).ready(function(){
$('.add-ordering').click(function(){
var new_order = new Order({column: 'none', order: 'ASCENDING'});
that.model.add(new_order);
});
});
return this;
},
});
and the call is from different file using requirejs:
that.orderView = new orderingView({el:table,
orderings: that.data.models.layers[0].orderings,
order_columns:that.data.models.layers[0].columns});
Also I load the html templates at the beginning using requirejs and known as order_template and ordering_template
templates:
<div class="control-group">
<div class="controls" style="margin-left:30px;">
<select class="order_columns" name="columns" style="float:left;">
<option value='none' <%=model.column==='none'? 'selected': ''%>>None</option>
<% _(order_columns).each(function(col){ %>
<option value="<%=col.alias%>" <%=model.column===col.alias? 'selected': ''%>><%= col.name %></option>
<% }); %>
</select>
<select class="ordering" name="ordering" style="float:left;margin-left:10px;">
<option value='ASCENDING' <%=model.order === 'ASCENDING'? 'selected':''%> >ASC</option>
<option value='DESCENDING' <%=model.order === 'DESCENDING'? 'selected':''%>>DESC</option>
</select>
<span class="ui-icon ui-icon-circle-close ui-order-close <%=model.column%>" style="margin-left:10px;"></span>
</div>
</div>
and ordering_template
<div class="row">
<form class="form-horizontal span12">
<fieldset>
<br/>
<div class="row">
<div class="span9 ordering_div" style="width:520px;">
<%=element%>
</div>
</div>
</fieldset>
</form>
</div>
Any suggestion?

Backbone.js event doubts

i have to create events using backbone.js.Below is my js code
var Trainee = Backbone.Model.extend();
var TraineeColl = Backbone.Collection.extend({
model: Trainee,
url: 'name.json'
});
var TraineeView = Backbone.View.extend({
el: "#area",
template: _.template($('#areaTemplate').html()),
render: function() {
this.model.each(function(good){
var areaTemplate = this.template(good.toJSON());
$('body').append(areaTemplate);
},this);
return this;
}
});
var good = new TraineeColl();
var traineeView = new TraineeView({model: good});
good.fetch();
good.bind('reset', function () {
$('#myButtons').click(function() {
traineeView.render();
});
});
<div class = "area"></div>
<div class="button" id="myButtons">
<button class="firstbutton" id="newbutton">
Display
</button>
</div>
<script id="areaTemplate" type="text/template">
<div class="name">
<%= name %>
</div>
<div class="eid">
<%= eid %>
</div>
<div class="subdomain">
<%= subdomain %>
</div>
my o/p on clicking display button is
Display // this is a button//
Sinduja
E808514
HPS
Shalini
E808130
HBS
Priya
E808515
HSG
Now from the view i have to bind a change event to the model..the changes in the model must be triggered on the view to display the output on the click of display button.
This isn´t exactly answering your queston but:
if trainee (I've renamed it to trainees) is a collection you should set it using:
new TraineeView({collection: trainees});
Then in render:
this.collection.models.each(function(trainee)
And you propably wan´t to move the call to fetch outside the view, in the router perhaps:
trainees = new TraineeColl();
view = new TraineeView({collection: trainees});
trainees.fetch();
That way your view only listens to the model.
You also should move the bind part to the views initialize method
this.collection.bind('reset', function () {
this.render();
});
Hope this helps.
var TraineeView = Backbone.View.extend({
el: "#area",
initialize : function(options){ // you will get the passed model in
//options.model
var trainee = new TraineeColl();
trainee.fetch();
trainee.bind('reset change', this.render,this); //change will trigger render
// whenever any model in the trainee collection changes or is modified
}
template: _.template($('#areaTemplate').html()),
render: function() {
this.model.each(function(trainee){
var areaTemplate = this.template(trainee.toJSON());
$('body').append(areaTemplate);
},this);
return this;
}
});
var traineeView = new TraineeView({model: trainee});
});

How to Attach ItemView instances at runtime to Backbone.marionette.Composite View

I am trying to add different views {Tabular View or Chart View} in a table. Each can have its own data. I am using Backbone Marionette for this and have following line of code. But item view is not render.
html
<script id="grid-template" type="text/template">
<div>
Data is displayed using Tabular View and Chart View !
</div>
</script>
<script id="TabularViewTemplate" type="text/template">
<table><tr><td>Value1</td><td>Value2</td></tr> </table>
</script>
<script id="ChartTemplate" type="text/template">
<table><tr><td>Value1</td><td>Value2</td></tr> </table>
</script>
<div id="grid">
</div>
​
JS
var ANBaseModel= Backbone.Model.extend({
name:"",
type:""
});
var SSANModel= ANBaseModel.extend({
type:"SS"
});
var BaseView=Backbone.Marionette.ItemView.extend({
template: "#row-template",
tagName: "tr" ,
model:SSANModel
});
// A Spreadsheet View
var SSView= BaseView.extend({
render: function(){
alert(this.model.type);
if(this.model.type=="SS")
alert("Spreadsheet");
else if(this.model.type=="ChartAN")
alert("Chart");
}
});
// A Chart View
var ChartView = BaseView.extend({
render: function(){
alert(this.model.type);
if(this.model.type=="SS")
alert("Spreadsheet");
else if(this.model.type=="ChartAN")
alert("Chart");
}
});
// The grid view
var GridView = Backbone.Marionette.CompositeView.extend({
tagName: "table",
template: "#grid-template",
});
var SS= new SSANModel();
alert(SS.type);
var objSSView=new SSView ({model:SS,template:"TabularViewTemplate"});
var gridView = new GridView({
itemView: objSSView
});
gridView.render();
console.log(gridView.el);
$("#grid").html(gridView.el);
JsFiddle: http://jsfiddle.net/Irfanmunir/ABdFj/
How i can attach ItemView instances to composite View. Using this i can create different views having its own data . I am not using collection for composite view.
Regards,
Well you should create a collection with your models and pass it as argument when you create your gridView:
var gridView = new GridView({
collection: SSCollection,
itemView: objSSView
});
Each model of the collection will be a new istance of your defined itemView.
You also need to tell you CompositeView where to put your itemViews:
appendHtml: function(collectionView, itemView, index){
collectionView.$("tbody").append(itemView.el);
},
You could also try to use use buildItemView method:
buildItemView: function(item, ItemViewType, itemViewOptions){
var options = _.extend({model: item}, itemViewOptions);
switch(item.type){
case 'ss':
ItemViewType = SSView;
case 'another':
ItemViewType = AnotherView;
}
var view = new ItemViewType(options);
return view;
},

Backbone Collection Cant Find Model's View Render

I'm trying to render a simple collection view and having a weird issue.
The problem is that when i try to call the render method of the model in a collection's view it can't find the render method.
My Model And View
var PersonModel = Backbone.Model.extend({});
var PersonView = Backbone.View.extend({
tagName : "person",
events:{
"click h3":"alertStatus"
},
initialize:function(){
this.model.on('change',this.render,this);
} ,
render:function(){
var underscore_template = _.template('<h3>Name : <%= name %></h3>'+
'<h3>Last Name : <%= surname %></h3>' +
'<h3>Email : <%= email %> </h3>') ;
console.log("Person View Render Oldu");
this.$el.html(underscore_template(this.model.toJSON()));
},
alertStatus :function(e){
alert("Clicked on Model View");
}
});
My Collection And Collection View
var PersonList = Backbone.Collection.extend({
model:PersonModel,
url:'/models'
});
var personList = new PersonList();
var PersonListView = Backbone.View.extend({
tagName : "personlist",
render : function(){
this.collection.forEach(this.addOne,this);
},
addOne : function(personItem){
var personView = new PersonView({model:personItem});
this.$el.append(personView.render().el); // The call to personView.render throws undefined
},
initialize : function(){
this.collection.on('add',this.addOne,this);
this.collection.on('reset',this.addAll,this);
},
addAll : function(){
this.collection.forEach(this.addOne,this);
}
});
var personListView = new PersonListView({
collection:personList
});
personList.fetch({
success:function(){
console.log("Fetch success");
}
});
I'm calling this JS on document ready with Jquery and adding it to a div with id named app.
My fetch is also successful.The problem persists at the addOne function of the Collection View when trying to call personView.render().el
Any help would be appreciated.
You forgot returning the element in your render:
render : function() {
var underscore_template = _.template('<h3>Name : <%= name %></h3>'+
'<h3>Last Name : <%= surname %></h3>' +
'<h3>Email : <%= email %> </h3>') ;
console.log("Person View Render Oldu");
this.$el.html(underscore_template(this.model.toJSON()));
return this; // chaining
}
Otherwise you can't chain it and you can't access el afterwards.

Categories