I am trying to use template.find to make my life easier.
But in the javascript console I get: undefined is not a function
Here's what I have. It is getting tripped up on template.find(...)
Template.superuserHUD.events =
{
'click input.new_device': function (template) {
var id = template.find(".new_device_id").value;
Device_IPs.insert({ID: id, IP: "Not Connected"});
}
}
Any ideas?
The Event handler function receives two arguments: event, an object with information about the event, and template, a template instance for the template where the handler is defined.
The second parameter is optional, but it needs to be received in handler when you want to use template instance functions like find(), findAll(), firstNode() and lastNode().
So, to use the template.find() in your event handler, you need to pass both the arguments as:
'click input.new_device': function (event, template) {
// your event handling code
}
use a second arugment please like
Template.superuserHUD.events
'click input.new_device': (event, template) ->
options =
id: template.find('.new_device_id').value
IP: 'Not Connected'
Device_IPs.insert options
and sometimes use template itself like
Template.superuserHUD.events
event: (event, template) ->
#find('.new_device_id').value
Here's the same in javascript for the coffee illiterate...
Template.superuserHUD.events({
'click input.new_device': function(event, template) {
var options;
options = {
id: template.find('.new_device_id').value,
IP: 'Not Connected'
};
return Device_IPs.insert(options);
}
});
Template.superuserHUD.events({
event: function(event, template) {
return this.find('.new_device_id').value;
}
});
Related
I have a backbone/backgrid editable grid, and everytime I edit a cell the "change" event is fired up twice and I end up making two separate PUT requests.
I know that this happens because the "change" event fires once when I edit it in the cell, and another when the data comes back from the server; and that the behaviour could be avoided by passing {wait: true} to the save method, but I don't know where I need to overload it.
My model declaration is like this:
var Redirects = Backbone.Model.extend({
urlRoot: '/global/redirects',
initialize: function () {
Backbone.Model.prototype.initialize.apply(this, arguments);
this.on("change", function (model, options) {
if (options && options.save === false) return;
model.save({
error: alertMe
});
});
this.on('fetch request', function (e) {
loadingOn(e);
});
this.on('sync error', function (e) {
loadingOff(e);
});
this.on('error', function(e, resp){
alertMe(e, resp);
});
}
});
You shouldn't receive a 2nd change event when a Model is synced from the server, regardless of the wait option.
The problem in your save call is that you haven't specified the attributes hash, i.e. the first parameter. If you don't have any attributes to modify, which considering you are firing save for a change event, that's probably the case, you will need the following:
this.on("change", function (model, options) {
if (options && options.save === false) return;
model.save(null, {error: alertMe});
});
What was actually happening was that you were setting error as an attribute on the model, and that triggered the change event.
I want to dynamically create event listeners in an angularjs service, however it seems that each $rootScope.$on event listener I create in the for loop in the service is overwritten by the following event listener. How can I dynamically create $rootScope.$on even listeners without overwriting the previous event listener? I create events using broadcasts from my controller like $rootScope.$broadcast(EVENTS.userDeleteSuccess.event);.
My EVENTS constant looks like:
myApp.constant('EVENTS', {
userDeleteSuccess: {
event: 'user-delete-success',
type: 'success',
message: 'User successfully deleted'
},
...,
siteDeleteSuccess: {
event: 'site-delete-success',
type: 'success',
message: 'Site successfully deleted'
}
}
My service looks like:
myApp.service("Alert", function($rootScope, EVENTS) {
var show = function(type, message) {
$rootScope.alert = {
type: type,
message: message,
show: true
};
};
// Initialized on application startup, this is the problem method!
this.initialize = function() {
for(var event in EVENTS) {
if(!EVENTS.hasOwnProperty(event)) break;
var _event = EVENTS[event];
$rootScope.$on(_event.event, function() {
show(_event.type, _event.message);
});
}
};
return this;
});
The only event that ever gets broadcasted is always the last event in the object (siteDeleteSuccess in this case). How can I dynamically create an event listener in a for loop that doesn't overwrite the previous $rootScope.$on event listener?
You can do two things use an IIFE or just bind the argument(s) so they get passed into the function
IIFE
(function(event){
$rootScope.$on(event.event, function() {
show(event.type, event.message);
});
})(_event);
Binding:
$rootScope.$on(_event, function(event) {
show(event.type, event.message);
}.bind(null,_event));
bind docs
I have a template with helpers and events like:
Template.myTemplate.helpers({
edit: function () {
console.log('helper');
return this.value;
}
});
Template.myTemplate.events({
'click .edit_button': function () {
console.log('click');
// Toggle the value this.value
}
});
Through the logs (simplified here) I can verify that the helper is called when the template is rendered on the page. However, when the event is fired the helper console message is not fired. It as though the event changing the value does not trigger processing of the helper, making the page not very reactive.
I have tried to assign a reactive variable and use it, to no avail.
Template.myTemplate.rendered = function () {
this.value = new ReactiveVar();
}
// Setting and getting using the .get()/.set() methods.
How does one cause the helpers to be reprocessed from an event?
In events you want to set value to ReactiveVar object.
In helpers you simply return that value of this object, helpers behaves like Tracker.autorun, they are reactive.
Template.myTemplate.helpers({
edit: function () {
console.log('helper');
// helpers are wrapped with Tracker.autorun, so any ReactiveVar.get()
// inside this function will cause to rerun it
return Template.instance().value.get()
}
});
Template.myTemplate.events({
'click .edit_button': function (e, tmpl) {
console.log('click');
// here you save value
tmpl.value.set(newValue)
}
});
Template.myTemplate.created = function () {
this.value = new ReactiveVar();
}
I'm using require.js with backbone.js to structure my app. In one of my views:
define(['backbone', 'models/message', 'text!templates/message-send.html'], function (Backbone, Message, messageSendTemplate) {
var MessageSendView = Backbone.View.extend({
el: $('#send-message'),
template: _.template(messageSendTemplate),
events: {
"click #send": "sendMessage",
"keypress #field": "sendMessageOnEnter",
},
initialize: function () {
_.bindAll(this,'render', 'sendMessage', 'sendMessageOnEnter');
this.render();
},
render: function () {
this.$el.html(this.template);
this.delegateEvents();
return this;
},
sendMessage: function () {
var Message = Message.extend({
noIoBind: true
});
var attrs = {
message: this.$('#field').val(),
username: this.$('#username').text()
};
var message = new Message(attrs);
message.save();
/*
socket.emit('message:create', {
message: this.$('#field').val(),
username: this.$('#username').text()
});
*/
this.$('#field').val("");
},
sendMessageOnEnter: function (e) {
if (e.keyCode == 13) {
this.sendMessage();
}
}
});
return MessageSendView;
});
When keypress event is triggered by jquery and sendMessage function is called - for some reason Message model is undefined, although when this view is first loaded by require.js it is available. Any hints?
Thanks
Please see my inline comments:
sendMessage: function () {
// first you declare a Message object, default to undefined
// then you refrence to a Message variable from the function scope, which will in turn reference to your Message variable defined in step 1
// then you call extend method of this referenced Message variable which is currently undefined, so you see the point
var Message = Message.extend({
noIoBind: true
});
// to correct, you can rename Message to other name, e.g.
var MessageNoIOBind = Message.extend ...
...
},
My guess is that you've bound sendMessageOnEnter as a keypress event handler somewhere else in your code. By doing this, you will change the context of this upon the bound event handler's function being called. Basically, when you call this.sendMessage(), this is no longer your MessageSendView object, it's more than likely the jQuery element you've bound the keypress event to. Since you're using jQuery, you could more than likely solve this by using $.proxy to bind your sendMessageOnEnter function to the correct context. Something like: (note - this was not tested at all)
var view = new MessageSendView();
$('input').keypress(function() {
$.proxy(view.sendMessageOnEnter, view);
});
I hope this helps, here is a bit more reading for you. Happy coding!
Binding Scopes in JavaScript
$.proxy
I tried to create a simple solution for ordering problem in async calls on a project I'm working on.
The best solution I found was this:
I attach an event that check if the pre-requirements are done, if so I remove the event listener and perform the function.
Each function calls the event once its done and that way everyone will be waiting until the can run.
This is the code:
$(function() {
$(document).on('bmadone',function() {
if(beepmeapp.done_arr['fb-init']){
$(document).off('bmadone','#bma-root',this);
getBMAUserRoutes();
}
});
});
The function (for the test) is doing this:
function getBMAUserRoutes(){
$.ajax({
url : '/bma/users/fb',
type : 'GET',
data : {
access_token: 'abc'
},
success : function( data ) {
console.log('getBMAUser: success');
beepmeapp.done_arr['user-init'] = true;
$('#bma-root').trigger('bmadone');
},
error : function( xhr, err ) {
console.log('getBMAUser: error');
}
});
}
It works great but the problem I have is that it gets into a loop that never ends.
Don't know why but it looks like:
$(document).off('bmadone','#bma-root',this);
Doesn't remove the listener...
I'm a true newbie in JS / Jquery and all of this client side development so I guess I'm probably missing something basic.
You have to pass the same (sub)set of parameters to .off that you passed to .on. I.e. in your case it would be $(document).off('bmadone').
You never passed '#bma-root' to .on and this does not refer to the event handler (the function you pass to .on), so by passing those you won't remove the correct event handler.
If you need to remove only that specific handler, you can use a named function instead:
function handler() {
if(beepmeapp.done_arr['fb-init']){
$(document).off('bmadone', handler);
getBMAUserRoutes();
}
}
$(document).on('bmadone', handler);
// or as a named function expression
$(document).on('bmadone', function handler() {
if(beepmeapp.done_arr['fb-init']){
$(document).off('bmadone', handler);
getBMAUserRoutes();
}
});
or use namespaced events.