Custom events binding in jquery function on not working - javascript

I just came to know about the jQuery .on() method and decided to use it as it was much cleaner than using multiple binds. It is working as long as I am using pre-defined events but when I am trying to add custom events it is not working.
I have this auxiliary function
var EV_ENTER_KEY = "enterKey";
function bind_events(cur_obj, e) {
if (e.keyCode == 13) {
$(cur_obj).trigger(EV_ENTER_KEY);
}
}
which I am using in the following code
CATEGORY_INPUT.on({
keyup: function (e) {
bind_events(this, e);
}
});
//Action for Category Search box Enter press
CATEGORY_INPUT.bind(EV_ENTER_KEY, function () {
alert("Aseem");
});
I am changing it to the following
CATEGORY_INPUT.on({
keyup: function (e) {
bind_events(this, e);
},
EV_ENTER_KEY: function () {
alert("Aseem");
}
});
But it is not working. No errors are being logged in console either for this. I looked and found this and I think I am using it correctly. The API reference did not have any examples of binding multiple events. Can someone tell whether I missed something in the API? If not what is the problem here?

It seems you have to give the custom event as string directly instead of storing it in a js variable and then using it.
If you change EV_ENTER_KEY to "enterKey" in your multiple event binding then it will work.
$(".myInput").on({
keyup: function (e) {
bind_events(this, e);
},
"enterKey": function () {
alert("Enter key pressed");
}
});
JS fiddle demo : http://jsfiddle.net/9ur4c/

It can be made to work like this. This is according to this answer
var EV_ENTER = "enter"
categoryInputEvents = {}
categoryInputEvents[EV_ENTER] = function(e) {
alert("Enter Event");
}
CATEGORY_INPUT.on(categoryInputEvents)
Although this still does not explain the thing reported by #Sanjeev but it is better to have alternatives.

Related

How to identify the input in which the key was pressed in JS code

I use the following jQuery code to process keys which are pressed in various input tags:
$(document).ready( function () {
$("input").keydown(function (e) {processKeys(e);});
...
It works great...
In a separate Javascript file I have a function which receives the event call:
function processKeys(e) {
key=e.which;
if (key==27) {
$("#searchCDB").hide();
}
}
So, is there a way for me to identify the <input> tag which caused the event at the event layer... What I mean is here, in some way like:
$("input").keydown(function (e) {processKeys($("#this"),e);});
I know my attempt is absurd, but any suggestion that works will be appreciated.
DK
You can pass in this to your processKeys function:
$(document).ready( function () {
$("input").keydown(function (e) {
processKeys(e, this);
});
});
function processKeys(e, obj) {
console.log(obj.id); //logs ID of keypressed input
key=e.which;
if (key==27) {
$("#searchCDB").hide();
}
}
Demo: http://jsfiddle.net/uE7ZD/

stopPropagation function reading not defined

I have a page with a lot of e.stopPropagation so what I decided I would do was to create a function. here is code
function stopProp(name) {
if($(e.target).hasClass(name)) {
e.stopPropagation();
}
}
Though each time in console it does not seem to work at all and says stopProp is undefined.
Here is the actual JS I am trying to turn into a function
$('#chatting').on('click','.chatheader',function(e){
if($(e.target).hasClass('setting')) {
e.stopPropagation();
}
}
});
Anyone can help me to figure out why this is not working and how I should go about this? I figured it would be fairly easy just to change to a function so I can easily write stopProp('setting');though that is not the case here.
The handler of the click event should return with one single argument which will be the event. So you should have a function that returns an event, for example like this :
$('#chatting').on('click','.chatheader',stopProp('setting'));
function stopProp(name) {
return function(e) {
if($(e.target).hasClass(name)) {
e.stopPropagation();
}
}
}
You need to pass the event object to the stopProp method.
function stopProp(e) {
if($(e.target).hasClass(e.data.className)) {
e.stopPropagation();
}
}
Then
$('#chatting').on('click', '.chatheader', {className: 'setting'}, stopProp);
Demo: Fiddle

Bind to custom CSS animation end event with jQuery or JavaScript?

We have multiple animations against the same object. We need to take different actions when each of these animations end.
Right now, we bind to the webkitAnimationEnd event, and use a gnarly if/then statement to handle each animation differently.
Is there a way to essentially create custom webkitAnimationEnd events, allowing us to fire a specific event handler when a specific animation ends? For instance, fire handler1 when animation1 ends and fire handler2 when animation2 ends.
We're building for Webkit browsers, specifically Mobile Safari.
Thanks!
For a simple event-trigger, you can pass a function to jQuery's trigger() method and use the returned value of that function to call a trigger a specific event (which can then be listened-for:
function animEndTrigger(e) {
if (!e) {
return false;
}
else {
var animName = e.originalEvent.animationName;
return animName + 'FunctionTrigger';
}
}
$('body').on('bgAnimFunctionTrigger fontSizeFunctionTrigger', function(e){
console.log(e);
});
$('div').on('webkitAnimationEnd', function(e) {
$(this).trigger(animEndTrigger(e));
});
JS Fiddle demo.
You can, of course, also use the called function to either trigger the event itself or assess the passed parameters to determine whether or not to return an event at all:
One method to assess for a particular event to trigger is to use an object:
var animations = {
'bgAnim': 'aParticularEvent'
};
function animEndTrigger(e) {
if (!e) {
return false;
}
else {
var animName = e.originalEvent.animationName;
return animations[animName] ? animations[animName] : false;
}
}
$('body').on('aParticularEvent', function(e) {
console.log(e);
});
$('div').on('webkitAnimationEnd', function(e) {
$(this).trigger(animEndTrigger(e));
});​
JS Fiddle demo.
Though, in this case, the return false should be altered so as not to provide the error Uncaught TypeError: Object false has no method 'indexOf' (which I've not bothered, as yet, to account for).
The following causes the called-function (animEndTrigger()) to directly trigger() the custom event (which requires an element on which to bind the trigger() method) and also avoids the Uncaught TypeError above:
var animations = {
'bgAnim': 'aParticularEvent'
};
function animEndTrigger(e, el) {
if (!e || !el) {
return false;
}
else {
var animName = e.originalEvent.animationName;
if (animations[animName]) {
$(el).trigger(animations[animName]);
}
}
}
$('body').on('aParticularEvent', function(e) {
console.log(e);
});
$('div').on('webkitAnimationEnd', function(e) {
animEndTrigger(e, this);
});​
JS Fiddle demo.
Of course you're still, effectively, using an if to perform an assessment, so I can't be particularly sure that this is any tidier than your own already-implemented solution.

Making my mouseevent coded in jquery a lot more elegant

I wrote this in order to fix the problem IE has with select drop down lists being truncated if their options were longer than the default value of the select. Now it works fine but I want to improve the code in order to learn how to write things in a much more useable fashion.
$(document).ready(function() {
if ($.browser.msie) {
$('select').focus(function() { $(this).addClass('expand').removeClass('clicked'); })
$('select').blur(function() { $(this).removeClass('expand clicked'); })
$('select').mousedown(function () { $(this).addClass('expand').removeClass('clicked'); } )
$('select').hover(function () { }, function () {if (!$(this).hasClass('clicked')) { $(this).removeClass('expand'); $(this.blur()) }})
$('select').click (function() { $(this).toggleClass('clicked'); })
$('select').change(function(){ $(this).removeClass('expand clicked'); $('select.widerIE').blur() })
}
});
I tried making functions which were called by each event but that seemed to fail eg:
$('select').click(test (a))
function test (a) {
$(a).addClass('expand').removeClass('clicked')
}
It's not clear to me what you're trying to achive. One thing is sure - you can't define a event handler like that (see note below):
$('select').click(test (a))
Note: Technically, you could define your event handler like in code above. For that to work, function test would have to return a function that would be actual handler for the event.

Get text from field on keyup, but with delay for further typing

I have a form which is submitted remotely when the various elements change. On a search field in particular I'm using a keyup to detect when the text in the field changes. The problem with this is that when someone types "chicken" then the form is submitted seven times, with only the last one counting.
What would be better is something like this
keyup detected - start waiting (for one second)
another keyup detected - restart waiting time
waiting finishes - get value and submit form
before I go off and code my own version of this (I'm really a backend guy with only a little js, I use jQuery for everything), is there already an existing solution to this? It seems like it would be a common requirement. A jQuery plugin maybe? If not, what's the simplest and best way to code this?
UPDATE - current code added for Dan (below)
Dan - this may be relevant. One of the jQuery plugins I'm using on the page (tablesorter) requires this file - "tablesorter/jquery-latest.js", which, if included, leads to the same error with your code as before:
jQuery("input#search").data("timeout", null) is undefined
http‍://192.168.0.234/javascripts/main.js?1264084467
Line 11
Maybe there's some sort of conflict between different jQuery definitions? (or something)
$(document).ready(function() {
//initiate the shadowbox player
// Shadowbox.init({
// players: ['html', 'iframe']
// });
});
jQuery(function(){
jQuery('input#search')
.data('timeout', null)
.keyup(function(){
jQuery(this).data('timeout', setTimeout(function(){
var mytext = jQuery('input#search').val();
submitQuizForm();
jQuery('input#search').next().html(mytext);
}, 2000)
)
.keydown(function(){
clearTimeout(jQuery(this).data('timeout'));
});
});
});
function submitQuizForm(){
form = jQuery("#searchQuizzes");
jQuery.ajax({
async:true,
data:jQuery.param(form.serializeArray()),
dataType:'script',
type:'get',
url:'/millionaire/millionaire_quizzes',
success: function(msg){
// $("#chooseQuizMainTable").trigger("update");
}
});
return true;
}
Sorry i haven't tested this and it's a bit off the top of my head, but something along these lines should hopefully do the trick. Change the 2000 to however many milliseconds you need between server posts
<input type="text" id="mytextbox" style="border: 1px solid" />
<span></span>
<script language="javascript" type="text/javascript">
jQuery(function(){
jQuery('#mytextbox')
.data('timeout', null)
.keyup(function(){
clearTimeout(jQuery(this).data('timeout'));
jQuery(this).data('timeout', setTimeout(submitQuizForm, 2000));
});
});
</script>
Here's your fancy jquery extension:
(function($){
$.widget("ui.onDelayedKeyup", {
_init : function() {
var self = this;
$(this.element).keyup(function() {
if(typeof(window['inputTimeout']) != "undefined"){
window.clearTimeout(inputTimeout);
}
var handler = self.options.handler;
window['inputTimeout'] = window.setTimeout(function() {
handler.call(self.element) }, self.options.delay);
});
},
options: {
handler: $.noop(),
delay: 500
}
});
})(jQuery);
Use it like so:
$("input.filterField").onDelayedKeyup({
handler: function() {
if ($.trim($(this).val()).length > 0) {
//reload my data store using the filter string.
}
}
});
Does a half-second delay by default.
As an update, i ended up with this which seems to work well:
function afterDelayedKeyup(selector, action, delay){
jQuery(selector).keyup(function(){
if(typeof(window['inputTimeout']) != "undefined"){
clearTimeout(inputTimeout);
}
inputTimeout = setTimeout(action, delay);
});
}
I then call this from the page in question's document.ready block with
afterDelayedKeyup('input#search',"submitQuizForm()",500)
What would be nice would be to make a new jquery event which uses this logic, eg .delayedKeyup to go alongside .keyup, so i could just say something like this for an individual page's document.ready block.
jQuery('input#search').delayedKeyup(function(){
submitQuizForm();
});
But, i don't know how to customise jquery in this way. That's a nice homework task though.
Nice job, Max, that was very helpful to me! I've made a slight improvement to your function by making it more general:
function afterDelayedEvent(eventtype, selector, action, delay) {
$(selector).bind(eventtype, function() {
if (typeof(window['inputTimeout']) != "undefined") {
clearTimeout(inputTimeout);
}
inputTimeout = setTimeout(action, delay);
});
}
This way you can use it for any type of event, although keyup is probably the most useful here.
I know this is old, but it was one of the first results when I was searching for how to do something like this so I though I would share my solution. I used a combination of the provided answers to get what I needed out of it.
I wanted a custom event that worked just like the existing jQuery events, and it needed to work with keypress + delete, backspace and enter.
Here's my jQuery plugin:
$.fn.typePause = function (dataObject, eventFunc)
{
if(typeof dataObject === 'function')
{
eventFunc = dataObject;
dataObject = {};
}
if(typeof dataObject.milliseconds === 'undefined')
dataObject.milliseconds = 500;
$(this).data('timeout', null)
.keypress(dataObject, function(e)
{
clearTimeout($(this).data('timeout'));
$(this).data('timeout', setTimeout($.proxy(eventFunc, this, e), dataObject.milliseconds));
})
.keyup(dataObject, function(e)
{
var code = (e.keyCode ? e.keyCode : e.which);
if(code == 8 || code == 46 || code == 13)
$(this).triggerHandler('keypress',dataObject);
});
}
I used $.proxy() to preserve the context in the event, though there could be a better way to do this, performance-wise.
To use this plugin, just do:
$('#myElement').typePause(function(e){ /* do stuff */ });
or
$('#myElement').typePause({milliseconds: 500, [other data to pass to event]},function(e){ /* do stuff */ });

Categories

Resources