JQuery Detect class changes - javascript

I am using a plugin that added a class open to .slide-out-div when opened.
So I am trying to change some css if the open is detected.
What I need to do is
IF
$('.slide-out-div **open**') IS Detected then
$('.otherDiv').css('top','0px');
Not sure how to put this together...

There is no event of class-added, you will need to track it yourself...
It can be done with an infinite loop with setTimeout to check if the class has changed.
function checkForChanges()
{
if ($('.slide-out-div').hasClass('open'))
$('.otherDiv').css('top','0px');
else
setTimeout(checkForChanges, 500);
}
You can call the function when you want, or onDOM ready:
$(checkForChanges);

The question's a bit old, but since I came across while looking for a similar problem, thought I'd share the solution I went with here - Mutation Observers
In your case, I'd create a mutation observer
var mut = new MutationObserver(function(mutations, mut){
// if attribute changed === 'class' && 'open' has been added, add css to 'otherDiv'
});
mut.observe(document.querySelector(".slide-out-div"),{
'attributes': true
});
The function in mutation observer is called any time an attribute of .slide-out-div is changed, so need to verify the actual change before acting.
More details here on Mozilla's documentation page

You can use attrchange jQuery plugin. The main function of the plugin is to bind a listener function on attribute change of HTML elements.
Code sample:
$("#myDiv").attrchange({
trackValues: true, // set to true so that the event object is updated with old & new values
callback: function(evnt) {
if(evnt.attributeName == "class") { // which attribute you want to watch for changes
if(evnt.newValue.search(/open/i) == -1) { // "open" is the class name you search for inside "class" attribute
// your code to execute goes here...
}
}
}
});

Related

Run javascript function or eventlistner until attribute value changed [duplicate]

Is it possible in JavaScript to listen for a change of attribute value? For example:
var element=document.querySelector('…');
element.addEventListener( ? ,doit,false);
element.setAttribute('something','whatever');
function doit() {
}
I would like to respond to any change in the something attribute.
I have read up on the MutationObserver object, as well as alternatives to that (including the one which uses animation events). As far as I can tell, they are about changes to the actual DOM. I’m more interested in attribute changes to a particular DOM element, so I don’t think that’s it. Certainly in my experimenting it doesn’t seem to work.
I would like to do this without jQuery.
Thanks
You need MutationObserver, Here in snippet I have used setTimeout to simulate modifying attribute
var element = document.querySelector('#test');
setTimeout(function() {
element.setAttribute('data-text', 'whatever');
}, 5000)
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.type === "attributes") {
console.log("attributes changed");
// Example of accessing the element for which
// event was triggered
mutation.target.textContent = "Attribute of the element changed";
}
console.log(mutation.target);
});
});
observer.observe(element, {
attributes: true //configure it to listen to attribute changes
});
<div id="test">Dummy Text</div>
Additionally, mutation.target property gives the reference to mutated/changed node.
This question is already answered, but I'd like to share my experiences, because the mutation observer did not bring me the insights in needed.
Note This is some kind of hacky solution, but for (at least) debugging purposes quite good.
You can override the setAttribute function of a particalar element. This way you can also print the callstack, and get an insight of "who" changed the attribute value:
// select the target element
const target = document.querySelector("#element");
// store the original setAttribute reference
const setAttribute = target.setAttribute;
// override setAttribte
target.setAttribute = (key: string, value: string) => {
console.trace("--trace");
// use call, to set the context and prevent illegal invocation errors
setAttribute.call(target, key, value);
};

event Listener for checking if a new child node is added to target Node [duplicate]

How can I detect when a new element has been added to the document in jquery ?
Explanation:
I want to know when an element with class "column-header" has been added to the document. As I plan to run some javascript on those elements.
How can I do this ? I use jQuery javascript library.
The accepted answer uses an obsolete plugin from 2011 and the highest upvoted answer uses Mutation events which are now deprecated.
Today, a MutationObserver is what you should use to detect when an element has been added to the DOM. MutationObservers are now widely supported across all modern browsers (Chrome 26+, Firefox 14+, IE11, Edge, Opera 15+, etc).
Here's a simple example of how you can use a MutationObserver to listen for when an element is added to the DOM.
For brevity, I'm using jQuery syntax to build the node and insert it into the DOM.
var myElement = $("<div>hello world</div>")[0];
var observer = new MutationObserver(function(mutations) {
if (document.contains(myElement)) {
console.log("It's in the DOM!");
observer.disconnect();
}
});
observer.observe(document, {attributes: false, childList: true, characterData: false, subtree:true});
$("body").append(myElement); // console.log: It's in the DOM!
The observer event handler will trigger whenever any node is added or removed from the document. Inside the handler, we then perform a contains check to determine if myElement is now in the document.
You don't need to iterate over each MutationRecord stored in mutations because you can perform the document.contains check directly upon myElement.
To improve performance, replace document with the specific element that will contain myElement in the DOM.
$(document).bind('DOMNodeInserted', function(e) {
console.log(e.target, ' was inserted');
});
DOMNodeInserted is a DOM level 3 Event. That in turn means, you need a fairly new browser to support that kind of event.
Reference: MDC
If you want to do some jQuery on it, you can also do something like livequery (extra plugin):
$('column-header').livequery(function()
{
// do things here with your column-header, like binding new events and stuff.
// this function is called when an object is added.
// check the API for the deletion function and so on.
});
UPDATE:
It seems that the link was broken. Try this link
I would use setInterval to repeatedly check for element. eg.
var curLength=0;
setInterval(function(){
if ($('.column-header').length!=curLength){
curLength=$('.column-header').length;
// do stuff here
}
},100);
this code will check for any new .colum-header elements every 100 ms
I think the DOMNodeInserted method mentioned above is probably the sexiest choice, but if you need something that is going to work with IE8 and lower, you could do something like the following:
// wrap this up in en immediately executed function so we don't
// junk up our global scope.
(function() {
// We're going to use this to store what we already know about.
var prevFound = null;
setInterval(function() {
// get all of the nodes you care about.
var newFound = $('.yourSelector');
// get all of the nodes that weren't here last check
var diff = newFound.not(prevFound);
// do something with the newly added nodes
diff.addClass('.justGotHere');
// set the tracking variable to what you've found.
prevFound = newFound;
}, 100);
})();
That is just the basic idea, you can change that however you want, make a method out of it, keep the return value of the setInterval so you can stop it, or whatever you need to do. But it should get the job done.
You should check out the jQuery Mutation Events. I believe that it is what you are looking for.
if you want to set same functions for all the elements with class column-header
Then you may use jquery live()
$(".column-header").live("click",function(){});
How about using a poll - keep searching for an element with class "column-header", until you find it and then perform action. Seems simple.
Up to 2013 MutationEvents are deprecated. If anyone else has got problems detecting new elements in the dom, you can use MutationObservers Instead:
https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
Just change this function call (observing).
Parameter 1 - Which element to monitor
Parameter 2 - Which element will trigger the function (parameter 3) when appears.
Parameter 3 - Function triggered
observing('div#application', 'div.viewContainer', function(mutation){
console.log('Mutation:', mutation)
})
<html>
<head>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script>
/* Observing Easy */
function observing(who, forWhat, callBack){
var observer = new MutationObserver(function(mutations) {
mutations.forEach(mutation => {
console.log(mutation.addedNodes[0])
if ( mutation.addedNodes[0].matches(forWhat)){
console.log('MATCH!');
if(callBack!==undefined){
callBack(mutation)
}
}else{
console.log('%cNOT match', 'color: #f00');
}
});
});
observer.observe($(who)[0], {attributes: false, childList: true, characterData: false, subtree:false});
}
$(document).ready(function(){
/* Observing Usage */
observing('div#application', 'div.viewContainer', function(mutation){
console.log('Mutation:', mutation)
})
/* Adding Elements for Test */
$("#application").append($("<div>Hello World</div>")[0]);
$("#application").append($("<div class='contentFake'>ContentClassFAKE</div>")[0])
$("#application").append($("<div class='contentFake'>ContentClass1</div>")[0])
$("#application").append($("<div class='viewContainer'>ContentClass2</div>")[0])
setTimeout(function(){
$("#application").append($("<div class='contentFake'>ContentClass3</div>")[0])
}, 1000)
setTimeout(function(){
$("#application").append($("<div class='viewContainer'>ContentClass4</div>")[0])
}, 1000)
})
</script>
</head>
<body>
<div id="application"></div>
</body>
</html>
try this...
if($('.column-header')){
//do something...
}
or you can also do something like this..it will be more generic
jQuery.exists = function(selector) { return ($(selector).length > 0); }
if ($(selector).exists()) {
// Do something
}

jQuery persist all event listeners on element for future setting

Using jQuery I need to:
persists list of all event handlers that are added to element,
remove them all for few seconds and
return things to initial state (reassign the same event handlers)
I found that get list of current listeners with (some jQuery inner mechanisms):
var eventsSubmitBtn = $._data(submitButton[0], "events");
Then I can remove all event listeners with
submitButton.off();
But last stem seems not to be working
setTimeout(function () {
$._data(submitButton[0], "events", eventsSubmitBtn);
}, 5000);
eventsSubmitBtn is an empty array.
Is this the way this should be done with initial setting and I'm need something like deep cloning for those objects or this can't be done with $._data?
N.B. I have possibility to add my cistom code after all other system js code, thus I can't place the code assigning to $.fn.on before anything. Code that I write will run the last on startup and other event listeners are attached before my scripts will run.
As you get a reference to the object returned by $._data(), any change to that object will not go unnoticed, i.e. after you invoke .off(), that object will have changed to reflect that there are no handlers attached any more.
You could solve this by taking a shallow copy of the object, (e.g. with Object.assign).
But this is not really a recommended way to proceed. According to a jQuery blog, "jQuery._data(element, "events") ... is an internal data structure that is undocumented and should not be modified.". As you are modifying it when restoring the handlers, this cannot be regarded best practice. But even only reading it should only be used for debugging, not production code.
It would be more prudent to put a condition in your event handling code:
var ignoreEventsFor = $(); // empty list
$("#button").on('click', function () {
if (ignoreEventsFor.is(this)) return;
// ...
});
Then, at the time it is needed, set ignoreEventsFor to the element(s) you want to ignore events for. And when you want to revert back to normal, set it to $() again.
Now adding this to all your event handlers may become a burden. If you stick to using on() for attaching event handlers, then you could instead extend $.fn.on so it will add this logic to the handlers you pass to it.
The following demo has a button which will respond to a click by changing the background color. With a checkbox you can disable this from happening:
/* Place this part immediately after jQuery is loaded, but before any
other library is included
*/
var ignoreEventsFor = $(), // empty list
originalOn = $.fn.on;
$.fn.on = function (...args) {
var f = args[args.length-1];
if (typeof f === 'function') {
args[args.length-1] = function (...args2) {
if (ignoreEventsFor.is(this)) return;
f.call(this, ...args2);
};
}
originalOn.call(this, ...args);
}
/* This next part belongs to the demo, and can be placed anywhere */
$(function () {
$("#colorButton").on('click', function () {
// Just some handler that changes the background
var random = ('00' + (Math.random() * 16*16*16).toString(16)).substr(-3);
$('body').css({ backgroundColor: "#" + random });
});
$("#toggler").on('change', function () {
// Toggle the further handling of events for the color button:
ignoreEventsFor = $(this).is(':checked') ? $("#colorButton") : $();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="colorButton">Change color</button><br>
<input type="checkbox" id="toggler">Disable events
Notice: the above code uses ES6 spread/rest syntax: if you need support for IE then that would have to be written using the arguments variable, apply, ...etc.

How to declare a document.on() listener to change text of specific selected elements using jQuery?

I try to define my problem clearly using a use case, so here it is:
consider <a class="fruit" href=#>apple</a> and instead of apple could be any fruit. i want to declare a jQuery on listener like the one below that any time a dom element that has fruit class created and added any part of the body my listener do something to that element.
$(document).on("HERE IS THE QUESTION",".fruit",function(){ do something to the fruit here });
I know there are some alternative ways for reaching the result but this is how i want to solve this problem due to some complexity reasons.
This only needs to work in Chrome.
If you're trying to monitor when a DOM element with a certain class name is created and added to the DOM, then you can't do that using straight jQuery as there is no good cross browser (that works in older browsers) way of doing that and it isn't something jQuery has tried to solve.
There is a newish interface (requires IE 11) called mutation observers (MDN reference here) that can allow you to monitor for certain types of DOM changes where you could get an event when items are added to the DOM and you could check if they were your class. If you really only need it to work in Chrome, this should be just what you want.
There is also the old standby (that's bad for battery life) technique of using a setInterval() to check the DOM regularly for changes.
Or, you could also describe in more detail and from a higher level what problem you're really trying to solve and we might be able to offer other ideas.
Here's some sample code using mutation objservers:
$(document).ready(function() {
// create an observer instance
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
for (var i = 0; i < mutation.addedNodes.length; i++) {
if (mutation.addedNodes[i].className === "fruit") {
console.log("found fruit", mutation.addedNodes[i]);
}
}
});
});
// configuration of the observer:
var config = { childList: true, subTree: true };
// pass in the target node, as well as the observer options
observer.observe($("#container")[0], config);
});
And, a working demo: http://jsfiddle.net/jfriend00/zxEXp/

Mootools - how to destroy a class instance

What I'm trying to do is create a class that I can quickly attach to links, that will fetch and display a thumbnail preview of the document being linked to. Now, I am focusing on ease of use and portability here, I want to simply add a mouseover event to links like this:
Testing
I realize there are other ways I can go about this that would solve my issue here, and I may end up having to do that, but right now my goal is to implement this as above. I don't want to manually add a mouseout event to each link, and I don't want code anywhere other than within the class (and the mouseover event creating the class instance).
The code:
TestClass = new Class({
initialize: function(anchor) {
this.anchor = $(anchor);
if(!this.anchor) return;
if(!window.zzz) window.zzz = 0;
this.id = ++window.zzz;
this.anchor.addEvent('mouseout', function() {
// i need to get a reference to this function
this.hide();
}.bind(this));
this.show();
},
show: function() {
// TODO: cool web 2.0 stuff here!
},
hide: function() {
alert(this.id);
//this.removeEvent('mouseout', ?); // need reference to the function to remove
/*** this works, but what if there are unrelated mouseout events? and the class instance still exists! ***/
//this.anchor.removeEvents('mouseout');
//delete(this); // does not work !
//this = null; // invalid assignment!
//this = undefined; // invalid assignment!
}
});
What currently happens with the above code:
1st time out: alerts 1
2nd time out: alerts 1, 2
3rd time out: alerts 1, 2, 3
etc
Desired behavior:
1st time out: alerts 1
2nd time out: alerts 2
3rd time out: alerts 3
etc
The problem is, each time I mouse over the link, I'm creating a new class instance and appending a new mouseout event for that instance. The class instance also remains in memory indefinitely.
On mouseout I need to remove the mouseout event and destroy the class instance, so on subsequent mouseovers we are starting fresh.
I could create a helper function for this to make sure that the class is only created once for each link, something like this:
function TestClassHelper(anchor) {
anchor = $(anchor);
if(!anchor) return;
if(!anchor.retrieve('TestClass')) anchor.store('TestClass', new TestClass(anchor));
anchor.retrieve('TestClass').show();
}
Testing
I may end up implementing it this way if I have to, but I'm curious as to how I can fix the other method.
This looks a lot more complex than it should be. But if you want to fix this, you need to save a reference to the bound function somewhere and later pass that to removeEvent.
For example:
// inside initialize
this.boundHandler = function() {
this.hide();
}.bind(this)
this.anchor.addEvent('mouseout', this.boundHandler);
// inside hide
this.removeEvent('mouseout', this.boundHandler);
See the removeEvent docs for examples of this very issue.
I wouldn't recommend event delegation here either for performance reasons. The best approach is to attach the handler in code rather than inline and only do it once, so unnecessary objects are not being created each time the user mouses over.

Categories

Resources