Keep track of changes in html table/form - javascript

What I'm trying to achieve is to keep track of any changes (e. g. user input, field added, ...) within a <table>-element.
In my specific scenario users can edit fields, add rows, add fields, remove fields and rows, select something in <select>-elements, etc.
Of course I could just attach my "change"-listener to all of those actions, but I think there must be a better way.
I tried attaching a $('#myTable tbody').change()-listener to it, but that doesn't fire...
Maybe some of you know of a way to keep track of table changes without having to subscribe to every possible user action manually?

You can use Jquery liveQuery Plugin
Below is the example for mouse over and mouse out. you can do it for all the events likewise
$('table')
.livequery(function(){
// use the helper function hover to bind a mouseover and mouseout event
$(this)
.hover(function() {
$(this).addClass('hover');
}, function() {
$(this).removeClass('hover');
});
}, function() {
// unbind the mouseover and mouseout events
$(this)
.unbind('mouseover')
.unbind('mouseout');
});

Edit: As I understand it, jQuery 1.4+ should actually support the described behavior. I'll leave the rest of my post for reference.
You can add the event to every changeable element, because that is where they are fired. However, you won't have to do it manually:
$('#myTable input, #myTable select, ...).change(...)
If, as you said, there are elements added later on, you might want to look into the .live method that allows you to bind event listeners to elements that are to be created later on.

To answer my own question:
I decided on doing it kinda like #mdsl suggested:
I now listen for changes like this:
$('#myTable tbody').on('focusout', 'input, select, checkbox', myListener);

Related

jQuery remove scroll listener after reach certain point [duplicate]

I have an input type="image". This acts like the cell notes in Microsoft Excel. If someone enters a number into the text box that this input-image is paired with, I setup an event handler for the input-image. Then when the user clicks the image, they get a little popup to add some notes to the data.
My problem is that when a user enters a zero into the text box, I need to disable the input-image's event handler. I have tried the following, but to no avail.
$('#myimage').click(function { return false; });
jQuery ≥ 1.7
With jQuery 1.7 onward the event API has been updated, .bind()/.unbind() are still available for backwards compatibility, but the preferred method is using the on()/off() functions. The below would now be,
$('#myimage').click(function() { return false; }); // Adds another click event
$('#myimage').off('click');
$('#myimage').on('click.mynamespace', function() { /* Do stuff */ });
$('#myimage').off('click.mynamespace');
jQuery < 1.7
In your example code you are simply adding another click event to the image, not overriding the previous one:
$('#myimage').click(function() { return false; }); // Adds another click event
Both click events will then get fired.
As people have said you can use unbind to remove all click events:
$('#myimage').unbind('click');
If you want to add a single event and then remove it (without removing any others that might have been added) then you can use event namespacing:
$('#myimage').bind('click.mynamespace', function() { /* Do stuff */ });
and to remove just your event:
$('#myimage').unbind('click.mynamespace');
This wasn't available when this question was answered, but you can also use the live() method to enable/disable events.
$('#myimage:not(.disabled)').live('click', myclickevent);
$('#mydisablebutton').click( function () { $('#myimage').addClass('disabled'); });
What will happen with this code is that when you click #mydisablebutton, it will add the class disabled to the #myimage element. This will make it so that the selector no longer matches the element and the event will not be fired until the 'disabled' class is removed making the .live() selector valid again.
This has other benefits by adding styling based on that class as well.
This can be done by using the unbind function.
$('#myimage').unbind('click');
You can add multiple event handlers to the same object and event in jquery. This means adding a new one doesn't replace the old ones.
There are several strategies for changing event handlers, such as event namespaces. There are some pages about this in the online docs.
Look at this question (that's how I learned of unbind). There is some useful description of these strategies in the answers.
How to read bound hover callback functions in jquery
If you want to respond to an event just one time, the following syntax should be really helpful:
$('.myLink').bind('click', function() {
//do some things
$(this).unbind('click', arguments.callee); //unbind *just this handler*
});
Using arguments.callee, we can ensure that the one specific anonymous-function handler is removed, and thus, have a single time handler for a given event. Hope this helps others.
maybe the unbind method will work for you
$("#myimage").unbind("click");
I had to set the event to null using the prop and the attr. I couldn't do it with one or the other. I also could not get .unbind to work. I am working on a TD element.
.prop("onclick", null).attr("onclick", null)
If event is attached this way, and the target is to be unattached:
$('#container').on('click','span',function(eo){
alert(1);
$(this).off(); //seams easy, but does not work
$('#container').off('click','span'); //clears click event for every span
$(this).on("click",function(){return false;}); //this works.
});​
You may be adding the onclick handler as inline markup:
<input id="addreport" type="button" value="Add New Report" onclick="openAdd()" />
If so, the jquery .off() or .unbind() won't work. You need to add the original event handler in jquery as well:
$("#addreport").on("click", "", function (e) {
openAdd();
});
Then the jquery has a reference to the event handler and can remove it:
$("#addreport").off("click")
VoidKing mentions this a little more obliquely in a comment above.
If you use $(document).on() to add a listener to a dynamically created element then you may have to use the following to remove it:
// add the listener
$(document).on('click','.element',function(){
// stuff
});
// remove the listener
$(document).off("click", ".element");
To remove ALL event-handlers, this is what worked for me:
To remove all event handlers mean to have the plain HTML structure without all the event handlers attached to the element and its child nodes. To do this, jQuery's clone() helped.
var original, clone;
// element with id my-div and its child nodes have some event-handlers
original = $('#my-div');
clone = original.clone();
//
original.replaceWith(clone);
With this, we'll have the clone in place of the original with no event-handlers on it.
Good Luck...
Updated for 2014
Using the latest version of jQuery, you're now able to unbind all events on a namespace by simply doing $( "#foo" ).off( ".myNamespace" );
Best way to remove inline onclick event is $(element).prop('onclick', null);
Thanks for the information. very helpful i used it for locking page interaction while in edit mode by another user. I used it in conjunction with ajaxComplete. Not necesarily the same behavior but somewhat similar.
function userPageLock(){
$("body").bind("ajaxComplete.lockpage", function(){
$("body").unbind("ajaxComplete.lockpage");
executePageLock();
});
};
function executePageLock(){
//do something
}
In case .on() method was previously used with particular selector, like in the following example:
$('body').on('click', '.dynamicTarget', function () {
// Code goes here
});
Both unbind() and .off() methods are not going to work.
However, .undelegate() method could be used to completely remove handler from the event for all elements which match the current selector:
$("body").undelegate(".dynamicTarget", "click")
I know this comes in late, but why not use plain JS to remove the event?
var myElement = document.getElementById("your_ID");
myElement.onclick = null;
or, if you use a named function as an event handler:
function eh(event){...}
var myElement = document.getElementById("your_ID");
myElement.addEventListener("click",eh); // add event handler
myElement.removeEventListener("click",eh); //remove it
This also works fine .Simple and easy.see http://jsfiddle.net/uZc8w/570/
$('#myimage').removeAttr("click");
if you set the onclick via html you need to removeAttr ($(this).removeAttr('onclick'))
if you set it via jquery (as the after the first click in my examples above) then you need to unbind($(this).unbind('click'))
All the approaches described did not work for me because I was adding the click event with on() to the document where the element was created at run-time:
$(document).on("click", ".button", function() {
doSomething();
});
My workaround:
As I could not unbind the ".button" class I just assigned another class to the button that had the same CSS styles. By doing so the live/on-event-handler ignored the click finally:
// prevent another click on the button by assigning another class
$(".button").attr("class","buttonOff");
Hope that helps.
Hope my below code explains all.
HTML:
(function($){
$("#btn_add").on("click",function(){
$("#btn_click").on("click",added_handler);
alert("Added new handler to button 1");
});
$("#btn_remove").on("click",function(){
$("#btn_click").off("click",added_handler);
alert("Removed new handler to button 1");
});
function fixed_handler(){
alert("Fixed handler");
}
function added_handler(){
alert("new handler");
}
$("#btn_click").on("click",fixed_handler);
$("#btn_fixed").on("click",fixed_handler);
})(jQuery);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btn_click">Button 1</button>
<button id="btn_add">Add Handler</button>
<button id="btn_remove">Remove Handler</button>
<button id="btn_fixed">Fixed Handler</button>
I had an interesting case relevant to this come up at work today where there was a scroll event handler for $(window).
// TO ELIMINATE THE RE-SELECTION AND
// RE-CREATION OF THE SAME OBJECT REDUNDANTLY IN THE FOLLOWING SNIPPETS
let $window = $(window);
$window.on('scroll', function() { .... });
But, to revoke that event handler, we can't just use
$window.off('scroll');
because there are likely other scroll event handlers on this very common target, and I'm not interested in hosing that other functionality (known or unknown) by turning off all of the scroll handlers.
My solution was to first abstract the handler functionality into a named function, and use that in the event listener setup.
function handleScrollingForXYZ() { ...... }
$window.on('scroll', handleScrollingForXYZ);
And then, conditionally, when we need to revoke that, I did this:
$window.off('scroll', $window, handleScrollingForXYZ);
The janky part is the 2nd parameter, which is redundantly selecting the original selector. But, the jquery documentation for .off() only provides one method signature for specifying the handler to remove, which requires this middle parameter to be
A selector which should match the one originally passed to .on() when attaching event handlers.
I haven't ventured to test it out with a null or '' as the 2nd parameter, but perhaps the redundant $window isn't necessary.

Javascript - bind to keys events, except if user is in a text input

So I have this page, in which the user can use the directional keys to navigate between different items. For that, I use a jquery binder :
$(document.body).bind('keydown', function(event) {
// use the directional keys
I want this event work at every time, except if the user is focused in a text input.
So I tried to filter out the event like this:
$(document.body).bind('keydown', '*:not(input[type="text"], textarea)', function(event) {
but unfortunately the filter does not work, and the event fires in every case.
I could detect the focus (and blur) events on every input in my page, and deactivate the move event via a global boolean, however I find it quite inelegant.
Is there a way to either let the input fields "consume" the events, or to filter the event with a reverse selector like I tried to do ?
Thanks in advance,
That isn't valid .bind() syntax. Events passed to .bind() cannot be delegated.
You probably mean to use .on():
$(document.body).on('keydown', '*:not(input[type="text"], textarea)', function(event) {
});
JSFiddle
If you are using a jQuery version prior to .on() (which you shouldn't be..) you can use delegate():
$(document.body).delegate('*:not(input[type="text"], textarea)', 'keydown', function(event){
});
I couldn't make the selector on on() work, so I finally solved the problem by filtering on event.target after reception:
$(document.body).on('keydown', function(event) {
if (!$(event.target).is('input[type="text"], textarea')){
// handle keys...
(the solution was proposed by someone who deleted his answer, so I retrace it here)

Javascript, jQuery - how signed actions to just created object?

I am trying to make simple list with ability to add and delete elements. For now I am working on adding and performing a simple action on each of list elements object (existing and added). Unfortunately I have met some difficulties with that. I am able to modify objects that are created at the beginning, but not one added during "webpage working".
First of all my idea was to add AJAX to this, but I don't think it is the easiest way.
I think that some time ago (I don't remember where) I read how to make this work, but now I don't know. I would be really glad if someone would help me with this or at least give a link to good explanation of this.
There is what I have done so far (well this is mostly just a scratch, but the main idea is in it): http://jsfiddle.net/sebap123/pAZ7H/0
$("li").click(function() {
$(this).text("new text");
});
$("#addButton").click(function() {
$(".list").append(
$('<li>').append($('<span>').append("added li")));
});​
Thank you for all responses.
You just need to use event-delegation, with the on() method:
$("ul").on('click','li', function() {
$(this).text("OK");
});
JS Fiddle demo.
The problem you were experiencing is that jQuery can only directly bind events to already-present elements (present at the point of event-binding); the on() approach binds the action to the element to which the new content is added (or an ancestor element of the newly-added elements), identifies the events to listen for 'click' (a space-separated list of events), that match the selector (li) and then the function performs the required actions.
If you're using jQuery 1.7 (or later) on() should be used, for versions of jQuery < 1.7, delegate() should be used instead (which does more or less the same thing, but reverses the event-list and the selector parameters):
$("ul").delegate('li', 'click', function() {
$(this).text("OK");
});
JS Fiddle demo.
References:
delegate().
on().
Need to use event delegation here..
Try this
$("ul").on('click' , 'li', function() {
$(this).text("OK");
});
The problem with the previous click event is that events are only attched to the current element's on the page..
But when you create a new element , no events are attached to the element.
You have two options here.. Either to delegate your event i.e; add the event listerner to the element's ancestor ..
Or add the event once the element is created..
2nd Approach
var clickEvent = function() {
$('li').unbind().on('click', function() {
$(this).text("OK");
});
}
clickEvent();
$("#addButton").click(function() {
$(".list").append(
$('<li>').append($('<span>').append("Press me - I am new!")));
clickEvent();
});​
In the second approach you are binding unbinding and binding the new event to all the elements once a new element is added..
Binding and again rebinding of events is a bad design pattern
FIDDLE
2nd APPROACH

call js script on every change state

i have big table with many html items such as select, textbox, radio-button, checkbox. also i have some function. i want to call this function on every change in item. for example select was changed, or some text type in textbox, or click radiobutton. how can i simply subscribes and call my js function? i can insert in any item
onchange='function()'
but may be jquery allow more simly way? any sample?
jQuery's .change() event will work for all types of input elements.
But for efficiency, if you've got a lot of elements, you might want to look into .delegate():
$('body').delegate('input', 'change', function() {
// in here, $(this) is the input that has changed
});
Delegating is more efficient since it creates only a single handler and makes use of event bubbling.
In JQuery, you could use a .click() event on the items you want to change. For example:
$("#the-element").click(function(){
//Enter your function here
});
Hope that helps!
You can use a jQuery selector to wrap all the items you want the event attached to. Then, use bind method on that wrapper to attach events.
An example:
$('input').bind({
click: function() {
// do something on click
},
mouseenter: function() {
// do something on mouseenter
}
});

jQuery event after dom tree change

I am using jQuery events like mouseover and mouseout.
When a user fires the mouseover on the target element, this element receives a new class (with removeClass and addClass).
Then, when the mouse gets out, mouseout is fired, but the selector of the element having the mouseout event doesn't match anymore, because I changed the class.
Example :
$('span.project_unsel').mouseover(function() {
$(this).removeClass('project_unsel');
$(this).addClass('project_sel');
});
After firing the above event, class has changed and the following doesn't get fired.
$('span.project_sel').mouseout(function() {
$(this).removeClass('project_sel');
$(this).addClass('project_unsel');
});
How can I tell jQuery to "update" or "bind" again too understand this ?
Many thanks !
I would suggest doing something like this instead, to makes things less confusing:
$('span.project').hover(function() {
$(this).addClass('selected');
}, function() {
$(this).removeClass('selected');
});
That is, bind .hover to elements with the class .project, and simply add and remove the .selected class when the mouseenter (first argument) and mouseleave (second argument) events are triggered.
Take a look at .hover.
There are quite a few ways to fix this, but if you want to minimize your code changes you can just add another class to your target elements that doesn't change, then bind to that.
If you can't add an additional class for some reason, try this:
$('span.project_sel,span.project_unsel').mouseout(function() {
$(this).removeClass('project_sel').addClass('project_unsel');
}).mouseover(function() {
$(this).removeClass('project_unsel').addClass('project_sel');
});
You could also take a look at toggleClass() if you feel add/remove is inelegant.
Edit: Karim's hover solution is better than doing it via mouseout/mouseover.

Categories