I'm trying to create a function that auto-saves input entered into a few textboxs. I have 3 inputs in one selector($input), and a timer(typingTimer) that updates on keyup/paste and keydown. If after a keyup event the timer hasn't been reset after 3 seconds(doneTypingInterval), the element is sent to an autosave function that posts the elements name and value via ajax.
The issue I'm having is that if I type in an input (ie: #input-name), and a second later I type in another (ie: #input-shortName), the first input (#input-name) is never sent to the autosave function. Is there a good way to do this without creating a unique typingTimer and on events for each input? I tried it that way and it works, but I'm sure there has to be a better way.
let typingTimer;
const doneTypingInterval = 3000;
const $input = $('#input-name, #input-shortName, #input-email');
$input
.on('keyup paste', function () {
if($.fn.isAutoSaveOn()) {
clearTimeout(typingTimer);
typingTimer = setTimeout($.fn.autoSaving, doneTypingInterval, this);
}
})
.on('keydown', function () {
if($.fn.isAutoSaveOn()) {
clearTimeout(typingTimer);
}
})
;
$.fn.autoSaving = function(e) {
const autosave = $('#autosave')
if(autosave.hasClass('active')) {
autosave.html('<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> ' + lang_saving);
const element = $(e);
const url = '/v3/api/orgs/' + orgId + '/update';
const input = JSON.stringify({
field: element.attr('name'),
value: element.val()
});
$.ajax({
type: "POST",
url: url,
data: input,
contentType: "application/json"
})
.done(function(response) {
notify("Success", response, "bottom", "right", "ni ni-bell-55", "success", "animated fadeIn", "animated fadeOut");
})
.fail(function(response) {
notify("Error", response, "bottom", "right", "ni ni-bell-55", "error", "animated fadeIn", "animated fadeOut");
})
.always(function() {
$.fn.autoSaveOn();
});
}
}
Rather than trying to keep timeouts from overlapping each other, you could give the input a auto save timestamp and just check if that has passed.
let auto_save_timer = null;
$('input.auto-save').on('keyup paste', function() {
this.setAttribute('data-auto-save-timeout', (new Date()).getTime() + 3000); //set save time
if (!auto_save_timer) {
auto_save_timer = setInterval(function() {
let $inputs = $('input[data-auto-save-timeout]');
if ($inputs.length) {
$inputs.each(function() {
if ((new Date()).getTime() - this.attributes['data-auto-save-timeout'].value >= 0) {
this.removeAttribute('data-auto-save-timeout');
your_save_function(this);
}
});
} else {
clearInterval(auto_save_timer); //stops the timer
auto_save_timer = null; //for checking if the timer is active,
//clearInterval() doesn't make it false
//this prevents multiple timers from overlapping
}
}, 1000);
}
});
https://jsfiddle.net/sjmdqhgu/
Still using multiple timers but at least you don't have to declare everyone of them.
Create a function template
const doneTypingInterval = 3000
registerInput('input-name')
registerInput('input-shortName')
registerInput('input-email')
function registerInput (id) {
let typingTimer
$(`#${id}`).on('keyup paste', function () {
if ($.fn.isAutoSaveOn()) {
clearTimeout(typingTimer)
typingTimer = setTimeout($.fn.autoSaving, doneTypingInterval, this)
}
}).on('keydown', function () {
if ($.fn.isAutoSaveOn()) {
clearTimeout(typingTimer)
}
})
}
Related
I have a search field to allow users to filter the results that are returned from the database. I have it set so that the search field has a .on('input', function() { which will trigger another function.
This poses a problem in which if a user was to search for "crumble" the ajax request will be triggered for each character the user types in.
Is there a way to delay the JavaScript so that if the user is searching for a product, the function isn't fired for each character inputted, but will trigger when detected that the user hasn't typed something further in. I.E. when the user is done typing in what that are searching.
Code:
$(document).ready(function () {
$('#cards-search').on('input', function() {
cards_page = ''
cards_search = this.value;
get_card_data()
});
});
try this, this is called debouncing in case u need to search more about it
$(document).ready(function () {
let oldTimeout = null;
let timeToWaitBeforeSending = 1000 //ms
$('#cards-search').on('input', function () {
if (oldTimeout !== null) {
clearTimeout(oldTimeout);
}
timout = setTimeout(() => {
cards_page = '';
cards_search = this.value;
get_card_data();
}, timeToWaitBeforeSending );
});
});
// Run javascript function when user finishes typing instead of on key up?
var typingTimer;
var doneTypingInterval = 5000;
//on keyup, start the countdown
$('#cards-search').on('keyup', function () {
clearTimeout(typingTimer);
typingTimer = setTimeout(doneTyping, doneTypingInterval);
});
//on keydown, clear the countdown
$('#cards-search').on('keydown', function () {
clearTimeout(typingTimer);
});
//user is "finished typing," do something
function doneTyping () {
//do something
console.log("DOne");
}
Following VLAZ advice I looked into debouncing and it is exactly what I needed.
I followed the steps here
HTML:
<input type="search" id="cards-search" onkeyup="cardSearchChange()"...
Javascript:
function debounce(func, timeout = 250){
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => { func.apply(this, args); }, timeout);
};
}
function card_search() {
cards_page = '';
cards_search = document.getElementById('cards-search').value;
get_card_data();
}
cardSearchChange = debounce(() => card_search());
I have an input box (search box) to filter my html table. My query is able to filter the table alright but when i clear the search box it does not bring back the already existing data
For instance if i have
MacBook
Acer
and i search for M
it displays MacBook which is fine
but when i clear the M from the search box, the table still looks like
MacBook
instead of
MacBook
Acer
JS
<script>
$(document).ready(function () {
var typingTimer; //timer identifier
var doneTypingInterval = 100; //time in ms (5 seconds)
$("#query").on('keyup', function () {
clearTimeout(typingTimer);
if ($('#query').val()) {
typingTimer = setTimeout(doneTyping, doneTypingInterval);
}
});
});
function doneTyping() {
var key = $('#query').val();
$.ajax({
url: 'search/?query='+key,
type: 'GET',
beforeSend: function () {
// $("#table").slideUp('fast');
},
success: function (data) {
console.log(data);
$("#table").slideDown('fast');
var table = $("#table tbody");
table.html("");
$.each(data, function(idx, elem){
table.append(
//appending rows here
);
});
}
});
}
</script>
This code:
$("#query").on('keyup', function () {
clearTimeout(typingTimer);
if ($('#query').val()) {
typingTimer = setTimeout(doneTyping, doneTypingInterval);
}
});
is binded to a keyup event (ok) but will look if $('#query') has a value:
if ($('#query').val()) {
If you empty the input field this condition will be false.
Simply remove the if condition and this will work.
$("#query").on('keyup', function () {
clearTimeout(typingTimer);
typingTimer = setTimeout(doneTyping, doneTypingInterval);
});
When there is an update from getjson, the textbox text changed!
No allert is comminh up.. some one can help me with this allert??
The textbox:
<input id="your_textbox" />
setInterval(function () {
$.getJSOg('/api/my_apiurl', function (Payload) {
$(Payload).each(function (i, item) {
$("#your_textbox").val(item.CR_DateTime);
});
});
}, 3000);
and the script to allert "haai:
setInterval(function () {
jQuery('#your_textbox').on('input', function () {
alert('haai');
});
}, 3000);
Change to (not working):
setInterval(function () {
var check;
$(function(checkForMessages) {
$.getJSON('/api/myapiurl', function (data) {
if(data == 1) {
//There are new messages
clearInterval(check);
alert("You have mail!");
}
}
);
check = setInterval(checkForMessages, 3000);
});
}, 3000);
You keep adding an even to the textbox over and over and over again! That is really bad.
It should just be
jQuery('#your_textbox').on('input', function () {
alert('haai');
});
Now JavaScript does not trigger the event when you change the textbox with code, so you need to do the triggering.
var previousValue = $("#your_textbox").val(),
newValue = item.CR_DateTime;
if (previousValue !== newValue ) {
$("#your_textbox").val(newValue).trigger("input");
}
in this code:
$("a").live("click", function(e) {
e.preventDefault();
setTimeout(function () {
$.get(
"someOtherUrl",
{someVariable: "someValue"},
function(result) {
$(".result").html(render(result));
}
);
}, 1000);
$('a').live("touchmove", function(e) {clearTimeout()});
});
I want to stop the timeout when the user moves his finger on the screen. The thing is that clearTimeout() doesn't work because it is not linked to the timeout. How would I name the timeout and clear it quickly?
Am I using the right method?
Save the return value from "setTimeout()" in a variable, and then pass that value to "clearTimeout()" to clear it.
$("a").live("click", function(e) {
e.preventDefault();
var t = setTimeout(function () {
$.get(
"someOtherUrl",
{someVariable: "someValue"},
function(result) {
$(".result").html(render(result));
}
);
}, 1000);
$('a').live("touchmove", function(e) {clearTimeout(t);});
});
Now I would actually write that quite differently; as it is, you're adding a redundant "touchmove" handler on every click. Maybe something like this:
function setupAnchorClicks() {
var timer = null;
$("a").live("click", function(e) {
e.preventDefault();
timer = setTimeout(function() {
// ...
}, 1000);
}).live("touchmove", function() {
clearTimeout(timer);
});
}
setupAnchorClicks();
You'll have to save the handle received from setTimeout (it's a plain integer), and then pass it to clearTimeout as the argument.
var functionToCancel = function() {console.log("hello");}
var timeoutHandle = setTimeout(functionToCancel, 1000);
clearTimeout(timeoutHandle);
I added to my handler the function you shared, and it looks like this:
initMouseHandling:function(){
var dragged = null,
_mouseP,
selected,
nearest = null,
show = true,
num_console = 0,
timeout,
clicks,
delay = 500;
var handler = {
single_double_click: function (element, clicked, double_click, timeout) {
$(element).observe('click', function (event) {
++clicks;
if (clicks === 1) {
var timeoutCallback = function (event) {
if (clicks === 1) {
clicked.call(this, event);
} else {
double_click.call(this, event);
}
clicks = 0;
};
timeoutCallback.bind(this, event).delay(timeout / 1000);
}
}.bind(this));
return false;
},
clicked:function(e){
...
},
dragged:function(e){
...
},
dropped:function(e){
...
},
over_edge:function(e){
...
},
over_node:function(e){
...
},
double_click:function(e){
...
}}
canvas.mousemove(handler.over_node);
canvas.mousemove(handler.over_edge);
canvas.mousedown(handler.single_double_click);
//canvas.mousedown(handler.clicked);
//canvas.dblclick(handler.double_click);
}
It says:
"Uncaught TypeError: Object [object Object] has no method 'observe'"
Regardless of using $(canvas) or $(window) as I've seen in other places...
I don't know if I should introduce the handlers as parameters or not, why I cannot use "observe" and if for a case like mine I should call my handlers like that:
clicked.call(this, event);
double_click.call(this, event);
Any suggestions?
Have you looked into jQuery's dblclick?
There is no jquery function observe and the error tells you that.
To detect double clicks you start a timeout on the first click,
cancel it if clicked in timeout duration (200ms) and trigger single click or trigger double click on next click:
let timeout;
$("button").on("click", () => {
if (timeout) {
clearTimeout(timeout);
timeout = null;
alert("double click")
return;
}
timeout = setTimeout(() => {
alert("single click");
timeout = null;
}, 200); // 200ms, try other values for best ux
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button>Click me</button>