I have a list of items and a query textfield. When I enter a query in the textfield, I want to filter the list of items based on the query. How can I do this?
In the view I added an event:
events: ->
'submit #query_form' : 'filterLinks'
This triggers a function where I first empty the list and then want to show only the items which meet the query criteria:
filterLinks: ->
query = $('#query').val()
#collection.reset()
How can I filter the list?
Edit: This is the complete view:
template: JST['links/index']
initialize: ->
#collection.on('reset', #render, this)
#collection.on('add', #appendLink, this)
events: ->
'submit #new_link' : 'createLink'
'submit #query_form' : 'filterLinks'
render: ->
$(#el).html(#template())
#collection.each(#appendLink)
this
createLink: (event) ->
event.preventDefault()
#collection.create
title: $('#title').val()
description: $('#description').val()
url: $('#url').val()
category: $('#category').val()
votes: 0
$('#message').append('<div>Link has been added succesfully!</div>').fadeOut(5000)
appendLink: (link) ->
view = new Hotlynx.Views.Link(model: link)
$('#all_links').append(view.render().el)
filterLinks: ->
alert($('#query').val())
#collection.reset()
You can use underscore's filter method to filter the collection and return only the results you want. See: http://underscorejs.org/#filter
Then you'd use the result of this filter to re-render the view that displays the items.
You could just re-render and do something like this:
appendLink: (link) ->
if( link.get('someAttribute') === this.filterValue)
view = new Hotlynx.Views.Link(model: link)
$('#all_links').append(view.render().el)
Related
I have a composite view which consist of item view. I need to capture the events of item view, what I am trying to capture is specific item view capture as I am rendering a pop up modal on click of button in item view. The Modal needs to contains the details of item for which it is clicked. Whats happening is if I put the event capture in either or item or composite view with query selector of buttons (this button has hidden span of item id) it always selects the first items.
Sounds like it is doing right thing as the item view repetition in composite view is not changing the id of buttons (even if the hidden span has different id).
Quesiton is how do I achieve capturing specific item events with attributes captures.
code below :
ItemView:
var regItemView = Marionette.ItemView.extend({
template: ProgramRegistraionMainItemView,
tagName: 'div',
className : 'accordion_in',
events : {
'click #subbtn' : function () {
var prgid = $('#regid').html();
var rate = $('#rate').html(); MyApp.mainregion.currentView.appcontent.currentView.maincontent.currentView.contentregion1.currentView.prgregmainmodal.show(new ProgramRegistrationModalView({selectedprgid : prgid,rate: rate}));
}
}
});
Composite View
var RegistrationView = Marionette.CompositeView.extend({
itemView : regItemView,
itemViewContainer: "#mainaccordion",
template : ProgramRegistraionMainCollectionView,
initialize : function(programcollection)
{
this.collection = programcollection;
this.model =null;
},
model : this.model,
collection : this.collection,
showAccord : function () {
//console.log("In Accodian show"+$("#mainaccordion").html());
$("#mainaccordion").smk_Accordion({
showIcon: true, // Show the expand/collapse icons.
animation: true, // Expand/collapse sections with slide aniamtion.
closeAble: true, // Closeable section.
slideSpeed: 200, // the speed of slide animation.
closeOther : false
});
}
Aim is to get the program id of the clicked item (rendered through item view).
From your regItemView's event hash, it looks like the issue is with using an html id for the jQuery event handler. id's are supposed to be unique across the whole page but you have repeated it for each ItemView. Change it to a class or an element name (if you've only got one per item view):
var regItemView = Marionette.ItemView.extend({
template: ProgramRegistraionMainItemView,
tagName: 'div',
className : 'accordion_in',
events : {
'click button' : 'showModal'
},
showModal: function () {
// Show modal somehow
// you can access the model in here as this.model
}
});
Marionette sets the event handler context as the item view so you can simple access the model as this.model. This is better than adding data-id tags into your HTML to retrieve the model.
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 a dynamic form where I am starting with a drop-down field with two values: bar chart and trend chart. If bar chart is selected I want to show a multi-select drop-down box for the dimension values while if trend chart is selected I want to show a single-select drop-down box.
With the template and model shown below, the multi-select box is only shown after the module is saved the first time. How can I get the isBarChart variable to be set so I can use it to determine if the select box shown should be multi-select or single-select before the module has been saved.
Thanks.
From the template:
%div.select_module_type
Module type:
%select{ :class => "module_type" }
{{#select module_type}}
%option{ :value => '' }
%option{ :value => 'bar_chart' } Bar chart
%option{ :value => 'trend_chart' } Trend chart
{{/select}}
%div.select_dimension_value
Dimension value:
{{#if isBarChart}}
%select.dimension_value{ 'multiple' => true }
{{#select dimension_value}}
{{/select}}
{{else}}
%select.dimension_value
{{#select dimension_value}}
{{/select}}
{{/if}}
From the model:
isBarChart: ->
return #get('module_type') == 'bar_chart'
From the view:
showDimensionValuesSelector: (e) ->
$(#el).find('div.select_dimension_value').hide()
$(#el).find('div.date').hide()
this_selector = $(#el).find('select.module_type')
table = $(#el).find('select.table').val()
return true if table == ''
dimension_selector = $(#el).find('select.dimension[data-table="'+table+'"]')
dimension = dimension_selector.val()
return true if dimension == ''
$(#el).find('div.select_dimension_value .preloader').css('display', 'inline')
$(#el).find('select.dimension_value').hide()
$(#el).find('select.dimension_value').html('')
$(#el).find('div.select_dimension_value').show()
$(#el).find('div.date[data-table="'+table+'"]').show()
self = #
$.get(
'/dashboards/'+#model.get('dashboard_id')+'/dashboard_modules/dimension_values',
{ table: table, dimension: dimension },
(data, status, xhr) ->
_.each(data, (item) ->
if item.value != null and self.model.has('dimension_value') and item.value.toString() == self.model.get('dimension_value').toString()
selected = 'selected="selected" '
else
selected = ''
$(self.el).find('select.dimension_value').append('<option '+selected+'value="'+item.value+'">'+item.name+'</option>')
)
$(self.el).find('select.dimension_value').prepend('<option value=""></option>')
$(self.el).find('select.dimension_value').show()
$(self.el).find('div.select_dimension_value .preloader').hide()
,
'json'
)
since you have a model already, you can just set the value on the model without saving it to the server:
in your view:
events: {
'change .module_type': handleModuleTypeChange
},
handleModuleTypeChange: function() {
this.model.set({
module_type: this.$el.find('.module_type').val()
});
}
then listen to your model changes, rerender the template:
//view initialize
initialize: function () {
this.listenTo(this.model, 'change', this.render);
}
I'm not sure why the select has to be rendered after the model is saved...if that's the case, you may wanna move the Dimensions part into new views.
==============================================================
EDIT: (Dec/01/2013)
A simple jsfiddle: http://jsfiddle.net/8x7rU/
this is a simple example of DOM events changing the model, and then the model changes trigger view rendering.
in this case the whole view is rerendered when the model attribute 'module_type' is changed. And, by changing the Module Type dropdown, the view is setting new 'module_type' values on the model.
lots of the DOM related logic is actually in the template, when the view rerenders, the template knows the current state of the model then render accordingly.
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()
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.