Change event do not catch option chosen selected, Backbone - backbone.js

Having the following view:
someView = Backbone.View.extend({
events : {
'change #selectID' : 'checkSelect'
},
checkSelect : function(e) {
console.log(e);
}
});
I wonder if possible to the selected option from the select tag, considering this select is rendered with data injected from a collection.
Any help?

You can get the value of the select with $(e.target).val() as in:
var MyView = Backbone.View.extend({
events : {
'change #selectID' : 'checkSelect'
},
checkSelect : function(e) {
var selectValue = $(e.target).val();
console.log(selectValue);
}
});
Check this fiddle

Related

click event didn't work in backbone

define(["jquery" ,
"underscore" ,
"backbone" ,
"custom",
"wishlist"
],function($ , _ , Backbone, Ice, WishList){
var wishlist1 = new WishList();
var SavedCartView = Backbone.View.extend({
tagName:"div",
initialize : function(){
console.log("hi!");
},
event : {
'click .savedCart' : 'viewEachCart'
},
viewEachCart : function(e){
console.log(1);
},
render : function(){
wishlist1.viewAllSaveCart(106,function(output){
_.each(output,function(row){
$("#webbodycontainer").append('<a class="savedCart" id="'+row.ID+'">'+row.Name + "</a><br>");
});
});
}
});
return SavedCartView;
});
Here is the router :
app_router.on('route:savedCart', function( ){
if(window.currentSection)
window.currentSection.remove();
window.currentSection = new SavedCart({});
$("#webbodycontainer").html(window.currentSection.$el);
window.currentSection.render();
});
console.log(1); didn't work, Any idea what could be causing this. Thanks.
I think this should be events : {
If ".savedCart" is an anchor tag (like this):
Saved Cart
...then you need to have e.preventDefault() in your function so that the link is not activated.
events : {
'click a.savedCart' : 'viewEachCart'
},
viewEachCart : function(e){
e.preventDefault();
console.log(1);
},

event in itemView trigger show CompositeView

In formView inside the newAttributes method i would like to trigger an event that will then show the entry view(both are shown here). In order to do this should I use a controller? It seems no matter how I set the trigger and listenTo commands up I get a different error.
MyApp = new Backbone.Marionette.Application();
MyApp.addRegions({
formBox : '#formBox',
listBox : '#listBox'
});
Entry = Backbone.Model.extend({
defaults: {
DB : 'not specified',
CT : 'not specified',
go : 'not specified'
},
});
EntryList = Backbone.Collection.extend({
model: Entry
});
FormView = Backbone.Marionette.ItemView.extend({
tagName: 'div',
template: '#form-template',
className: 'form',
ui: {
DB: '#DB',
CT: '#CT',
gos: '#gos'
},
events:{
'click #processInput' : 'validateForm'
},
onRender: function(){
console.log("rendering...");
},
validateForm : function(){
var validInput = true;
if(!this.ui.DB.val().trim())
{
validInput = false;
!this.ui.DB.css("background-color","#CC0000");
}
else
{
!this.ui.DB.css("background-color","#ffffff");
}
if(!this.ui.CT.val().trim())
{
validInput = false;
this.ui.CT.css("background-color","#CC0000");
}
else
{
this.ui.CT.css("background-color","#ffffff");
}
if(!this.ui.gos.val().trim())
{
validInput = false;
this.ui.gos.css("background-color","#CC0000");
}
else
{
this.ui.gos.css("background-color","#ffffff");
}
if(validInput)
{
this.hideForm();
this.getEntries(this.ui.DB.val().trim(),
this.ui.CT.val().trim(),this.ui.gos.val().trim());
}
},
newAttributes :function(db,con,gos){
for(go in gos)
{
MyApp.ents.add({DB : db, CT: con, go: gos[go]});
}
//TRIGGER CUSTOM EVENT
},
getEntries : function(db,con,gos){
var gos = gos.split("\n");
for(go in gos)
{
console.log("data bank: " + db + " CT: " + con + " go: |" + gos[go].trim()+"|");
}
this.newAttributes(db,con,gos);
},
hideForm : function(){
this.$el.hide();
}
});
EntryView = Backbone.Marionette.ItemView.extend({
tagName: 'tr',
template: '#entry-template',
className: 'entry',
events: {
'click .delete' : 'destroy'
},
destroy : function(){
this.model.destroy();
}
});
EntriesView = Backbone.Marionette.CompositeView.extend({
tagName: 'table',
template: '#entries-template',
itemView: EntryView,
appendHtml: function(collectionView, itemView){
colleCTionView.$('tbody').append(itemView.el);
}
});
MyApp.addInitializer(function(test){
var entriesView = new EntriesView({
collection: test.DB
});
var formView = new FormView();
//SHOW on load
MyApp.formBox.show(formView);
//SHOW Later with custom event
MyApp.listBox.show(entriesView)
});
$(document).ready(function(){
MyApp.ents = new EntryList([]);
MyApp.start({DB: MyApp.ents});
});
There are 2 ways you can solve your problem.
The cleanest way is to use a controller, and listen for the triggered event on the view instance within the controller. E.g. in your view, have this.trigger("my:event"), then in your controller have myFormViewInstance.on("my:event", function(...){...})
Another option (which wouldn't really be recommended), is to trigger the event at the application level, and listen for it elsewhere also on the application level. I.e. MyApp.trigger("my:event") and MyApp.listen("my:event")

Controller listenTo breaks when in callback method

I have the problem that the event "form:selectedForm" is calling the method "showForm" but when sending this to my view I am getting the following error: TypeError: e[t] is not a function.
This is stated in line 128 in the backbone.js script but I have no clue what he is doing there. It looks like that he is looking for a "to" or "on" event on the collection.
What I am doing wrong here?
MyController = Backbone.Marionette.Controller.extend({
initialize: function(options) {
this.options = options;
this.urls = options.urls;
this.mainRegion = options.mainRegion;
this.view = new MyLayout();
this.mainRegion.show(this.view);
this.view.render();
this.showSelectorView(this.view.formHeader);
},
showSelectorView : function(view) {
var forms = new MyForms();
forms = this.urls.loadForms;
var selectorView = new FormSelectorView({
collection: forms
});
forms.fetch();
this.listenTo(selectorView, "form:selectedForm", this.showForm);
view.show(selectorView);
},
showForm : function(models) {
console.log("showForm");
var form = new FormContentView({
collection: models
});
this.view.form.show(form);
}
});
MyLayout = Backbone.Marionette.Layout.extend({
template: Backbone.Marionette.TemplateCache.get('#content'),
regions: {
formHeader: "#selector",
form: "#formContent",
formContent: "#content",
formFooter: "#save",
formTemplates: "#templates"
}
});
FormSelectorView = Backbone.Marionette.ItemView.extend({
template: Backbone.Marionette.TemplateCache.get('form-selector-template'),
events : {
"click option" : "selectForm"
},
initialize : function() {
this.listenTo(this.collection, "sync", this.render, this);
},
selectForm : function(e) {
e.preventDefault();
var id = $(e.currentTarget).attr("name");
var item = this.collection.get(id);
this.trigger("form:selectedForm", item.attributes.fields);
}
});
I think the error is in your showSelector view function, you are overwriting your forms collection in the second line,
i think your intention in that line was to assing the url of the forms collection so my guess is that this will fix it:
showSelectorView : function(view) {
var forms = new MyForms();
forms.url = this.urls.loadForms; /// Im assuming you were trying to pass the url here
var selectorView = new FormSelectorView({
collection: forms
});
forms.fetch();
this.listenTo(selectorView, "form:selectedForm", this.showForm);
view.show(selectorView);
},

Backbone, one field not set when calling view.render after model.save

I have the following problem. On a user-event (click on .twitterDefault) I call save event with
twitter : {
handle : handle,
ignore : false
}
Then the success function gets called and I set fields on the model (klout, twitter and tester). All fields are set (logging statements all print out appropiate objects.
However, then I call view.render() and here twitter is not set anymore. I have no idea why, there is no sync happening after the save so twitter does not get overwritten (additionally I made sure twitter is also saved on the server before the success method gets called).
Any help greatly appreciated!
Code as follows (stripped to improve readability)
$(function() {
var ContactModel,
ContactModelCollection,
ContactView,
ContactCollectionView,
contacts,
contactCollectionView;
//base model
ContactModel = Backbone.Model.extend({
defaults : {
},
initialize : function() {
}
});
ContactModelCollection = Backbone.Collection.extend({
model : ContactModel,
url : '/api/contacts',
comparator : function(contact) {
return contact.get('strength_of_relationship');
},
initialize : function() {
}
});
ContactView = Backbone.View.extend({
tagName : 'li', //attempting to create a new element
render: function() {
var compiled_tmpl = _.template($('#contact-template').html());
var html = compiled_tmpl(this.model.toJSON());
console.log('model.get("twitter")=('+JSON.stringify(this.model.get('twitter)'))+')');
console.log('model.get("klout")=('+JSON.stringify(this.model.get('klout'))+')');
console.log('model.get("tester")=('+JSON.stringify(this.model.get('tester'))+')');
this.$el.html(html);
console.log('rendered view successfully)');
return this;
},
initialize: function() {
console.log('contactView initalized');
this.model.bind('change', this.render, this);
this.model.bind('destroy', this.remove, this);
},
events: {
'click .twitterDefault' : 'assignDefaultTwitterHandle',
},
assignDefaultTwitterHandle : function(event) {
var handle = $(event.currentTarget).data('twitter');
this.assignTwitterHandle(handle);
},
assignTwitterHandle : function(handle) {
console.log('model assignTwitterHandle. handle='+handle+')');
var view = this,
model = view.model;
model.save({
twitter : {
handle : handle,
ignore : false
},
id : model.get('id')
}, {
error : function() {
console.log('saving twitter handle failed');
},
success : function(model, response) {
console.log('response=('+JSON.stringify(response)+')');
if(response.error) {
console.log('error on server ='+response.error);
}
if(response.twitter) {
console.log('twitter is set');
var twitter = {
handle : handle,
tweet : response.twitter,
age : new Date()
};
console.log('setting twitter to '+JSON.stringify(twitter));
model.set('twitter', twitter);
model.set('tester', 'tester');
console.log('twitter after setting it = '+JSON.stringify(model.get('twitter')));
console.log('view\'s model twitter after setting it = '+JSON.stringify(view.model.get('twitter')));
}
if(response.klout) {
console.log('klout is set');
var klout = {
topics : response.klout
}
console.log('setting klout to '+JSON.stringify(klout));
model.set('klout', klout);
}
if(response.twitter || response.klout) {
console.log('Rerendering view after setting klout/twitter');
view.render();
}
}
});
}
});
contacts = new ContactModelCollection;
ContactCollectionView = Backbone.View.extend({
el : $('#suggestions-list'),
initialize : function(){
contacts.bind('add', this.addOne, this);
contacts.bind('reset', this.addAll, this);
contacts.bind('all', this.render, this);
},
render : function(){
console.log('contactcollectionview render');
},
addOne : function(contact) {
console.log('addOne');
var view = new ContactView({model: contact});
var el = view.render().el;
console.log('el=('+el+')');
$('#suggestions-list').append(el);
},
addAll : function() {
console.log('addAll');
contacts.each(this.addOne);
}
});
contactCollectionView = new ContactCollectionView;
App.contacts = contacts;
App.contactCollectionView = contactCollectionView; });
I guess the problem is the scope of the render function.
Depending from where is called, this takes a different value.
To warranty that always this is pointing to the View scope, add to your initialize:
_.bindAll(this,"render");
Also, it's not good habit to call view.render manually. You should let the events do their work. Model save already triggers some events. Just listen to them to update your View.

How to bind elements in backbone?

I have a small backbone class:
view = Backbone.View.extend({
events: {
"click textarea" : "doSomething"
},
doSomething : function() {
var textarea = $(this.el).find('textarea')
// I would like to just call, this.textarea, or this.elements.textarea
}
});
Ideally I would like to be able to access my textarea through a variable instead of having to search the element every time. Anyone have any idea on how to accomplish this?
maybe i am under thinking it but how bout giving the textarea a class or id and target specifically when needed,
or create a sub view that generates the textarea
var View = Backbone.View.extend({
el: '#main',
initialize: function(){
this.render();
},
render: function() {
var subview = new SubView();
this.$('form').append(subview.el);
this.$('form').show();
},
});
var SubView = Backbone.View.extend({
tagName: 'textarea',
id: 'whateverId',
events: {
"click" : "doSomething"
},
initialize: function(){
this.render();
},
doSomething : function(event) {
var textarea = $(event.target);
// or var textarea = $(this.el);
},
render: function(){
return $(this.el);
}
});
The other answers get you the reference that you need, but if you really need a handle to the textarea, then you can do something like this:
view = Backbone.View.extend({
initialize: function() {
this.myTextareaElement = $(this.el).find('textarea')
}
events: {
"click textarea" : "doSomething"
},
doSomething : function() {
// use this.myTextareaElement ...
}
});
pass the event as the argument and then use the event target
view = Backbone.View.extend({
events: {
"click textarea" : "doSomething"
},
doSomething : function(event) {
var textarea = $(event.target);
}
});

Resources