This is how i populate the table
I'm having some trouble with the datatables plugin for jquery. The table is populated dynamically, I have 3 columns with text and a fourth column which consists of a delete and an edit button. For the edit button I have a modal, and if I confirm the changes, it does indeed change the specific line in the table.
However, if I click on several edit buttons and cancel, when I actually want to change one it changes all the previously canceled lines.
Here is the relevant code:
$("#example").on("click", ".edit-button", function() {
$("#edit-modal").modal("show");
saveChanges(this);
});
function saveChanges(k) {
$("#edit-confirm").click(function() {
$(".itm-loader-modal").show();
setTimeout(function() {editJob(k);},1000);
});
}
function editJob(currentButton) {
$(".itm-loader-modal").fadeOut("slow");
var editedName = $("#job-name").val();
var editedDescription = $("#job-description").val();
var editedCompany = $("#job-company").val();
var data = {
"name":editedName,
"description": editedDescription,
"company": editedCompany
};
var currentLine = $(currentButton).parent().parent().children();
currentLine.eq(0).text(data.name);
currentLine.eq(1).text(data.description);
currentLine.eq(2).text(data.company);
$("#edit-modal").modal("hide");
}
Hard to say for sure, but one think that looks wrong is that each time saveChanges is called, you register new event listener on #edit-confirm button.
Once that #edit-confirm is clicked, it will execute all the registered event handlers – one for each .edit-button click.
Instead, you probably want to have a single #edit-confirm click handler and find a way to pass the info about the line that's currently being edited to it.
Cheers.
so when you call saveChanges it assign event handler to "#edit-confirm", all those event handlers are executed at once,
to avoid it you should attach event handler to it via delegation or i think this quick fix should work
$(this).find('#edit-confirm').click(function() {
/...
})
I was asked to refresh a page (and it's data) based on the user's selection of an option in a select box.
I know that using the onChange event is the standard way to detect that a user changed their selection in a selectbox and I've done this a lot:
$("#provider").change(function(){
var selectedprovider = $('#provider').val();
//... Do something
});
I've also seen cases where certain browsers (IE) fire change events when a mouse wheel or arrow keys are being used to interact with the selectbox, not the actual event of changing an option selection.
Is there a better way to deal with this kind of scenario? For example checking to see if the array index of the selected option has changed? Not sure that there is an event for that specifically.
I am thinking it might be best to simply add a submit button next to the select box and stop trying to rely on the onChange event for select boxes.
How are you all handling this scenario?
One way would be to check to see if the value has actually changed at all since you registered your event. That would be one way to determine if the value is different or not.
Here's an example: http://jsfiddle.net/p9v7x/1/
$(function () {
var lastVal = $('#target').val();
$('#target').on('change', function () {
var self = $(this);
if (self.val() === lastVal) {
// don't do anything if it's the same:
console.log('same!');
} else {
// only do your action in this case:
console.log(self.val());
}
});
});
In jqGrid, I am currently disabling row select with the following:
beforeSelectRow: function() {
return false;
}
This works fine for left clicking. However, I noticed it's not firing the beforeSelectRow event handler and still selecting the row when I right click. This is a problem for me since I'm implementing a custom context menu.
I am able to get around this with what asker himself admitted is a hack found here:
Is it possible to Stop jqGrid row(s) from being selected and/or highlighted?
Is there any other, less hacky way to do this?
Thanks!
Update
It appears this is only a problem with subgrids. Please refer to this example. You'll notice left clicking does not select the row but right clicking does.
(I took the lazy way out and stole this example from an answer to a different question provided by Oleg.)
If you want to disable the row select, you can config onSelectRow to return false, this will block both left click and right click.
onSelectRow: function() {
return false;
}
To force unselect row on right click:
onRightClickRow: function () {
grid.jqGrid('resetSelection');
return false;
}
In jqGrid, Is there a "built-in" way to know what mouse button was clicked, before row selection?
Currently we have jqGrid with some actions bind on "onSelectRow" event of jqGrid. The problem is that when user right click on that row, onSelectRow event raised to and action performed. What I need, is to ignore "onSelectRow" when user right click on a row.
EDIT: I know there exists onRightClickRow event, but it raised after onSelectRow and action already performed.
I found that I can know what button clicked by "type" of event object. When it's click, the type is "click" when it's right click, the type is "contextmenu"....Does exists the additional way, or I must check type to know what button is clicked?
Thanks
It's good question! The reason of such behavior is the following. jqGrid register an event handler for the event contextmenu on the whole grid <table> element with the following code (see here)
.bind('contextmenu', function(e) {
td = e.target;
ptr = $(td,ts.rows).closest("tr.jqgrow");
if($(ptr).length === 0 ){return;}
if(!ts.p.multiselect) { $(ts).jqGrid("setSelection",ptr[0].id,true,e); }
ri = ptr[0].rowIndex;
ci = $.jgrid.getCellIndex(td);
$(ts).triggerHandler("jqGridRightClickRow", [$(ptr).attr("id"),ri,ci,e]);
if ($.isFunction(this.p.onRightClickRow)) {
ts.p.onRightClickRow.call(ts,$(ptr).attr("id"),ri,ci, e);
}
});
How one can see from the code it calls setSelection method and calls onRightClickRow callback and trigger jqGridRightClickRow event. So if you don't need the selection of rows and if you don't use onRightClickRow and jqGridRightClickRow you can just unbind the event handler:
$("#list").unbind("contextmenu");
If you do want use onRightClickRow callback or if you don't sure whether you need to use jqGridRightClickRow somewhere you can "subclass" the event handler. The implementation is depend a little from the version of jQuery which you use. Starting with jQuery 1.8 one should use a little another call to get the current events registered on the DOM element. The corresponding code could be about the following:
//$grid.unbind('contextmenu');
var getEvents = $._data($grid[0], "events"); // $grid.data("events") in jQuery ver<1.8
if (getEvents && getEvents.contextmenu && getEvents.contextmenu.length === 1) {
var orgContextmenu = getEvents.contextmenu[0].handler;
$grid.unbind('contextmenu', orgContextmenu);
$grid.bind('contextmenu', function(e) {
var oldmultiselect = this.p.multiselect, result;
this.p.multiselect = true; // set multiselect to prevent selection
result = orgContextmenu.call(this, e);
this.p.multiselect = oldmultiselect; // restore multiselect
return result;
});
}
The demo demonstrate the above code live.
Events are listed here: http://www.trirand.com/jqgridwiki/doku.php?id=wiki:events
There is an onRightClickRow event.
Also, using the plain jquery event object and which will tell you. http://api.jquery.com/event.which/
You must use 3rd parameter to onRowSelected and which or the type like you mentioned.
There are many ways the value of a <input type="text"> can change, including:
keypresses
copy/paste
modified with JavaScript
auto-completed by browser or a toolbar
I want my JavaScript function to be called (with the current input value) any time it changes. And I want it to be called right away, not just when the input loses focus.
I'm looking for the cleanest and most robust way to do this across all browsers (using jQuery preferably).
This jQuery code uses .bind() to catch immediate changes to any element, and should work across all browsers:
$('.myElements').each(function() {
var elem = $(this);
// Save current value of element
elem.data('oldVal', elem.val());
// Look for changes in the value
elem.bind("propertychange change click keyup input paste", function(event){
// If value has changed...
if (elem.data('oldVal') != elem.val()) {
// Updated stored value
elem.data('oldVal', elem.val());
// Do action
....
}
});
});
However, note that .bind() was deprecated in jQuery version 3.0. Anyone using jQuery version 1.7 or newer should use .on() instead.
A real-time solution for jQuery >= 1.7 is on
$("#input-id").on("change keyup paste", function(){
dosomething();
})
if you also want to detect "click" event, just:
$("#input-id").on("change keyup paste click", function(){
dosomething();
})
if you're using jQuery <= 1.6, just use bind or live instead of on.
Unfortunately, I think setInterval wins the prize:
<input type=text id=input_id />
<script>
setInterval(function() { ObserveInputValue($('#input_id').val()); }, 100);
</script>
It's the cleanest solution, at only 1 line of code. It's also the most robust, since you don't have to worry about all the different events/ways an input can get a value.
The downsides of using 'setInterval' don't seem to apply in this case:
The 100ms latency? For many applications, 100ms is fast enough.
Added load on the browser? In general, adding lots of heavy-weight setIntervals on your page is bad. But in this particular case, the added page load is undetectable.
It doesn't scale to many inputs? Most pages don't have more than a handful of inputs, which you can sniff all in the same setInterval.
Binding to the input event seems to work fine in most sane browsers. IE9 supports it too, but the implementation is buggy (the event is not fired when deleting characters).
With jQuery version 1.7+ the on method is useful to bind to the event like this:
$(".inputElement").on("input", null, null, callbackFunction);
Unfortunately there is no event or set of events that matches your criteria. Keypresses and copy/paste can both be handled with the keyup event. Changes through JS are trickier. If you have control over the code that sets the textbox, your best bet is to modify it to either call your function directly or trigger a user event on the textbox:
// Compare the textbox's current and last value. Report a change to the console.
function watchTextbox() {
var txtInput = $('#txtInput');
var lastValue = txtInput.data('lastValue');
var currentValue = txtInput.val();
if (lastValue != currentValue) {
console.log('Value changed from ' + lastValue + ' to ' + currentValue);
txtInput.data('lastValue', currentValue);
}
}
// Record the initial value of the textbox.
$('#txtInput').data('lastValue', $('#txtInput').val());
// Bind to the keypress and user-defined set event.
$('#txtInput').bind('keypress set', null, watchTextbox);
// Example of JS code triggering the user event
$('#btnSetText').click(function (ev) {
$('#txtInput').val('abc def').trigger('set');
});
If you don't have control over that code, you could use setInterval() to 'watch' the textbox for changes:
// Check the textbox every 100 milliseconds. This seems to be pretty responsive.
setInterval(watchTextbox, 100);
This sort of active monitoring won't catch updates 'immediately', but it seems to be fast enough that there is no perceptible lag. As DrLouie pointed out in comments, this solution probably doesn't scale well if you need to watch lots of inputs. You can always adjust the 2nd parameter to setInterval() to check more or less frequently.
Here is a solution that doesn't make use of jQuery (Its really quite obsolete and not necessary these days)
Using the event "input" you can look for any kind of change:
Deleting, Backspacing, Pasting, Typing, anything that will change the inputs value.
The input event is directly related to the text input. ANY time the text is changed in ANY fashion, input is dispatched.
document.querySelector("#testInput").addEventListener("input", test);
function test(e) {
var a = document.getElementById('output');
a.innerText += "Detected an Update!\n";
}
<input id="testInput">
<br>
<a id="output"></a>
Here is a slightly different solution if you didn't fancy any of the other answers:
var field_selectors = ["#a", "#b"];
setInterval(function() {
$.each(field_selectors, function() {
var input = $(this);
var old = input.attr("data-old-value");
var current = input.val();
if (old !== current) {
if (typeof old != 'undefined') {
... your code ...
}
input.attr("data-old-value", current);
}
}
}, 500);
Consider that you cannot rely on click and keyup to capture context menu paste.
Add this code somewhere, this will do the trick.
var originalVal = $.fn.val;
$.fn.val = function(){
var result =originalVal.apply(this,arguments);
if(arguments.length>0)
$(this).change(); // OR with custom event $(this).trigger('value-changed');
return result;
};
Found this solution at val() doesn't trigger change() in jQuery
I have created a sample. May it will work for you.
var typingTimer;
var doneTypingInterval = 10;
var finaldoneTypingInterval = 500;
var oldData = $("p.content").html();
$('#tyingBox').keydown(function () {
clearTimeout(typingTimer);
if ($('#tyingBox').val) {
typingTimer = setTimeout(function () {
$("p.content").html('Typing...');
}, doneTypingInterval);
}
});
$('#tyingBox').keyup(function () {
clearTimeout(typingTimer);
typingTimer = setTimeout(function () {
$("p.content").html(oldData);
}, finaldoneTypingInterval);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<textarea id="tyingBox" tabindex="1" placeholder="Enter Message"></textarea>
<p class="content">Text will be replace here and after Stop typing it will get back</p>
http://jsfiddle.net/utbh575s/
We actually don't need to setup loops for detecting javaScript changes.
We already setting up many event listeners to the element we want to detect. just triggering any un harmful event will make the job.
$("input[name='test-element']").on("propertychange change click keyup input paste blur", function(){
console.log("yeh thats worked!");
});
$("input[name='test-element']").val("test").trigger("blur");
and ofc this is only available if you have the full control on javascript changes on your project.
Although this question was posted 10 years ago, I believe that it still needs some improvements. So here is my solution.
$(document).on('propertychange change click keyup input paste', 'selector', function (e) {
// Do something here
});
The only problem with this solution is, it won't trigger if the value changes from javascript like $('selector').val('some value'). You can fire any event to your selector when you change the value from javascript.
$(selector).val('some value');
// fire event
$(selector).trigger('change');
Or in a single line
$(selector).val('some value').trigger('change');
Well, best way is to cover those three bases you listed by yourself. A simple :onblur, :onkeyup, etc won't work for what you want, so just combine them.
KeyUp should cover the first two, and if Javascript is modifying the input box, well I sure hope it's your own javascript, so just add a callback in the function that modifies it.
Here's a working example that I'm using to implement an autocomplete variation the populates a jqueryui selector (list), but I don't want it to function exactly like the jqueryui autocomplete which does a drop-down menu.
$("#tagFilter").on("change keyup paste", function() {
var filterText = $("#tagFilter").val();
$("#tags").empty();
$.getJSON("http://localhost/cgi-bin/tags.php?term=" + filterText,
function(data) {
var i;
for (i = 0; i < data.length; i++) {
var tag = data[i].value;
$("#tags").append("<li class=\"tag\">" + tag + "</li>");
}
});
});
Can't you just use <span contenteditable="true" spellcheck="false"> element in place of <input type="text">?
<span> (with contenteditable="true" spellcheck="false" as attributes) distincts by <input> mainly because:
It's not styled like an <input>.
It doesn't have a value property, but the text is rendered as innerText and makes part of its inner body.
It's multiline whereas <input> isn't although you set the attribute multiline="true".
To accomplish the appearance you can, of course, style it in CSS, whereas writing the value as innerText you can get for it an event:
Here's a fiddle.
Unfortunately there's something that doesn't actually work in IE and Edge, which I'm unable to find.
you can simply identify all changers in the form, like this
//when form change, show aleart
$("#FormId").change(function () {
aleart('Done some change on form');
});
You can bind the 'input' event to <input type="text">. This will trigger every time the input changes such as copy, paste, keypress, and so on.
$("#input-id").on("input", function(){
// Your action
})