I have a model as defined below
class Colors extends Backbone.Model
name: -> [#get("name")]
value: -> [#get("value")]
Collection as defined below
class #ColorsCollection extends Backbone.Collection
model: Colors
Select tag as define below
%select{name: "colorslist" type: "hidden" value: "" }
Upon an event, I want to dynamically populate the colorslist select options with data fetched from ColorsCollection.
I have been looking into select2 documentation but unable to find any relevant examples.
Basically, you will bind to the reset event and replace the html and start the select2 plugin.
I know the plugin has some internal ways of doing it - but why deal with having to comb through the documentation.
class View extends Backbone.View
initialize: ->
#collection = new ColorsCollection
# Bind to reset event
#listenTo #collection, "reset", #updateSelect
#collection.fetch()
updateSelect: (collection) ->
# Use template engine (eg. Handlebars) to redraw the html
#$el.find('#selection').html tmpl(#collection)
# Start select2
#$el.find('#selection > select').select2()
Related
I'm trying to follow a Backbone Rails tutorial and I'm getting stuck trying to render my collection of links in a CompositeView, no nesting involved. I suspect that tutorial is drastically outdated, but since I yet lack Backbone skills I can't pin point the problem. Please, take a look at the following code:
Creating a collection of navigational links.
#TestApp.module "Entities", (Entities, App, Backbone, Marionette, $, _) ->
class Entities.Navigation extends Backbone.Model
class Entities.NavigationCollection extends Backbone.Collection
model: Entities.Navigation
API =
getLinks: ->
new Entities.NavigationCollection [
{ name: "one" }
{ name: "two" }
{ name: "three" }
{ name: "four" }
{ name: "five" }
]
App.reqres.setHandler "navigation:entities", ->
API.getLinks()
Core navigation file.
#TestApp.module "NavigationUnit", (NavigationUnit, App, Backbone, Marionette, $, _) ->
#startWithParent = false
API =
listNavigation: ->
NavigationUnit.List.Controller.listNavigation()
NavigationUnit.on "start", ->
API.listNavigation()
Controller, where I'm passing collection to the view.
#TestApp.module "NavigationUnit.List", (List, App, Backbone, Marionette, $, _) ->
List.Controller =
listNavigation: ->
links = App.request "navigation:entities"
navigationView = #getNavigationView links
App.navRegion.show navigationView
getNavigationView: (links) ->
new List.Navigation
collection: links
And the view.
#TestApp.module "NavigationUnit.List", (List, App, Backbone, Marionette, $, _) ->
class List.NavigationLinks extends Marionette.ItemView
template: "navigation/list/templates/_links"
tagName: "li"
class List.Navigation extends Marionette.CompositeView
template: "navigation/list/templates/list_navigation"
itemView: List.NavigationLinks
itemViewContainer: "ul"
Content of the ItemView template is %a{:href => "#"}= #name. And in the CompositeView is a basic wrapper structure with the %ul tag. Now what happens is that the CompositeView renders the template as expected, but it does not populate the %ul with the itemView. Instead it creates amount of divs equals to the amount of models in the collection (five in this case) and inserts there entire wrapper templates, so it looks like this:
#navRegion
.div
.navigation-wrapper
.navigation-content
%ul
.div
.navigation-wrapper
// entire template
.div
.navigation-wrapper
// entire template
//etc +3 divs
What am I doing wrong here?
Your tutorial is probably out of date. Marionette renamed the property from itemView to childView in version 2.0.0.
From the docs
Each childView will be rendered using the childView's template. The CompositeView's
template is rendered and the childView's templates are added to this.
var ChildView = Marionette.ItemView.extend({});
var CompView = Marionette.CompositeView.extend({
childView: ChildView
});
I have two models, User and Picture. User has many Pictures. I want to make a suspend call to backend server query on Picture. Currently when I hit the suspend button I get the User model but I want picture model. In my User view I have following code.
USER VIEW
class MyApp.Views.User extends Backbone.View
initialize: ->
#listenTo(#model, 'change', #render)
#listenTo(#model, 'destroy', #remove)
render: ->
$(#el).html(#template(user: #model))
#fetchPictures()
this
fetchPictures: ->
#picture_collection = new MyApp.Collections.Pictures()
#picture_collection.fetch({
reset: true,
data: { "user_id": #model.get("objectId") }#,
success: (e) ->
for picture in e.models
view = new MyApp.Views.Picture(model: picture)
$("#objects-info").html(view.render().el)
})
PICTURE VIEW
class MyApp.Views.Picture extends Backbone.View
template: JST['flagged_objects/picture']
el: 'td'
events: ->
"click #Picure": "deletePicture"
initialize: ->
#model.set('id', this.model.get('objectId'))
#listenTo(#model, 'change', #render)
#listenTo(#model, 'destroy', #remove)
render: ->
$("#object-info").append(#template(entry: #model))
this
deletePicture: (e) ->
e.preventDefault()
console.log #
PICTURE COLLECTION
class MyApp.Collections.Pictures extends Backbone.Collection
model: MyApp.Models.Picture
url: "/api/pictures"
PICUTRE MODEL
class MyAdmin.Models.Picture extends Backbone.Model
urlRoot: 'api/picture'
idAttribute: 'objectId'
In USER VIEW in #model variable I get User model. Is there any way to get Picture model here so that I can send call to suspend the picture.
In summary I just want to suspend picture model obejct from collection when I press suspend button. Suspend essentially is an update call.
Thanks,
So as we have spoken in the comments, the deletePicture function should be in the Picture sub-view as what you want to suspend is a Picture model.
I think the strange behaviour you are having it's related to the way you are rendering your views.
In the user view you should append the Picture sub-views.
fetchPictures: ->
#picture_collection = new MyApp.Collections.Pictures()
#picture_collection.fetch({
reset: true,
data: { "user_id": #model.get("objectId") }#,
success: (e) ->
for picture in e.models
view = new MyApp.Views.Picture(model: picture)
$("#objects-info").append(view.render().el)
})
And it's in the render of the sub-view where you get access to the html function.
render: ->
this.$el.html(#template(entry: #model))
this
Let me know how it goes!
I have 2 models, implemented via backbone.relational and backbone.localstorage, they're working good.
and I have 2 views, first is a "single item" viewer and the second one is an item view with a render function to view my single item view in the way I want, the problem is events not working, neither in parent view nor in single item view.
I've reimplemented that code in the similar way to show you how it's not working ( code is in coffeescript ) :
log = console.log
class $.Girl extends Backbone.RelationalModel
localStorage: new Backbone.LocalStorage 'gals'
initialize: -> if typeof #get('id') is 'undefined' then #save() else #fetch()
class $.Girls extends Backbone.RelationalModel
localStorage: new Backbone.LocalStorage 'gals'
relations:[{
type: Backbone.HasMany
key: 'gals'
relatedModel: $.Girl
includeInJson: 'id'
}]
initialize: ->
if typeof #get('id') is 'undefined' then #save() else #fetch()
#fetchRelated()
class $.GirlView extends Marionette.ItemView
tagName: 'tr'
template: (data)-> '<td>'+data.name+' -- '+data.age+'<button>Love</button></td>'
initialize: ->
#listenTo #model,'change',#render
events:
'click button': 'sayLove'
sayLove : -> log 'I Love YOU!'
class $.GirlsView extends Marionette.ItemView
template: (data)->
'<table>
<thead><tr><th>My Gals</th></tr></thead>
<tbody></tbody>
<tfoot><tr><td>I Love Them!</td></tr></tfoot>
</table>'
initialize: (options)->
#models = #model.get('gals').models
#list = []
self = #
_.each #models,(girl)-> self.list.push new $.GirlView {model:girl}
events:
'click th': 'hello'
render: ->
#$el.html(#template {})
self = #
_.each #list,(girl)->
girl.delegateEvents()
self.$('tbody').append girl.render().$el
hello: -> log 'hello'
gal1 = new $.Girl {name:'gal1',age:'22',id:'gal-1'}
gal2 = new $.Girl {name:'gal2',age:'19',id:'gal-2'}
gals = new $.Girls {title:'maGals',id:'gals-1',gals:['gal-1','gal-2']}
gv = new $.GirlsView {model:gals}
gv.render()
$('body').append gv.$el.html()
It's kinda hello world for me.
Any idea how can I implement nested itemViews with events working or any other idea for this snippet is appreciated.
Try calling delegateEvents after appending your child views:
self.$('tbody').append girl.render().el
girl.delegateEvents()
// or maybe #delegateEvents()? the context should be the child here
Edit:
Change $('body').append gv.$el.html() to $('body').append #$el.
I've followed Ryan Bates' example on Backbone.js to start a project using Backbone + Eco. It's great. However, I'm stuck trying to display a nested attribute.
For example, I'm trying to do this: <%= #stream.user.get('name') %> in index.jst.eco
and I'm getting Uncaught TypeError: Cannot call method 'get' of undefined
However, I can get <%= #stream.get('stream_type') %> to work.
Here's the REST API data:
[
: {
: : "id":"5004095283de4ca9ff000005",
: : "created_at":"2012-07-16T12:30:10Z",
: : "stream_type":"project",
: : "user":
: : {
: : : "id":"5002f30560de7d0ffb000003",
: : : "name":"Regular User2"
: : },
...
I've also tried extending my Model using Backbone.DeepModel but that didn't seem to work.
class Project1.Collections.Streams extends Backbone.Collection
url: '/streams'
model: Topaz.Models.Stream
class Project1.Models.Stream extends Backbone.DeepModel
Here's my views on the collection, pretty standard.
class Project1.Views.StreamsIndex extends Backbone.View
#views/streams/index.js
template: JST['streams/index']
initialize: ->
#collection.on('reset', #render, this)
#collection.on('add', #appendStream, this) #rerenders entire template
render: ->
$(#el).html(#template())
#collection.each(#appendStream)
this
appendStream: (stream) =>
view = new Topaz.Views.Stream(model: stream)
#$('#streams').append(view.render().el) # looks for the #entries element within the view’s element and not on the page directly
and here's the View for the model
class Project1.Views.Stream extends Backbone.View
template: JST['streams/show']
className: 'stream-item'
initialize: ->
#model.on('change', #render, this) #The change event is triggered by Backbone when a model saves
render: ->
$(#el).html(#template(stream: #model))
this
I'm creating a backbone view for displaying a list of folders created by user in my webapp. but I want to have a default entry like no folder to be displayed in the list as well.
Instead of inserting the DOM inside the view, I want to just add a model to the collection which does not get synced to server but is just used to be rendered in the view.
Is there a way I can do this? I tried this an failed...
var def = {'name': 'none', 'selected': 'true'};
var coll = new app([def]);
// model here
var appitem = Backbone.Model.extend({
defaults: {
name: '',
id: '',
selected: 'false'
}
});
// collection here
app = Backbone.Collection.extend({
model: appitem,
url: '/apps'
});
You should not alter your models based on what the view needs.
If you need to display a 'no folder' entry, than it belongs in the view.
Don't complicate your life by adding data without meaning to the model layer. Keep it in the view.