I'm trying to get an Ember.View to listen to events triggered by a contenteditable element, but am having a little trouble.
The end result I'm going for is to have the contenteditable changes bound to an Ember Object property.
Events are correctly bound using jQuery directly as given in this answer: contenteditable change events
$(function () {
$(document).on('focus', '[contenteditable]', function(event) {
var $this = $(this);
console.log("$" + event.type);
return $this;
});
$(document).on('blur keyup paste', '[contenteditable]', function(event) {
var $this = $(this);
console.log("$" + event.type);
return $this;
});
});
But event handlers that specified on the Ember.View never get called:
App.ContentEditable = Ember.View.extend({
item: App.Item.create({name:"Editable content"}),
tagName: "span",
contenteditable:"true",
attributeBindings: ["contenteditable"],
// Only event that gets triggered
click: function(){ console.log("click") },
// None of these events are triggered
focusin: function(){ console.log("focusin") },
focusout: function(){ console.log("focusout") },
keyup: function(){ console.log("keyup") },
blur: function(){ console.log("blur") },
paste: function(){ console.log("paste") },
});
I've put together a jsfiddle showing that the .on() events are logged to the console but the events on the Ember.View are not: http://jsfiddle.net/chrisconley/RqSn4/
That's because the event names in Ember are translated to a more Ember-like naming convention. This stuff happens in packages/ember-views/lib/system/event_dispatcher.js. As you can see, you have to rename your existing event handlers into keyUp, focusIn and focusOut.
The other events blur and paste are not handled by default, thats what customEvents on Ember.Application is for, see http://jsfiddle.net/pangratz666/CHVRt/
App = Ember.Application.create({
customEvents: {
blur: 'blur',
paste: 'paste'
}
});
Related
In backbone, how do you asynchronously add events, based on other events. I want to allow click handlers on a certain set of buttons, but not until their containing button is clicked. Here's how I have things set up at the moment:
var ProductsView = Backbone.View.extend({
events : {
"click .filter-options-container" : "filterOptionContainerClick"
},
filterOptionContainerClick: function(e){
$(e.currentTarget).addClass('active');
//want to add an event to all .filter-options to allow them to trigger the filterOptionClick function when clicked
},
filterOptionClick: function(e){
$('.filter-option').removeClass('active');
$(e.currentTarget).addClass('active');
$('.filter-options-container').removeClass('active');
}
});
return ProductsView;
Instead of adding click handlers for sub-buttons whenever the container is clicked, you can use another approach:
register sub-buttons' click handlers once with events map.
add boolean property to the View to store state of the container
click
toggle that property in filterOptionContainerClick handler
depends on the value of the property, allow/disallow clicking on
sub-buttons
So the code should look like this:
var ProductsView = Backbone.View.extend({
events : {
"click .filter-options-container" : "filterOptionContainerClick",
"click .filter-options" : "filterOptionClick" // register sub-buttons' click handlers
},
initialize: function() {
this.enabled = false; // state of the container click
},
filterOptionContainerClick: function(e){
this.enabled = !this.enabled;
if (this.enabled) $(e.currentTarget).addClass('active');
else $(e.currentTarget).removeClass('active');
},
filterOptionClick: function(e){
if (!this.enabled) return;
$('.filter-option').removeClass('active');
$(e.currentTarget).addClass('active');
$('.filter-options-container').removeClass('active');
}
});
Meteor offers to define eventHandlers for templates. I have a text input that a user can type, but also paste in etc.
Sofar I have used:
Template.myTemplate.events({
'keyup #inputfield': function() {
DO SOMETHING HERE
}
});
Is it possible to define something similar to jquery's "on" function?
$('#inputfield').on('change keypress paste focus textInput input', function ()
{
DO SOMETHING HERE
});
This will fire only once regardless of how many of the events occur at the same time.
You can use stopImmediatePropagation to stop additional handers:
Template.myTemplate.events({
'keyup #inputfield': function(event) {
event.stopImmediatePropagation();
}
});
or you could use jQuery plus the rendered command to achieve the same thing:
Template.myTemplate.rendered(function() {
$(this.find('#inputField')).on('change keypress paste focus textInput input', function ()
{
DO SOMETHING HERE
});
});
_.throttle should do the trick:
var handler = _.throttle(function(event) {
...
}, 1, {leading: false});
Template.myTemplate.events({
'event event anotherEvent': handler,
});
I have an event listener, and an element that triggers a custom event on click. They’re set up as follows:
$(document).on('customEventName', function(e) {
// do something
});
$(document).on('click', '[data-action]', function(e) {
e.preventDefault();
$(document).trigger( $(this).attr('action') );
});
Say I have an anchor tag (<a href="#" data-target="customEventName">) trigger the click event, how would I then get at that <a> tag and its properties in my listener? I’m wanting to get at the object to parse any additional data- attributes.
Solution 1: extraParameters
Use extraParamters parameter as second argument of trigger jQuery function.
$(document).on('customEventName', function(e, dataActionElement) {
// do something
});
$(document).on('click', '[data-action]', function(e) {
e.preventDefault();
$(document).trigger($(this).attr('action'), [$(this)]);
});
From documentation:
.trigger( event [, extraParameters ] )
event
Type: Event
A jQuery.Event object.
extraParameters
Type: Array or PlainObject
Additional parameters to pass along to the event handler.
JSFIDDLE
Solution 2: custom events
According to documentation, you also can create a custom Event where you can set the target:
Category: Event Object
jQuery’s event system normalizes the event object according to W3C standards. The event object is guaranteed to be passed to the event handler. Most properties from the original event are copied over and normalized to the new event object.
$(document).on('customEventName', function(e) {
// e.target is clicked element sent using customEvent
// do something
});
$(document).on('click', '[data-action]', function(e) {
var customEvent = $.Event($(this).attr('action'), {target: this })
$(document).trigger(customEvent);
});
JSFIDDLE
You could pass it as a parameter in trigger:
$(document).on('customEventName', function(e, target) {
// do something
});
$(document).on('click', '[data-action]', function(e) {
e.preventDefault();
$(document).trigger( $(this).attr('action'), [this] );
});
you could also try something like this:
$(document).on('customEventName', function(e) {
var target = e.target;
// do something
});
$(document).on('click', '[data-action]', function(e) {
e.preventDefault();
var customEvent = $.Event($(this).data('action'), { target: this });
$(document).trigger( customEvent );
});
is there an id for each fired event?
I am yet to dig into events, for now i have a view (div) with some buttons, a click on the div itself should do the same as a click on one of the buttons.
When i click on any button, the event elevates and the function that bind to 'click div' also called.
For a quick fix that i did, i save the event object and on 'click div' i check if the calle event is the same that i saved, then do nothing.
What is the better way to do this?
And also i cant find ids in events, are there any and can they be added to the event object?
if( arguments ){
if( arguments[0] ){ // jquery event
if( this.lastEvent == arguments[0] ){ //already processed event
return;
}
this.lastEvent = arguments[0];
}
}
UPDATE:
as suggested - what id did, in view:
events: {
'click .btn-mark-saw': 'mark_saw',
'click .btn-mark-circle': 'mark_circle',
'click':'mark_circle'
},
mark_saw: function(event){
event.stopPropagation();
//...
this.render();
},
mark_circle: function(event) {
event.stopPropagation();
//...
this.render();
},
it works, thank you!
This should serve your purpose.
$(document).ready(function(){
$("#divID").live("click", function(){
//div click action..
});
$("#buttonID").live("click", function(event){
//button click action..
event.stopPropagation();
});
});
Thanks..
I have an anchor tag on my page, I want an event attached to it, which will fire when the display of this element change.
How can I write this event, and catch whenever the display of this element changes?
This is my way of doing on onShow, as a jQuery plugin. It may or may not perform exactly what you are doing, however.
(function($){
$.fn.extend({
onShow: function(callback, unbind){
return this.each(function(){
var _this = this;
var bindopt = (unbind==undefined)?true:unbind;
if($.isFunction(callback)){
if($(_this).is(':hidden')){
var checkVis = function(){
if($(_this).is(':visible')){
callback.call(_this);
if(bindopt){
$('body').unbind('click keyup keydown', checkVis);
}
}
}
$('body').bind('click keyup keydown', checkVis);
}
else{
callback.call(_this);
}
}
});
}
});
})(jQuery);
You can call this inside the $(document).ready() function and use a callback to fire when the element is shown, as so.
$(document).ready(function(){
$('#myelement').onShow(function(){
alert('this element is now shown');
});
});
It works by binding a click, keyup, and keydown event to the body to check if the element is shown, because these events are most likely to cause an element to be shown and are very frequently performed by the user. This may not be extremely elegant but gets the job done. Also, once the element is shown, these events are unbinded from the body as to not keep firing and slowing down performance.
You can't get an onshow event directly in JavaScript. Do remember that the following methods are non-standard.
IN IE you can use
onpropertychange event
Fires after the property of an element
changes
and for Mozilla
you can use
watch
Watches for a property to be assigned
a value and runs a function when that
occurs.
You could also override jQuery's default show method:
var orgShow = $.fn.show;
$.fn.show = function()
{
$(this).trigger( 'myOnShowEvent' );
orgShow.apply( this, arguments );
return this;
}
Now just bind your code to the event:
$('#foo').bind( "myOnShowEvent", function()
{
console.log( "SHOWN!" )
});
The code from this link worked for me: http://viralpatel.net/blogs/jquery-trigger-custom-event-show-hide-element/
(function ($) {
$.each(['show', 'hide'], function (i, ev) {
var el = $.fn[ev];
$.fn[ev] = function () {
this.trigger(ev);
return el.apply(this, arguments);
};
});
})(jQuery);
$('#foo').on('show', function() {
console.log('#foo is now visible');
});
$('#foo').on('hide', function() {
console.log('#foo is hidden');
});
However the callback function gets called first and then the element is shown/hidden. So if you have some operation related to the same selector and it needs to be done after being shown or hidden, the temporary fix is to add a timeout for few milliseconds.