Can I somehow let my empty view know about my collection, so that I can potentially add to my collection from the empty view?
Is it not best practice if I do something like :
EmailsView = Backbone.Marionette.CollectionView.extend({
emptyView: EmptyMealView,
itemView : EmailView,
itemViewOptions : function(){
return {collection : this.collection}
},
});
So I can do something like this in the empty view:
EmptyMealView = Backbone.Marionette.ItemView.extend({
events:{
'click .sendEmail' : 'sendEmail',
},
sendFakeEmail: function(e){
var myEmail = new Email({
Date : new Date(),
Type : 3
});
var that = this;
myEmail.save(null,{
success:function(model){
that.collection.add(model);
}
});
}
});
What you have is perfectly fine. ItemViewOptions is created so that you could pass data from the parent view to its child views.
The emptyView is actually a fully qualified child of the collectionView.
In backbone, an empty collection actually has a weird blank model in it, and your empty view actually gets this empty model. In addition, the empty view will get options passed in by the itemviewOptions method. You may need to implement serializeData in your empty view in order to retrieve data you pass in as options that isn't part of the model.
Related
I have a base model, that is creating a view with several div's. It is not actually a form; but it is acting as a form. I have variables being set with defaults as well. Here's my model right now:
var BaseModel = require('base-m');
var SomeModel = BaseModel.extend({
defaults: function() {
return {
FirstName : null,
LastName : null,
Age : null,
State : null
};
}
update: function() {
return {
FirstName : $('[name="FirstName]').val()
};
console.log(FirstName);
}
});
I am trying to update the model with the particular value of whatever is entered. Do I need to use an event? I am doing this because I want to retrieve the updated variable for output purposes.
Also; (if it's different), lets say it's a drop down menu like states..? Would I update it similar to a text field like first name?
Thanks
It appears your model is accessing the DOM. Usually, your view would deal with the DOM, extracting information then updating the model.
So for example, create a view with a constructor that:
Creates your input elements and put them in an attribute called $el; then
Adds $el to the DOM; then
Binds event listeners to $el.
These event listeners can update model attributes via a reference to the model, e.g. this.model in the view's context.
The view can also watch the model for changes and update itself accordingly.
For example:
var SomeView = Backbone.View.extend({
// Store HTML of DOM node in template. Easy to change in future.
template: [
'<div class="blah">',
'<input type="text" class="hello" />',
'</div>'
].join(''),
initialize: function() {
// Create DOM node, add to DOM
this.$el = $(_.template(this.template)());
$("body").append(this.$el);
this.hello = this.$el.find('.hello');
// Update model when view changes
this.hello.on('keydown', this.updateModel);
// Update view when model changes
this.model.on('change', this.updateView);
},
updateModel: function(evt) {
this.model.set('hello', this.hello.val());
},
updateView: function() {
this.hello.val(this.model.get('hello'));
}
});
The code that creates your model could also create this view and pass the model reference to the view constructor, e.g.
var myModel = new SomeModel();
var myView = new SomeView({model: myModel});
Of course, all of the specifics will vary according to your situation.
If you would like to use an existing DOM node as $el, remove the first two lines of code that create and append $el. Then instantiate your view like:
var existingJqNode = $('#existing'); // find existing DOM node, wrap in jQuery object
var myView = new SomeView({
model: myModel,
$el: existingJqNode
});
Above all, think about how best to set this up. Does using an already existing DOM element as $el create an advantage? If you want to create more of these views in the future, what code is responsible for creating/adding the $els before each view is instantiated?
Hope that helps.
Case 1: Passing model as in options
var View1 = Backbone.View.extend({
initiliaze:function(){
}
});
Case 2 : Passing model as a param and setting it using this
var View2 = Backbone.View.extend({
initiliaze:function(model){
this.model = model
}
});
var view1 = new View1({model:someModel})
var view2 = new View2(someModel)
It's the same thing, except that in the first case you have less code in your view declaration because Backbone handle setting the model in the view for you (this.model = model).
In general Backbone can handle some parameters for you, you can take a look at the documentation to have more informations about it.
Here I am passing a model to a Backbone view.
view = new View ({model:{item:4,name:"Ipad"}});
When I console.log that model from within the View. I get:
Object {item: 4, title: "Ipad"}
This is not a backbone model therefore I don't have methods
like toJSON. I realize that if I define a Backbone model and
passed it in everything works fine.
view = new GenreView ({model:new Model({title: 4, title: "Ipad"})});
This logs
r {cid: "c2", attributes: Object, _changing: false, _previousAttributes: Object, changed: Object…}
Why is it that first approach doesn't work and how can I fix it?
Its simply that the special 'model' option expects a Backbone.Model not a javascript object.
So you are correct when you create a new Backbone.Model to pass into the view.
There is nothing to fix as far as I can tell.
You need to use a Backbone.Model instead of a regular JavaScript object {}
var Item = Backbone.Model.extend({
// ...
});
Instantiate the Item model
var myItem = new Item();
Now use your item in the view
var myView = new View({model: myItem});
This answer assumes that View is setup as something like
var View = Backbone.View.extends({
// ...
});
You could cast the object to a Backbone Model in your view's initialize method:
var View = Backbone.View.extend({
initialize: function(options){
if (_.isPlainObject(this.model)) {
this.model = new Backbone.Model(this.model);
}
}
});
This way the view will be able to operate on it's model regardless of whether you passed it an instance of a Backbone.Model or a plain object. You can see an example of it working here: http://jsbin.com/igecEgE/1/edit?js,console
i have this result from the restful service i have:
NOTE: Response is in JSON format it's the plugin from chrome which displays it like that.
if you look at image two [the one above this] the models attributes is Items then each item are under Items. What should i do to access item?
my problem is i can't access or retrieve data of each item from this result. i must not change anything from the server side though. I'm using backbone with this code.
window.Item = Backbone.Model.extend();
window.ItemCollection = Backbone.Collection.extend({
model: Item,
url: 'http://localhost/InterprisePOS/Product/loaditembycategory/Event Materials'
});
window.ItemListView = Backbone.View.extend({
tagName : 'ul',
initialize: function(){
this.model.bind("reset",this.render,this);
},
render: function(eventName){
_.each(this.model.models.Items, function(item){
$(this.el).append(new ItemListItemView({model:item}).render.el);
},this);
return this;
}
});
window.ItemListItemView = Backbone.View.extend({
template : _.template($("#item-list").html()),
render: function(eventName){
$(this.el).html(this.template(this.model.toJSON()));
return this;
}
});
var AppRouter = Backbone.Router.extend({
routes:{
"":"list"
},
list:function(){
this.itemList = new ItemCollection();
this.itemListView = new ItemListView({model:this.itemList});
this.itemList.fetch();
$("#itemContainer").html(this.itemListView.render().el);
}
});
var app = new AppRouter();
Backbone.history.start();
UPDATE
I was able to correct the my problem with nested json objects. Now the Models attrib or my Collection is populated with individual items. But still the problems is it doesn't work and doesn't display my views.
This is the code i added:
parse: function(response) {
return response.Items;
}
UPDATE
I Finally answered my question! horray! somehow i forgot to put "()" on render in my ItemListview. and also $("#ItemContainer") doesn't seem to work so i made it to $('#ItemContainer) now i'm displaying the Details from my model.
I'm fairly certain that Backbone by default uses JSON for all requests and has no idea what to do with XML, you'll probably need to override the sync method for the collection in order to us use XML.
The following should be helpful in addressing your issue: http://newcome.wordpress.com/2011/02/20/consuming-xml-web-services-in-backbone-js-using-jath/
They use a 3rd party library xml parser in the sync parse operation which converts the model to JSON which Backbone can use natively.
Make sure the response is returned as JSON. Backbone works on JSON data by default.
How can I know which attribute of the view model is changed in the render function? (In the render function, "e" is the model, but I need only the attribute which is changed.) I need to know this to know which template to use. Or is there another method to do this?
window.Person = Backbone.Model.extend({});
window.Njerzit = Backbone.Collection.extend({
model: Person,
url: '/Home/Njerzit'
});
window.PersonView = Backbone.View.extend({
tagName: 'span',
initialize: function () {
_.bindAll(this, 'render');
this.model.bind('change', this.render);
},
render: function (e) {
//if model name is changed, I need to render another template
this.template = _.template($('#PersonTemplate').html());
var renderContent = this.template(this.model.toJSON());
$(this.el).html(renderContent);
return this;
}
});
I believe the changedAttributes function is what you're looking for
changedAttributesmodel.changedAttributes([attributes])
Retrieve a hash of only the model's attributes that have changed. Optionally,
an external attributes hash can be passed in, returning the attributes
in that hash which differ from the model. This can be used to figure
out which portions of a view should be updated, or what calls need to
be made to sync the changes to the server.
or to check if a specific attribute has changed use the hasChanged function
hasChangedmodel.hasChanged([attribute])
Has the model changed since the last "change" event? If an attribute is passed, returns true
if that specific attribute has changed.
var nameChanged = this.model.hasChanged("name");
From Backbone Docs
You can bind to change:name if you only want to notify if the name has changed: http://documentcloud.github.com/backbone/#Model-set