Javascript oninput(setTimeout 2s) / onchange - fire that comes as first - javascript

Hi I have a function Save that's triggered onchange event or oninput after 2s timeout.
Problem is that function Save is triggered twice in this scenario:
type something
wait 2s
oninput fires save event
click out of input
onchange fires save event
I need save only once depending on what happens first. If user types something and immediately leaves input, then save via onchange and oninput timeout should be cancelled. But if types something and waits 2s then save via oninput and onchange shouldn't be triggered.
I need some simple and clean solution. Does it exist? Thanks :)
edit:
here is my code http://jsfiddle.net/TQ9KR/
jQuery('#text').on('change', function() {
save();
});
jQuery('#text').on('input', function(){
clearTimeout(this.delayer);
var context = this;
this.delayer = setTimeout(function () {
jQuery(context).trigger('change');
}, 2000);
});
function save(){
jQuery('#a').text('saved on ' + new Date().getTime());
}

You could set a flag to indicate whether save is needed:
jQuery('#text').on('change', function() {
save();
});
jQuery('#text').on('input', function(){
jQuery(this).data('unsaved', true);
clearTimeout(this.delayer);
var context = this;
this.delayer = setTimeout(function () {
jQuery(context).trigger('change');
}, 2000);
});
function save(){
if (jQuery('#text').data('unsaved')) {
jQuery('#a').text('saved on ' + new Date().getTime());
jQuery('#text').data('unsaved', false);
}
}
Demo: http://jsfiddle.net/TQ9KR/1/
Update: for your requirement of dealing also with changes to the field value from other JavaScript functions you could do the following instead (keeping your original 'change' and 'input' handlers:
function save(){
var $text = jQuery('#text');
if ($text.data('prevVal') != $text.val()) {
jQuery('#a').text('saved on ' + new Date().getTime());
$text.data('prevVal', $text.val());
}
}
That is, only save if the current value of the field is different to whatever was saved last time (where the first time around it will automatically be different since there will be no previously saved value).
Demo: http://jsfiddle.net/TQ9KR/2/

Could you not add a data attribute, something like data-hasChanged and check that?

well honestly only cleen solution that i can think of is to initialize global boolean variable that indicates has save hapen
var hasSaveHapen = false;
and now when any of those functions try to save use this:
if(!hasSaveHapen){
do your save action
hasSaveHapen = false;
}

Related

jQuery nested functions

I am still new to JavaScript and jQuery, so I am confused as to why the following code is not working as I anticipated. All I am trying to do is save input on a button click (id=recordInput) and display it with another button click (id=displayInput). What I observe is that tempInput is stored, (the code works until that point) but assignment of displayInputs onclick attribute is not executed. My question is, can you not nest a $().click() call inside of another &().click() call?
<script>
$(document).ready(function () {
$('#recordInput').click(function(event) {
var tempInput = $('#testInput').val();
&('#displayInput').click(function(event) {
console.log(tempInput);
});
});
});
</script>
My thinking is this in pseudocode:
assign recordInput onclick attribute to the following function:
store tempInput
set displayInput onclick to alert the tempInput value
what is wrong with my thinking?
NOTE: I did not include any html tags but all of the ids are referenced correctly
It's not working because you have put & instead of $ here
$('#displayInput').click(function(event) {
Fixing this may work, but you shouldn't set event handlers this way. Because every time your first handler function is called it will set an event handler for the second one. You can try with your console.log and you will see that the number of console.log is increasing by every click on #recordInput. So you should better set it like this :
var tempInput;
$('#recordInput').click(function(event) {
tempInput = $('#testInput').val();
});
$('#displayInput').click(function(event) {
console.log(tempInput);
});
I would change
$(document).ready(function () {
$('#recordInput').click(function(event) {
var tempInput = $('#testInput').val();
&('#displayInput').click(function(event) {
console.log(tempInput);
});
});
});
to
$(function(){
var testInput = '';
$('#recordInput').click(function(){
testInput = $('#testInput').val();
});
$('#displayInput').click(function(){
if(testInput !== ''){
console.log(testInput);
}
});
});
You are using & instead of $. Of course, you don't have to format the code exactly like I did.

Selectize.js: onItemAdd event triggered when silently adding an item

Using Selectize.js, I'm trying to initialize the dynamically pre-select one of the item of the list without triggering the onItemAdd event. In the following code, the event is triggered even if the silent parameter is truthy:
$(function () {
$('select').selectize({
onItemAdd: function () {
alert("Add item");
}
});
// this triggers an the event
$('select')[0].selectize.addItem('2', true);
});
JSFiddle: http://jsfiddle.net/zuzat0dc/1/
According to the documentation:
addItem(value, silent): "Selects" an item. Adds it to the list at the current caret position. If "silent" is truthy, no change event will be fired on the original input.
Any idea how to avoid triggering the onItemAdd event? Is the silent parameter b0rked or should I use the change event instead?
A quick fix that worked for me was to keep a state flag and refer to it in the event handler...
$(function () {
var initialising = true;
$('select').selectize({
onItemAdd: function () {
if(!initialising) {
alert("Add item");
}
}
});
// this triggers an the event
$('select')[0].selectize.addItem('2', true);
initialising = false;
});
The silent parameter in addItem(value, silent) affects only to the fact whether or not the change event. You can't avoid item_add event with silent = true.
The only thing that worked for me was to store item_add event locally, remove it from selectize instance and set it back after I added the item:
onItemAdd: function(val) {
var e = this._events['item_add'];
delete this._events['item_add'];
this.addItem(123);
this._events['item_add'] = e;
}

How to disable the click if a function is in active status

I have created a fiddle of my function here( http://jsfiddle.net/rhy5K/10/ ) . Now i want to disable the button click i.e play/pause if the sound is playing like Get ready,5,4,3,2,1 .
I know only how to disable the form submit button , but I am very confused how to disable the click in my case the hyperlinks.
Explanation using code example:
I want to disable this
PLAY
click, while interpreter is executing the below code:
var playGetReady = function (done) {
var ids = ['audiosource', 'a_5', 'a_4', 'a_3', 'a_2', 'a_1'],
playNext = function () {
var id = ids.shift();
document.getElementById(id).play();
if (ids.length) {
setTimeout(playNext, 1000);
} else {
done();
}
};
playNext();
};
Warning: This JS fiddle demo may play sound on load
You may try this (Changes in following function), but not sure if this is you want and maybe there are other ways to do it.
App.prototype.start = function () {
var self = this;
// unbind for a while
self.$button.unbind('click', self.buttonHandler); // <--
var start = function () {
// start countdown
self.intervalHandle = setInterval($.proxy(self.tick, self), 1000);
// bind again
self.$button.click($.proxy(self.buttonHandler, self)); // <--
// change button text to PAUSE
self.$button.text('PAUSE');
};
if (this.newTimer) {
playGetReady(start);
} else {
start();
}
};
DEMO.
In jquery, it can be done easily by cancel default action. Here's the sample.
$("#btn_start").click(function(event){
if(not_active_flag){
// Prevent anchor to active
return false;
}else{
// Anchor active as usual
return true;
}
});
In your case, the link will ultimately call this.buttonHandler, which has the following code:
App.prototype.buttonHandler = function (e) {
e.preventDefault(); // prevent anchor default action
this.toggle(); // toggle play/pause
};
Because buttonHandler is attached before playGetReady is executed, it is not possible to let playGetReady attach a click handler to that anchor element that uses .stopImmediatePropagation() to prevent the other click handler from executing.
In this case #gp.'s solution in the comments is most likely the best solution. In your case you might even be able to use a local variable in your app. If you use a global variable, reference it with window.yourglobalvariable. If you use a local variable, make sure you define it somewhere and reference it with this.yourvariable. Change your buttonHandler to:
App.prototype.buttonHandler = function (e) {
e.preventDefault(); // prevent anchor default action
if( this.soundready )
this.toggle(); // toggle play/pause
};
On the appropiate place make this variable false to prevent the 'button' from working. When the button should work, change the variable to true. I think that should be just before done() in the code you have in your question, but you probably have a better idea in what order the code is executed.

Do not fire one event if already fired another

I have a code like this:
$('#foo').on('click', function(e) {
//do something
});
$('form input').on('change', function(e) {
//do some other things
));
First and second events do actually the same things with the same input field, but in different way. The problem is, that when I click the #foo element - form change element fires as well. I need form change to fire always when the content of input is changing, but not when #foo element is clicked.
That's the question )). How to do this?
Here is the code on jsfiddle: http://jsfiddle.net/QhXyj/1/
What happens is that onChange fires when the focus leaves the #input. In your case, this coincides with clicking on the button. Try pressing Tab, THEN clicking on the button.
To handle this particular case, one solution is to delay the call to the change event enough check if the button got clicked in the meantime. In practice 100 milisecond worked. Here's the code:
$().ready(function() {
var stopTheChangeBecauseTheButtonWasClicked = false;
$('#button').on('click', function(e) {
stopTheChangeBecauseTheButtonWasClicked = true;
$('#wtf').html("I don't need to change #input in this case");
});
$('#input').on('change', function(e) {
var self = this;
setTimeout(function doTheChange() {
if (!stopTheChangeBecauseTheButtonWasClicked) {
$(self).val($(self).val() + ' - changed!');
} else {
stopTheChangeBecauseTheButtonWasClicked = false;
}
}, 100);
});
});
And the fiddle - http://jsfiddle.net/dandv/QhXyj/11/
It's only natural that a change event on a blurred element fires before the clicked element is focused. If you don't want to use a timeout ("do something X ms after the input was changed unless in between a button was clicked", as proposed by Dan) - and timeouts are ugly - you only could go doing those actions twice. After the input is changed, save its state and do something. If then - somewhen later - the button is clicked, retrieve the saved state and do the something similar. I guess this is what you actually wanted for your UI behaviour, not all users are that fast. If one leaves the input (e.g. by pressing Tab), and then later activates the button "independently", do you really want to execute both actions?
var inputval = null, changedval = null;
$('form input').on('change', function(e) {
inputval = this.value;
// do some things with it and save them to
changedval = …
// you might use the value property of the input itself
));
$('#foo').on('click', function(e) {
// do something with inputval
});
$('form …').on('any other action') {
// you might want to invalidate the cache:
inputval = changedval;
// so that from now on a click operates with the new value
});
$(function() {
$('#button').on('click', function() {
//use text() not html() here
$('#wtf').text("I don't need to change #input in this case");
});
//fire on blur, that is when user types and presses tab
$('#input').on('blur', function() {
alert("clicked"); //this doesn't fire when you click button
$(this).val($(this).val()+' - changed!');
});
});​
Here's the Fiddle
$('form input').on('change', function(e) {
// don't do the thing if the input is #foo
if ( $(this).attrib('id') == 'foo' ) return;
//do some other things
));
UPDATE
How about this:
$().ready(function() {
$('#button').on('click', function(e) {
$('#wtf').html("I don't need to change #input in this case");
});
$('#input').on('change', function(e) {
// determine id #input is in focus
if ( ! $(this).is(":focus") ) return;
$(this).val($(this).val()+' - changed!');
});
});

Detect Textbox Field Change jQuery

I have a text box that accepts integers, and I need it to run a function that will use the text box's input, as soon as a user inputs numbers into the field.
The problem here is that keyUp() will detect each and every input. So if I type 23, it will fire once for 2 and once for 3. I only need it to run when the input is complete.
Is there a way to do this, without losing focus and without using a timer that will keep checking the text box input every while using setInterval?
Look like you want to be notified when the user stops typing. The following code can be used as a starting point, it calls bufferedKeyUp 300 ms after the user stops typing. http://jsfiddle.net/mendesjuan/VTMEe/
$(function() {
// Creates a handler that will wait until the event hasn't fired for a period
// before it fires the actual event handler
function createBuffered(fun, delay) {
var timer;
return function() {
clearTimeout(timer);
var args = arguments;
var me = this;
timer = setTimeout(function() {
fun.apply(me, args);
}, delay);
}
}
$('#in').keyup( createBuffered(function(){
console.log('change');
}, 300));
});​
Ext-JS has a nice simple way to do this http://jsfiddle.net/mendesjuan/DYkmU/1/
Ext.get('myid').on('keyup', function() {
console.log('change');
}, null, {buffer: 300});
Why not test the textbox contents after they're changed, after all that's when input is complete isn't it?
If the result is not okay, you can always clear and focus the textbox so the user has to enter valid data.
Something like:
$("textbox").change( function () {
if (someTestForGoodData) {
handleTheGoodData();
} else {
$(this).focus();
alert($(this) + " has bad data!");
}
})
$('input').on('input propertychange', function() {
$('#output').html($(this).val().length + ' characters');
});
From this answer.

Categories

Resources