Backbone.js - Adding keydown events when view is active? - javascript

I have a view called gallery that options. I want to listen and act on keydown events when the gallery is rendered (until it's closed).
How do I do this in backbone events? I've tried all variations of 'keydown X':function and none have worked.

I just tested the following and it worked flawlessly:
var view = Backbone.View.extend({
// ... snip ...
events: {
'keyup :input': 'logKey'
,'keypress :input': 'logKey'
}
,logKey: function(e) {
console.log(e.type, e.keyCode);
}
});
I'd go back and check your code. All events in Backbone are defined as delegates attached to the viewInstance.el element. To unbind the events, call viewInstance.remove() which calls $(viewInstance.el).remove() under the covers and cleans up all the delegated events.
Also note that in some browsers (Firefox I believe) there's a known issue that some keys (like arrow keys) don't bubble and will not work properly with delegated keypress events. If you're catching special keys, you're probably better off using keyup and keydown.

Related

Is hover from jquery to backbone code

I want to translate this into backbone event model, avoiding using directly jquery.
$(".class").is(":hover")
What I have tried in my view is register an event (mouseenter, mouseleave), but seems that the events are being intercepted before by another component probably because it have stopPropagation or for an uncertain reason I don't receive it. I need to have something like this.
if($(".class").is(":hover")){
//execute this code.
}
What I tried to do is using event handlers to intercept the hover on a specific element change a flag, and change the condition to use that flag.
if(flag){
//execute this code.
}
You're looking for the mouseover javascript event.
If the event bubbling is stopped by stopPropagation, rethink using stopPropagation as it causes all sort of problems.
Here's a simple backbone view using the event.
var View = Backbone.View.extend({
events: {
"mouseover .specific-element": "onMouseOver"
},
onMouseOver: function(e) {
// do stuff
}
});

stopPropagation in Chrome and IE

I've been having trouble getting stopPropagation to work for my dataview. Basically the issue is as follows;
Select node in the dataview, this fires the select, selectionchange events
Selected node has an image with an onClick event, this creates a report in a pop up window.
When image is clicked I call stopPropagation to prevent the event being bubbled up to the dataview which would cause the deselect, selectionchange events to be fired.
stopPropagation only seems to work in Firefox for me. Chrome and IE it seems to have no effect as the node is deselected and the unwanted events fired.
I've tried the following function on the onClick event
handleBubbleEvent: function(e) {
if (!e) {
var e = window.event;
}
e.cancelBubble = true;
e.returnValue = false;
if (e.stopPropagation) {
e.stopPropagation();
}
}
Have also seen stopImmediatePropagation, preventDefault, stopEvent but these also has had no effect
I am doing all this inside an Ext XTemplate
I'm wondering if this is an ExtJS 5 issue and the same code is working for an older version of ExtJS. I just can't seem to stop the click event bubbling back up to the dataview which then fires the deselect and selectionchange events.
Could it be that it is a timing/order issue. I use ExtJS's selectionchange event on the dataview whereas in the XTemplate I am using my own listener function? I see stuff online referencing capturing/bubbling of events and as I'm not a web developer I'm struggling on this.
UPDATE:
I'm now looking at events and capturing/bubbling, it seems the capturing is going up to the parent and calling the deselect, selectionchange then going down into the actual click handler at which point I then call stopPropagation but it is too late at this stage. Looking at creating my own listener for selectionchange with either target/delegate set so that it is only called when class != 'some class' and then a listener on 'some class' click to handle what I want and stopPropagation, if that makes any sense!
Try using a setTimeout on any dom manipulation triggered by the event.target element's event handler so that the event bubbling completes before any of the dom manipulation occurs.
I had the same issue with Chrome, and (like with you) Firefox worked. I discovered that Chrome seems to get confused if you modify the dom before the event bubbling completes.
In my case, I was adding two elements to the document.body (a canvas and a fieldset) and by the time chrome bubbled the event, the event.target was incorrect (it thought "BODY" was the event.target.tagName -- WRONG!). I wrapped the DOM manipulation portion in a setTimeout like this:
setTimeout(()=>
{
document.body.appendChild(canvas);
document.body.appendChild(fieldSet);
},0);
After this, chrome started reporting the correct element.target on the bubbled body click event. Maybe this same technique will help you get e.stopPropagation() to do its thing before the dom manipulation occurs.

Famo.us attaching click and touchstart events

I'm wondering how to bind both events "click" and "touchstart" within a single line:
Engine.on("click"), function(){ aCode() }
Engine.on("touchstart", function(){ aCode() }
I expected something like this (as it is implemented in some other frameworks):
Engine.on("click touchstart", function(e){ aCode() });
My current workaround is chaining them:
Engine.on("click", function(){Engine.emit("touchstart")});
Engine.on("touchstart", function() { aCode() }
Is there a better practice for this ? The problem is that click is not caught on iOS nor the touchstart with a mouse on desktop… obviously I would like to handle the event the same way whatever the device.
[EDIT] For handling the click and touchstart->touchend in the same way, just use the FastClick override shim.
just add:
FastClick = require('famous/inputs/FastClick');
then this will also work on tablet:
anElement.on("click", function(){alert("Click caught")})
Another alternative is using this helper:
function onEvent(source, events, callback)
{
for (var event in events)
{
source.on(events[event], function(e) {
callback(e);
});
}
}
Then:
onEvent(Famous.Engine, ["click","touchstart"],function(){});
The on() method in Famo.us only accepts one event type. It doesn't do any jQuery style string processing to determine separate events. In theory you could have an event named get to the chopper
What I do when creating my custom views however is create a bindEvents() function which groups all the event listeners together. The only code in these handlers are other functions. If I wanted to react to two different events in the same way, I'd just use the same function for both of them.
// An example Class demonstrating events - some off-topic parts omitted
function myLovelyHorseButton() {
// Recomended Reading: https://famo.us/guides/dev/events.html
this._eventInput = new EventHandler();
this._eventOutput = new EventHandler();
this._eventInput.pipe(this.sync);
this.sync.pipe(this._eventInput);
EventHandler.setInputHandler(this, this._eventInput);
EventHandler.setOutputHandler(this, this._eventOutput);
/** Set options & variables
/* ...
*/
// create event listeners for this specific instance
_bindEvents.call(this);
};
// bind all the events for the button
function _bindEvents() {
//Call event handlers with this set to owner.
this._eventInput.bindThis(this);
// listen for events
this._eventInput.on('click', _handleClick);
this._eventInput.on('touchstart', _handleClick); //Same as 'click'
};
// Nay to the console on click/touch
function _handleClick(event) {
console.log('Nayyyyy!!!');
};
// create an instance of myLovelyHorseButton
var button = new myLovelyHorseButton;
// We would then add the button to the Render Tree
mainContext.add(button);
There is a big reason why you don't want to do the chaining pattern you're currently using. And that's because by emitting a touchstart event on a click, you're inferring that there's going to be some code there to act upon it. One day you might get drunk and decide "Nobody on touch devices is using this!" and delete the ontouchstart handler. And in an instant, your code doesn't work for anybody, touch or mouse.
TL;DR There is nothing wrong with using multiple on() calls.
I hope this helps.

jQuery $(window).blur vs native window.onblur

What are the advantages of using jQuery's
$(window).blur(function() { ... })
to attach an event handler versus setting it directly with
window.onblur = function() { ... }
It seems that the latter is less robust because it only supports one blur handler, and when used with other packages, other code might override the window.blur value with another function. However, couldn't this also happen with the jQuery implementation too, which presumably uses window.blur as its underlying implementation?
EDIT: Several people have also mentioned the window.addEventListener alternative, which can be used to add an 'onblur' event apart from the methods above.
$(window).blur(function() { ... })
Lets you add one or more event handlers.
window.onblur = function() { ... }
Lets you only have one event handler handling the blur event.
The former uses the jQuery's own event handle mechanism. The call to .blur() will delegate to jQuery.fn.on() which in turn will delegate to jQuery.event.add. This add() method will create it's own handler for the given event type and tell addEventListener() to call this handler whenever a event of given type is fired. So basically jQuery has it's own way of event handling which relies on addEventListener() to execute properly.
The latter is just an attribute which can only contain one value so queueing event handlers is impossible.
I wrote a little demonstration to prove this point: http://jsfiddle.net/GnNZm/1/
With the jQuery method, you can attach multiple event handlers. By setting window.onblur, you can only have a single handler.
Pure JavaScript also has this: window.addEventListener(). In fact, i'm sure jQuery uses this internally. (Yes they do.)
(EDIT)
The window.onblur property is basically a shortcut for setting a single handler. Using addEventListener() (or the jQuery wrapper) basically creates a list of event handlers, which all get fired when the event happens. I haven't tested, but i think you can even use the two together. Because it's a list, not a single value, multiple handlers shouldn't interfere with each other. They can also be removed separately or all at once.
jQuery's event handlers, using on(), also let you namespace your handlers, to prevent clashes if a plugin removes its handlers. Pure JS doesn't seem to have this easily.
For jquery blur
The blur event does not bubble in Internet Explorer. Therefore,
scripts that rely on event delegation with the blur event will not
work consistently across browsers. As of version 1.4.2, however,
jQuery works around this limitation by mapping blur to the focusout
event in its event delegation methods, .live() and .delegate().
taken from jquery doc https://api.jquery.com/blur/
Also jquery allows you bind multiple event handlers
When you attach an event there is the possibility of overwriting an event already attached to an event handler. This used to happen a lot with window.onload() where different scripts overwrote each others event handlers.
eg:
//lightbox.js
window.onload = function() { /* do lightbox stuff */ }
//carousel.js
window.onload = function() { /* do carousel stuff */ }
So the common practice used to be something like this:
var existing_event_handlers = window.onload;
window.onload = function(){
//my event code
alert('onready fired');
//call other event handlers after
existing_event_handlers();
}
Using window.onblur = function() { ... } still has an advantage because you can specifically dictate if you want your event fired before or after other attached events.
Like many other answers already pointed out jQuery abstracts you from most browser differences. Version before IE9 used attachEvent() rather than addEventListener().

Extend jQuery's .on() to work with mobile touch events

I am attempting to use the jQuery mobile events without the rest of jQuery mobile.
https://github.com/jvduf/jquery-mobile-events/blob/master/jquery.mobile.events.js
That snippet enables them all, and works fine, but not with the .on() event handler. E.g:
$('a').on('tap',function(){
console.log('Hi there!');
});
However it does work with .live(), but that is now depreciated.
So my question; is there a a way to extend the .on() functionality to include the tap event and others? Full list below:
touchstart
touchmove
touchend
orientationchange
tap
taphold
swipe
swipeleft
swiperight
scrollstart
scrollstop
Thanks :)
However it does work with .live(), but that is now depreciated.
So I take it that you want to use event delegation to preserve those events on replaced elements. That would mean that this:
$('a').on('tap',function () {
console.log('Hi there!');
});
would need to change to something like:
$(document).on('tap', 'a', function () {
console.log('Hi there!');
});
in order for it to behave the same as $("a").live("tap", ...
Maybe it should be better to extend the JQuery event code for mobile and desktop.
One way to do this is to use the JQuery vmouse (virtual mouse) plugin.
From vmouse plugin comments:
// This plugin is an experiment for abstracting away the touch and mouse
// events so that developers don't have to worry about which method of input
// the device their document is loaded on supports.
//
// The idea here is to allow the developer to register listeners for the
// basic mouse events, such as mousedown, mousemove, mouseup, and click,
// and the plugin will take care of registering the correct listeners
// behind the scenes to invoke the listener at the fastest possible time
// for that device, while still retaining the order of event firing in
// the traditional mouse environment, should multiple handlers be registered
// on the same element for different events.
//
// The current version exposes the following virtual events to jQuery bind methods:
// "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel"
For a better explanation, see https://coderwall.com/p/bdxjzg
vmouse plugin: https://github.com/jquery/jquery-mobile/blob/master/js/jquery.mobile.vmouse.js
Also see this link about current state of (touch) events: http://blogs.adobe.com/adobeandjquery/2011/03/07/the-current-state-of-touch-events/

Categories

Resources