let's say i do this:
$('field').addEvents ({
'focus' : function() { // do some stuff }
'blur' : function() { // do other stuff }
});
this is the default behaviour for all my text input fields. what i now want to do is something like this
<button id='shinyButton' name='shinyButton'>Poke Me</button>
then:
$('shinyButton').addEvent('click', function() {
stopDefaultBlurFunctionInCurrentlyFocussedField();
// do seriously cool stuff
if (finishedDoingSeriouslyCoolStuff) {
$('field').focus(); // return focus to input field
}
}
so:
1) how do i stopDefaultBlurFunctionInCurrentlyFocussedField();?
2) how do i tell if i'm actually finishedDoingSeriouslyCoolStuff?
Strictly speaking you can't do what you want to do because the blur event fires before your click handler does.
Dimitar's suggestion of disabling the event on mouseover works fine for mouse users, but prevents users from triggering the button with the keyboard.
One option (but a bit of a hack) would be to introduce a tiny delay into the blur event handler, and use a variable flag to control the event firing (you might need to tune the delay so it's imperceptible but still long enough for your purposes:
var disableBlurMethod = false;
$('field').addEvents ({
'focus' : function() { // do some stuff }
'blur' : function() {
(function() {
if (!disableBlurMethod) {
// do some stuff
}
}).delay(50);
}
});
$('shinyButton').addEvent('click', function() {
disableBlurMethod = true;
// do seriously cool stuff
if (finishedDoingSeriouslyCoolStuff) {
disableBlurMethod = false;
$('field').focus(); // return focus to input field
}
}
Related
I'm fairly new to canvas and experimenting with random functions. I've gotten mouseClick events and now I'm trying to implement a keydown event to do something simple like change the background color.
I'm looking at a lot of keyDown event examples and am a little confused about the structured.
Is it as simple as
if (e.keyCode == 40) { *change background color code }
I'm seeing a lot of people having some false, true statements in there as well, which throws me off.
Yes, it's that simple. Check if the key was pressed inside of a listener for the keydown event:
window.addEventListener('keydown', function (event) {
if (event.keyCode === 40) {
*change background*
}
});
Alternative:
var keys = [];
window.addEventListener('keydown', function (event) {
keys[event.keyCode] = true;
if (keys[40] === true) {
*change background color*
}
});
window.addEventListener('keyup', function (event) {
keys[event.keyCode] = false;
});
(might be aforementioned true/false statements OP mentioned)
JSFiddle: #1, #2.
I'm using Kendo MVVM and I have a kendo numerictextbox bound to a kendo observable.
All I want is: when the user changes value, a confirm should pop saying something like 'are you sure?' if yes -> no problem, go on.
if no -> NOTHING should happen!
In theory it sounds simple as that... but I found 3 major issues:
1) numerictextbox only got 2 events: spin and change... so any idea of using keypress/focus/or any other event is discarded.
2) So tried using the change event... but I can't preventDefault! Another try was to save previous value and restore it back in case of 'no answer' but this brings me to trigger event change TWICE!
3) Any other model field who is 'observing' the numerictextbox will change before I even answer the confirm box... And I absolutely don't want this!
P.S. I also got a dropdownlist and a datepicker that must work in the same way!
Help please!
Provided a fast example: http://dojo.telerik.com/EyItE
Here you can see how the numericbox2 (who is observing numericbox1 and is computed) changes itself before the user answer yes/no (problem 3)
and keypress/focus/preventDefault doesn't work.
here is an answer about binding events not supported by default:
Kendo MVVM and binding or extending custom events
For preventDefault (or "reverting" the value). I tried to store the previous value as you suggested and it is does not fire twice:
var viewModel = kendo.observable({
myItem: {
// fields, etc
myNumericBox: 10,
myNumericBox2: function () {
return viewModel.get("myItem.myNumericBox")*2;
},
tmp: 10
},
onChange: function (e) {
if ( confirm("are you sure?")) {
viewModel.set("myItem.tmp", viewModel.get("myItem.myNumericBox"));
}
else {
viewModel.set("myItem.myNumericBox", viewModel.get("myItem.tmp"));
}
},
tryf: function () {
alert("hello!"); // doesn't trigger
},
tryk: function() {
alert("hello2!"); // doesn't trigger
}
});
I solved with a custom binding that ask you a confirm between html widget change -> model update.
kendo.data.binders.widget.valueConfirm = kendo.data.Binder.extend({
init: function (widget, bindings, options) { // start
kendo.data.Binder.fn.init.call(this, widget.element[0], bindings, options);
this.widget = widget;
this._change = $.proxy(this.change, this);
this.widget.bind("change", this._change); // observe
},
refresh: function () { // when model change
if (!this._initChange) {
var widget = this.widget;
var value = this.bindings.valueConfirm.get(); // value of the model
if (widget.ns == ".kendoDropDownList") { // for the dropdown i have to use select
widget.select(function (d) {
return d.id == value.id;
});
}
else widget.value(value); // update widget
}
},
change: function () { // when html item change
var widget = this.widget;
if (widget.ns == ".kendoDropDownList") var value = widget.dataItem(); // for dropdown i need dataitem
else var value = widget.value();
var old = this.bindings.valueConfirm.get();
this._initChange = true;
// I want to bypass the confirm if the value is not valid (for example after 1st load with blank values).
if (old == null || old == 'undefined' || old == 'NaN') this.bindings.valueConfirm.set(value); // Update the View-Model
else {
if (confirm("Are you sure?")) {
this.bindings.valueConfirm.set(value); // Update the View-Model
}
else {
this._initChange = false;
this.refresh(); // Reset old value
}
}
this._initChange = false;
},
destroy: function () { // dunno if this is useful
this.widget.unbind("change", this._change);
}
});
I'm using ajax to pull in content to create a light box type content page. It also has a next and prev button once loaded so hence the use of ajax.
I wanted to use Ajax for the page navigation too. But if someone clicks a page link and then tries to use the light box feature both the jquery and ajax requests no longer work within the loaded area.
I've read a lot about bind and delegate but not sure how to use them in this context
Here's my main pieces of code:
// This gets called on document ready
function clicky() {
$link.click(function(e) {
e.preventDefault();
var linkPage = $(this).attr('href');
if ($(this).hasClass('pages')){
// PAGE specific code
if ($('body').scrollTop() != 0) {
$('body').animate({ scrollTop: 0 }, 500, function(){
pageLoad(linkPage);
});
} else { pageLoad(linkPage); }
console.log('page');
} else {
// PRODUCT specific code
if ($('body').scrollTop() != 0) {
$('body').animate({ scrollTop: 0 }, 500, function(){
productLoad(linkPage);
});
} else {
productLoad(linkPage);
}
}
});
}
Here's my ajax for the two different areas:
// Ajax stuff going on for pages
function pageLoad(linkPage) {
// Page stuff fades out
history.pushState(null, null, linkPage);
$("#page-content").load(linkPage + " #guts", function(){
// Loads in page content
});
}
// Ajax stuff going on for Products
function productLoad(linkPage) {
// Page stuff fades out
history.pushState(null, null, linkPage);
$("#product-content").load(linkPage + " #guts", function(){
// Shows an overlay/lightbox and loads in content
});
}
Edit: This worked for me
$(document).on('click', '.link' , function(){
console.log('this worked');
return false;
});
This worked:
$(document).on('click', '.link' , function(){
console.log('this worked');
return false;
});
I'm using Bootstrap Typeahead to suggest som search results. The results are returned from a ajax ressource, and since this resource creates a delay, I'm experiencing a unfortunate effect.
Example:
If typing a 4 letter word, the suggestions will appear after 2 letters, I can then go through the results with the keys up/down, but suddenly the suggestions will reload because the last request has finished.
Is there any way to "cancel" any remaining, if user is currently using the keys up/down to go through the suggestions?
('#query').typeahead({
items: 4,
source: function (query,process) {
map = {};
$.getJSON('/app_dev.php/ajax/autosuggest/'+query, function (data) {
vehicles = [];
$.each(data, function(i,vehicle){
map[vehicle.full] = vehicle;
vehicles.push(vehicle.full);
});
process(vehicles);
});
},
updater: function (item) {
// do something here when item is selected
},
highlighter: function (item) {
return item;
},
matcher: function (item) {
return true;
}
});
I think the following will satisfy your needs (its hard to reproduce exactly) :
There is no easy way to abort a delayed response, but you could extend typeahead as I figured out here (without modifying bootstrap.js)
The concept is to catch keydown, detect if the event is KEY_UP or KEY_DOWN, set a flag is_browsing, and then abort process if is_browsing is true (that is, if the user has hitted KEY_UP or KEY_DOWN and no other keys afterwards).
Extending typeahead :
// save the original function object
var _superTypeahead = $.fn.typeahead;
// add is_browsing as a new flag
$.extend( _superTypeahead.defaults, {
is_browsing: false
});
// create a new constructor
var Typeahead = function(element, options) {
_superTypeahead.Constructor.apply( this, arguments )
}
// extend prototype and add a _super function
Typeahead.prototype = $.extend({}, _superTypeahead.Constructor.prototype, {
constructor: Typeahead
, _super: function() {
var args = $.makeArray(arguments)
// call bootstrap core
_superTypeahead.Constructor.prototype[args.shift()].apply(this, args)
}
//override typeahead original keydown
, keydown: function (e) {
this._super('keydown', e)
this.options.is_browsing = ($.inArray(e.keyCode, [40,38])>-1)
}
//override process, abort if user is browsing
, process: function (items) {
if (this.options.is_browsing) return
this._super('process', items)
}
});
// override the old initialization with the new constructor
$.fn.typeahead = $.extend(function(option) {
var args = $.makeArray(arguments),
option = args.shift()
// this is executed everytime element.modal() is called
return this.each(function() {
var $this = $(this)
var data = $this.data('typeahead'),
options = $.extend({}, _superTypeahead.defaults, $this.data(), typeof option == 'object' && option)
if (!data) {
$this.data('typeahead', (data = new Typeahead(this, options)))
}
if (typeof option == 'string') {
data[option].apply( data, args )
}
});
}, $.fn.typeahead);
This typeahead-extension could be placed anywhere, eg in a <script type="text/javascript"> -section
Testing the extension :
<input type="text" id="test" name="test" placeholder="type some text" data-provide="typeahead">
<script type="text/javascript">
$(document).ready(function() {
var url='typeahead.php';
$("#test").typeahead({
items : 10,
source: function (query, process) {
return $.get(url, { query: query }, function (data) {
return process(data.options);
});
}
});
});
</script>
A "serverside" PHP script that returns a lot of randomized options with forced delay, typeahead.php :
<?
header('Content-type: application/json');
$JSON='';
sleep(3); //delay execution in 3 secs
for ($count=0;$count<30000;$count++) {
if ($JSON!='') $JSON.=',';
//create random strings
$s=str_shuffle("abcdefghijklmnopq");
$JSON.='"'.$s.'"';
}
$JSON='{ "options": ['.$JSON.'] }';
echo $JSON;
?>
It really seems to work for me. But I cannot be sure that it will work in your case. Let me now if you have success or not.
I want to re-open a question someone else asked. What's the best way to emulate mouseenter with live or delegate? The original question was here:
How should I emulate a mouseenter event using jquery's live functionality?
And the OP's proposal was:
// mouseenter emulation
jQuery('.selector').live('mouseover',function (e) {
// live sees all mouseover events within the selector
// only concerned about events where the selector is the target
if (this != e.target) return;
// examine relatedTarget's parents to see if target is a parent.
// if target is a parent, we're "leaving" not entering
var entering = true;
jQuery(e.relatedTarget).parents().each(function () {
if (this == e.target) {
entering = false;
return false; // found; stop searching
}
});
if (!entering) return;
/*
the rest of my code
*/
});
$('ul.cms_tabs_edit').delegate('li', 'mouseenter', function() {
$(this).addClass('hover');
});
$('ul.cms_tabs_edit').delegate('li', 'mouseleave', function() {
$(this).removeClass('hover');
});
I ended up doing:
$("#id").delegate(".selector", "mouseover", function(){
if(!$(this).hasClass("bound")){
$(this).hover(function(){
alert('entering');
},
function(){
alert('leaving');
}).mouseover().addClass("bound");
}
});
Does anyone have a better solution?