Backbone.js event doubts - javascript

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});
});

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 DELETE is sent with an empty body

Delete Function:
My backbone function to delete a model (called on the click of a button) looks like this:
deleteCar: function (ev) {
console.log(this.car.toJSON());
this.car.destroy({
success: function () {
router.navigate('', {trigger:true});
}
});
return false;
},
this.car is created in another function but in the main scope. As seen above, I'm logging the contents of this.car and I get a JSON like this:
Object {carId: "17", carDes: "awesome"}
Now, I'm calling this.car.destroy... and I'm observing the network tab on Chrome. I can see a DELETE request firing but there is no data appended to the request. It's just an empty request to the correct url.
How can I attach my car model to the request?
Edit:
Render Function:
This is the function that creates a new car model. It is in the same Backbone view as the Delete function above.
render: function(options) {
var that = this;
if (options.id) {
that.car = new Car({
carId: options.id
});
that.car.url = 'http://localhost/Project/index.php/rest/resource/car/carId/' + options.id;
that.car.fetch({
success: function(car) {
console.log(that.car.toJSON());
that.car.url = 'http://localhost/Project/index.php/rest/resource/car/';
var template = _.template($("#edit-car-template").html());
var data = {
car: that.car
};
that.$el.html(template(data));
}
});
} else {
var template = _.template($("#edit-car-template").html());
var data = {
car: null
};
that.$el.html(template(data));
}
}
Edit-Car-Template
<script type="text/template" id="edit-car-template">
<form class="edit-car-form">
<legend>
<%= car ? 'Edit' : 'New' %> Car</legend>
<label>Car Description</label>
<input name="carDes" type="text" value="<%= car ? car.get('carDes') : '' %>">
<hr />
<button type="submit" class="btn">
<%= car ? 'Update' : 'Create' %>
</button>
<% if(car) { %>
<input type="hidden" name="carId" value="<%= car.get('carId') %>" />
<button data-car-id="<%= car.get('carId') %>" class="btn btn-danger delete">Delete</button>
<% }; %>
</form>
</script>
Edit 2:
Layout:
The view layout of my application is as follows:
And the following code is used to render the CarListView (get the list of cars using the REST API)
var CarListView = Backbone.View.extend({
el: '.page',
render: function () {
var that = this;
this.cars = new Cars();
this.cars.fetch({
success: function () {
var template = _.template($("#car-list-template").html());
var data = {cars: that.cars.toJSON()};
that.$el.html(template(data));
}
})
}
});
Models
My car model and car collection are defined as follows:
var Car = Backbone.Model.extend({
urlRoot: ROOT + 'car',
idAttribute: 'carId'
});
var Cars = Backbone.Collection.extend({
model: Car,
url: ROOT + 'car'
})
Update Function:
And following is the code for saving (updating) the model once the update button is clicked. This part works perfectly.
events: {
'submit .edit-car-form': 'saveCar',
'click .delete': 'deleteCar'
},
saveCar: function (ev) {
console.log('in save');
var carDetails = $(ev.currentTarget).serializeObject();
var car = new Car();
car.save(carDetails, {
success: function (car) {
router.navigate('', {trigger: true});
}
});
return false;
}
Sounds like this is working as intended. The Backbone.Model.destroy() method will generate an HTTP DELETE call to the model's the relevant URL. It typically won't have any content in the method body, as the ID at the end of the URL should be all you need to delete the RESTful resource. If you need different behavior, Backbone expects you to override the model's sync method (see here and here). Traditionally HTTP servers ignored any body sent on an HTTP DELETE method call, and the HTTP spec doesn't mention it needing a body, so Backbone is just encouraging you to follow that example.
Note also that setting the url property on the model instance itself is not the usual way to ensure the URL has the model ID. If you're going to use a Backbone.Model outside of a Backbone.Collection, you should include the urlRoot property when specifying Car ... where you can also specify the fetch function if you really need to override it:
var Car = Backbone.Model.extend({
urlRoot: '/Project/index.php/rest/resource/car`
fetch: function(options) {
// ... if needed, but note you can provide a "success"
// callback in the options; see below.
}
});
Doing it that way, Backbone will ensure that any call to car.destroy() will generate the right URL. For instance:
var car = new Car({
id: 123
});
// This will GET /Project/index.php/rest/resource/car/123
car.fetch({
success: function() {
console.log('Received: ' + car.toJSON());
// ... anything else you need to do after fetching.
});
});
// ... some time later ...
// This will DELETE /Project/index.php/rest/resource/car/123
car.destroy({
success: function() {
console.log('Car has been deleted on server');
}
});
Again, if your server needs more info than the model's ID to delete something, you'll have to override the sync method... but that's another question!

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.

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

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;

Categories