Backbone - Accessing Model defaults through Collection in a View - backbone.js

Ok thaht might not be too clear.
I passed a collection to my view. My collection has a Model, and the Model has defaults in an array. When I log the collection from the View it shows no length. But there are 4 defaults in my model. How can I get the default of my model to my view?
The call to view:
var menuLinks = new App.Collections.MenuLinks ;
var newView = new App.Views.Navbar({ collection: menuLinks }) ;
View:
App.Views.Navbar = Backbone.View.extend({
initialize: function(){
console.log(this.collection) ;
//this.render() ;
}
});
COllection:
App.Collections.MenuLinks = Backbone.Collection.extend({
model: App.Models.MenuLinks
});
Model:
App.Models.MenuLinks = Backbone.Model.extend({
//Default menus
defaults:[
{
name: 'Home',
href: ''
},
{ name: 'Trips',
href: '#trips'
},
{ name: 'Login',
href: '#login'
},
{ name: 'LogoutOhYeah',
href: '#logout'
},
]
});

So... you simply want something like:
var collection = this.options.collection, defaults;
defaults = collection.length && collection.models[0].defaults ||{};

Related

Can't conditionally render view marionette

I can't figure out how to use a function to decide which child view to render in marionette. It seems like it should be pretty simple based on the documentation here: https://marionettejs.com/docs/master/marionette.collectionview.html#collectionviews-childview
I found that page from the composite view docs which inferred that using a function to define a childView should be the same for collection and composite views https://marionettejs.com/docs/master/marionette.compositeview.html#compositeviews-childview)
However, with the following code I am getting the error message "Uncaught TypeError: view.on is not a function." My code is below:
var Backbone = require('backbone');
var Marionette = require('backbone.marionette');
var ToDoModel = require('./models/todo');
var ToDo = Marionette.LayoutView.extend({
tagName: 'li',
template: require('./templates/todoitem.hbs')
});
var TodoList = Marionette.CompositeView.extend({
el: '#app-hook',
template: require('./templates/todolist.html'),
childView: function(item) {
return ToDo;
},
childViewContainer: 'ul',
ui: {
assignee: '#id_assignee',
form: 'form',
text: '#id_text'
},
triggers: {
'submit #ui.form': 'add:todo:item'
},
collectionEvents: {
add: 'itemAdded'
},
modelEvents: {
invalid: 'itemInvalid'
},
onAddTodoItem: function() {
this.model.set({
assignee: this.ui.assignee.val(),
text: this.ui.text.val()
});
if (this.model.isValid()) {
var items = this.model.pick('assignee', 'text');
this.collection.add(items);
}
},
itemAdded: function() {
this.model.set({
assignee: '',
text: ''
});
this.ui.assignee.val('');
this.ui.text.val('');
},
itemInvalid: function() {
console.log('this item is invalid!')
}
});
var todo = new TodoList({
collection: new Backbone.Collection([
{assignee: 'Scott', text: 'Write a book about Marionette'},
{assignee: 'Andrew', text: 'Do some coding'}
]),
model: new ToDoModel()
});
todo.render();
Why isn't the ToDo view being rendered?
It appears as if you are using an older version of Marionette (LayoutView for example was removed in version 3) and referencing the documentation for the newest version (currently 3.5.1).
In older versions of Marionette, childView as a function is not supported, instead you should use getChildView
So, the relevant portion of your code should look like:
var TodoList = Marionette.CompositeView.extend({
...
getChildView: function(item) {
return ToDo;
},
...
});

Render object type in backbone-forms

I'm trying to render a object type with the backbone-forms tool but I can't get it to work.
I define a model:
Models.ModelType = Backbone.Model.extend({
schema: {
object1: {
type: 'Object',
subSchema: {
option: {
type: 'Checkbox'
},
description: {
type: 'Text'
}
}
},
object2: {
type: 'Checkbox'
}
}
});
And then I call it in my view:
var model = new app.Models.ModelType();
var form = new Backbone.Form({
model: model
}).render();
It doesn't render either object1 and object2. When I comment object1, it does render object2.
In my template I have:
<div data-fields="object1"></div>
<div data-fields="object2"></div>
Edit:
Here is the view:
Views.ModelView = Backbone.View.extend({
initialize: function(){
this.render();
},
render: function () {
var model = new app.Models.ModelType();
var form = new Backbone.Form({
model: model
}).render();
$('#form').html(form.el);
}
});
And then I call it like:
var modelView = new ModelView();
In my routes file

Backbone - Nested Model with Model Binder

ModelBinder doesn't seem to work together with nested model( backbone-nested project) ..the changes from model don't get propogated to the nested elements.On changing the input value the span value doesn't change...If NestedModel is replace with DeepModel it works. Again the NestedModel also works if the person.name is removed and Model has just one level(lastName and firstName).
<script type='text/coffeescript'>
$ ->
class MyModel extends Backbone.NestedModel
defaults:
person:
name :
firstName: 'Bob'
lastName: 'Sass'
window.model = new MyModel
FormView = Backbone.View.extend
initialize: ->
#modelBinder = new Backbone.ModelBinder();
#modelBinder.bind(#model,#el)
el: '#frm'
view = new FormView model: model
</script>
<body>
<form method="post" action="/test" id='frm'>
<div id="welcome"> Welcome, <span id='person.name.firstName'></span> <span id='person.name.lastName'></span>
<br><br>
Edit your information:
<input type="text" name="person.name.firstName" value="zz"/>
<input type="text" name="person.name.lastName" value="nn"/></div>
</form>
I ran into the very same problem. I found success using Backbone.ModelBinder in conjunction with backbone-associations. It allowed me to use ModelBinder with my nested models and accomplish what you are describing.
I took the example you posted and created a fiddle Using Backbone.ModelBinder with backbone-associations using your example. Check it out and see if it answers your question.
The JavaScript ends up looking like this:
var Name = Backbone.AssociatedModel.extend({
defaults: { 'firstName': '', 'lastName': '' }
});
var Person = Backbone.AssociatedModel.extend({
defaults: { 'name': null },
// create a relation for our nested model
relations: [{
'type': Backbone.One,
'key': 'name',
'relatedModel': Name
}]
});
var MyModel = Backbone.AssociatedModel.extend({
defaults: { 'person': null },
// create a relation for our nested model
relations: [{
'type': Backbone.One,
'key': 'person',
'relatedModel': Person
}]
});
var FormView = Backbone.View.extend({
el: '#frm',
initialize: function() {
this._modelBinder = new Backbone.ModelBinder();
},
render: function() {
var bindingsHash = {
'person.name.firstName': [
{ 'selector': '#firstName' },
{ 'selector': '[name=firstName]' }
],
'person.name.lastName': [
{ 'selector': '#lastName' },
{ 'selector': '[name=lastName]' }
]
};
this._modelBinder.bind(this.model, this.el, bindingsHash);
},
close: function() {
this._modelBinder.unbind();
}
});
// create the model
var modelInfo = new MyModel({
'person': {
'name': {
'firstName': 'Bob',
'lastName': 'Sass'
}
}
});
// create the view and render
var view = new FormView({ model: modelInfo });
view.render();

how to listen to array submodel's value change

I have a model define like below.
var A = Backbone.Model.extends({
initialize: function(){
this.on('change:users.name',this.onUserNameChanged)
},
onUserNameChanged: function(){ alert('name changed')
});
var a = new A ({
id:1,
name:'test',
users:[
{
id:2,
name:'u1'
},
{
id:3,
name:'u4'
}
]
})
I want add event on the each user name change in Model define.
I have no idea to do this.It's seems hard to me.
It seems that you can't get change events by manipulating Backbone model array members as is described here:
backbone-js-set-model-array-property
Your best option is to set the whole array and listen to a change:users event or even better - come up with a different model that has a Backbone collection for users that will get the event when manipulated:
var A = Backbone.Model.extend({
initialize: function (options) {
_.extend(this, options);
}
});
var Users = Backbone.Collection.extend({
initialize: function () {
this.on('change:name', function () {
alert('name changed');
});
}
});
var a = new A({
id: 1,
name: 'test',
users: new Users([{
id: 2,
name: 'u1'
}, {
id: 3,
name: 'u4'
}])
});
a.users.get('2').set('name', 'u2');

Appending data to same collection after every pagination fetch

I am trying to populate instagram images using backbone,
I have basically 3 models as follows,
User model store all the user info related to instagram
App.Models.User = Backbone.Model.extend({
defaults: {
id: '',
access_token: '',
userid: '',
username: '',
full_name: '',
profile_picture: ''
},
urlRoot: "/api/user/",
initurl: function() {
return "https://api.instagram.com/v1/users/"+this.get('userid')+"/media/recent/?access_token=" + this.get('access_token');
},
initialize: function() {
this.set('id', $('#domdump .id').val());
this.fetch({
success: function(model) {
var photos = new App.Collections.Ig_photos([],{
url: model.initurl()
});
}
});
}
});
A model to store the next url for pagination
App.Models.Ig_next_url = Backbone.Model.extend({
defaults: {
next_url: ''
},
next_url:function(){
return this.get('next_url');
}
});
A model for the photo
App.Models.Ig_photo = Backbone.Model.extend({});
A collection for the multiple photo
App.Collections.Ig_photos = Backbone.Collection.extend({
model: App.Models.Ig_photo,
initialize: function(model, options) {
this.url = options.url;
this.nextSet();
},
sync: sync_jsonp,
parse: function( response ) {
if(response.pagination && response.pagination.next_url && response.pagination.next_url != this.url){
var next_url = new App.Models.Ig_next_url({ next_url: response.pagination.next_url });
this.url = next_url.next_url();
}
return response.data;
},
nextSet: function(){
this.fetch({
success: function(photos){
var ig_photos_views = new App.Views.Ig_photos_view({ collection: photos});
console.log(photos);
}
});
}
});
Also i have some views that does the render with a load more button that calls the nextset of the collection.
What i was trying to achieve is the photos get appended to the collection upon nextset() and the collection get updated with pervious data + new data but right now its getting overwritten.
Also is it okay to instantiate new collection from the modelfetch ?
You shouldn't need to make a new view. You should instead listen to the "add" event being triggered on the collection and render new items accordingly.
nextSet: function(){
this.fetch({add : true}); // The add option appends to the collection
}
This option is detailed in the very good documentation.

Resources