Javascript/Jquery How to catch the use of a CSS class - javascript

I am using a Javascript plugin (several lines of code) that from times to times is released a new version.
For this reason I am trying to avoid changing the original source code in order to affect my wishes.
One way that is "half" working for me is to find all the elements that are using a specific CSS class (or group of classes) and them I am removing it (or do something else with them) in order to do what I want.
The part that is not working is the "trigger/event" to process this action. During the execution of this plugin new elements are created and removed and once again I am having "wrong" entries once again.
My question: How can I "catch" all the elements that are "from a moment to the other" using the CSS class XXX? and then execute my own code.
Notes: I was reading the Jquery .on() but I need to specify an event, however the issue is that I do not know the many "places/events" from the original source code are processing this.
Update:
At this point I am "manually" calling my function:
function MyOverrideAction(){
$.each( $( ".sch-gantt-terminal" ), function( key, value ) {
// here I have all my logic.... based on several rules (non relevant to my stackoverflow question)
});
}
I just want that this function is executed every instance when some HTML element is using my target css class.

It is much easier to redefine the CSS class after the original definition. One way to do it is to attach an inline style tag at the bottom of the document which redefines the style. You can use jQuery.append for this. For example see this.

Maybe you search something like this:
https://stackoverflow.com/a/3219767/5035890
If you listen a change in the DOM you can apply all actions that you need. With MutationObserver you can achieve it. Please, consider of the compatibility.
Good luck

Related

Jquery remove function follow up

I submitted this question last week:
chrome not working with jquery remove
and was able to resolve it (stupidity on my part really), however my example was very simple. Currently I'm trying to use .remove to eliminate a complete div from a page before sending an array of inputs to an ajax function. However, I am not able to get .remove to work at all.
Here's my latest try:
http://jsfiddle.net/CJ2r9/2/
I get function not defined on the jsfiddle on multiple browsers. On my application I get absolutely no errors, but nothing works either.
I'm relatively new to javascript scopes, so if the problem is scope-wise then please let me know how I'm screwing up.
I have also tried using the .on jquery function, but it's a bit more confusing considering my div ids are dynamically loaded from the server (jstl, spring MVC, etc). If that's a solution please let me know how I can get on the right track.
Thank you!
The two problems in your jsFiddle are:
Scope: removeElem is not in global scope, since you left the default configuration option to execute the code on DOM ready. You can change it to "no wrap" to make the funciton global.
The elements you want to remove don't exist. The div elements have IDs like "removeXXXp" and in your event handlers you pass "removeXXXs".
Here is an other, simpler solution (in my opinion) for element removal. Given your markup:
<div class="scheduleSet" id="remove315p">
<!-- ... -->
Remove
</div>
You can use .on like so:
$('.schduleSet a.optionHide').on('click', function() {
// traverses up the DOM tree and finds the enclosing .schduleSet element
$(this).closest('.scheduleSet').remove();
});
You don't even need IDs at all.
I made a simple fiddle, the inline onclick doesn't see the function defined in javascript so I get a ReferenceError: myRemove is not defined.
By adding the listener in js, .remove() works fine.
Sorry I don't know what causes the difference in behavior though.
Test it out: http://jsfiddle.net/xTv5M/1/
// HTML5
<div id="removeme">foo bar</div>
<button onclick="myRemove('removeme')">Go</button><br>
<div id="removeMe2">foo bar</div>
<button id="go2">Go Again</button>
// js
function myRemove(name){
$('#'+name).remove()
};
$('#go2').click(function(){ myRemove('removeMe2') });
I see that you are already using jquery. Why dont you do it this way:
<div id="foo">This needs to be removed</div>
Remove
function removeElem(element){
$('#'+element).remove();
}
$(function(){
$("#remove").click(function(){
removeElem($(this).data('remove'));
});
})
Fiddle here: http://jsfiddle.net/vLgpk/
They way this works is, using data-remove (can be anything like data-xyz btw), binds the remove link with the div. You can then read this binding later when remove is clicked.
If you are new to jQuery, and wondering what data-remove is, its just custom attribute that you can add to you code which can be later retrieved using the data() call on the element. Many great frameworks like Bootstrap use this approach.
Advantage of using this approach in my opinion is you can have the remove links anywhere in your UI and they don't need to be related structurally to your divs by siting inside them.

Optimising Jquery code - Adding and removing classes on click

I am currently learning js and jquery to assist me with my designs, a common problem that I am having is that I can get it to do what I want it to but I have no idea if the way in which it has been coded is efficient. Could anyone see a better way to code this:
$(".cal-check a").click(function(e) {
e.preventDefault();
$(".agenda").addClass("active");
});
$(".agenda .close-panel").click(function(e) {
e.preventDefault();
$(".agenda").removeClass("active");
});
I want to click on a calendar event then it adds the class active to another class within the calendar called agenda which then brings up the agenda. I then remove it by clicking on a close panel element. Many thanks
You could cache the .agenda selector like so:
var $agenda = $(".agenda");
$(".cal-check a").click(function(e) {
e.preventDefault();
$agenda.addClass("active");
});
$agenda.find(".close-panel").click(function(e) {
e.preventDefault();
$agenda.removeClass("active");
});​
I recommend not changing classes, that will usually be rather intensive on the browser, because one class change will mean that all the classes have to be reparsed. This is usually very bad for more aggressive stuff, like animation, but if you have performance considerations, you should take that into advisement.
I think this is already efficient.
Just something that might help in the future is to try and dive into the DOM as little as possible. In this small example it wont make a difference but for example create a variable for agendaClass instead of using jquery every time to fetch it.
var agendaClass = $(".agenda");
$(".cal-check a").click(function(e) {
e.preventDefault();
agendaClass .addClass("active");
});
$(".agenda .close-panel").click(function(e) {
e.preventDefault();
agendaClass .removeClass("active");
});
That should be efficient enough. How you can optimize your code strongly depends on your DOM structure.
Behind the scene, jQuery with its Sizzle search engine will use built in methods for DOM search, if those are available (native search will be always faster than search done with JS). In your case everything should be Ok, especially in modern browsers, as they have querySelectorAll and .cal-check a and .agenda selectors will be executed with that built in method. Also, there is getElementByClassName which could be used to find .agenda.
Both of those methods are supported by most of modern browsers (provided links have a list of supported browser), so talking about browsers like IE8+, Firefox and Chrome will be fast enough with your selectors. At the same time IE7 has no functions like above and Sizzle will be forced to go through numerouse elements to find elements you are looking for. Maybe you can limit that amount specifying some container with id, in that case it will look inside that elements only:
$("#someId .agenda"), for instance. You may want additionally add some tag: $("#someId div.agenda"). This way you will limit amount of elements to search with divs (getElementsByTagName could be used) inside #someId (getElementById). That way you may increase speed in IE7 and other old browsers with no support of getElementByClassName and querySelector
Plus, you may cache search results as it was already mentioned here.

How can I dynamically change css for html that is generated by javascript at runtime?

I have some html that is generated programmatically using javascript at runtime.
I want to be able to dynamically change the css properties of this html
e.g.
$(".pointsbox").css("background-color","green");
but it appears to not work as those html elements are not available at the time that the css change is called.
I am pretty sure I have managed to do this before but I've forgotten what the function is called.
Any help much appreciated!
You haven't posted code on how exactly you create your HTML elements, but it can be something as simple as this:
You can create an HTML element by passing HTML into the jQuery function right?
var new_element = $('<div>');
Well, you can treat that like any other jQuery object, and just manipulate its CSS right then and there.
var new_element = $('<div>').css('background-color', 'green');
Heck, you can even chain the create, the css change and the DOM insert in one call.
var new_element = $('<div>')
.css('background-color', 'green')
.appendTo('#container')
;
There are the Mutation events - specifically the DOMNodeInserted event - that you could bind an event handler to. However, as the page I linked states, it's recommended that you don't because it has a serious negative effect on the performance of your page and the cross-browser support isn't particularly good.
An alternative is to simulate your own DOMNodeInserted event using a custom event. Essentially you bind a handler for a custom event (say nodeinserted) on the document, then trigger that event whenever you have code that dynamically modifies the structure of your page. Code might look something like the following:
$(document).on('nodeinserted', function() {
$('.pointsbox').css('background-color', 'green');
});
function modifyPage() {
// code to modify your page here
$(document).trigger('nodeinserted');
}
Note that, with this approach, you'll need to modify all functions that add elements to the page to trigger that nodeinserted custom event.
I use this. It ensures the DOM has loaded.
$(document).ready(function(){
//code here
$(".pointsbox").css("background-color","green");
});

How do I replace an inline JavaScript event handler?

I'd like to use JavaScript only (no jQuery) to replace an inline onmenuclick event handler generated by a third party control with my own.
The custom control has added the following HTML to the page:
<ie:menuitem
menugroupid="200"
description="Create a site for a team or project."
text="New Site"
onmenuclick="if (LaunchCreateHandler('Site')) { STSNavigate('\u002fsites\u002fsd\u002f_layouts/newsbweb.aspx') }"
iconsrc="/_layouts/images/newweb32.png" type="option" id="zz4_MenuItem_CreateSite"></ie:menuitem>
I'm trying to replace the onmenuclick handler with:
var createSiteMenuItem = document.getElementById('zz4_MenuItem_CreateSite');
if (createSiteMenuItem)
createSiteMenuItem.onmenuclick = function () { alert('Hello!'); }
The original handler still fires! I'm making sure the script runs after the document has loaded.
Is this the correct approach?
The trouble is that directly assigning to onmenuclick is unreliable and non-standard. You need to use attachEvent() (IE) or addEventListener() (everyone else).
Edit:
As explained below, the actual problem was that in Javascript, element attributes are case-sensitive, despite the HTML, which isn't. So any reference to the menu click event in Javascript has to refer to it as "onMenuClick".
The id may be generated dynamically. So one time it is 'zz4_MenuItem_CreateSite' the next time it is something else. Way to check: observe the html source on multiple downloads, see if the ids vary.
This msdn article seems to point in that direction.
Suggestion: wrap the menu items in a div with an id that you assign. Then walk the dom tree within your div to find the right element to modify.
I've marked staticsan's answer as correct - onmenuclick is non-standard and that's why the problem is occurring. However the original resolution suggested wasn't quite right. This has since been corrected, but here's the back story for completeness...
I debugged this in Visual Studio and could see that onmenuclick is recognised as an expando instead of an event. This means attachEvent and addEventListener do not apply and fail when used.
The resolution was far more simple. I changed the casing to that shown in the Visual Studio debugger so it read onMenuClick instead of onmenuclick. The "faux-event" now fired correctly.

In Greasemonkey/javascript, how can I handle new elements added to page?

I have written a Greasemonkey script which manipulates the contents of certain elements with the following selector:
$("span.relativetime").each(function() { $(this).html("TEST"); });
However, sometimes matching elements are added to the page through AJAX, and I don't know how to handle those new elements. I have tried this, but it doesn't work:
$("span.relativetime").live(function() { $(this).html("TEST"); });
The documentation for jQuery live() says that it wants an event (like "click"). But I don't have any event, I just want to know when something matching my selector has been created, and then I want to modify it.
Background: I am encountering this problem with a Greasemonkey script to display StackOverflow's relative timestamps as absolute local timestamps, which you can find on meta-SO. The problem is when you click "show all comments", the new comments are added by AJAX, and I don't know how to find and replace the timestamps in those scripts.
With StackOverflow's setup I find it annoying to handle stuff after the comments. What I've done is put a bind on the Add/Remove comments button that uses setTimeout to wait for the elements to be created, and then modify them.
One thing you could try (although I'm not sure if it would work) is to cache your selection in some global variable like so:
var $relativetime = $("span.relativetime");
Then you would have your .each function:
$relativetime.each(function() { $(this).html("TEST"); });
After your new elements were added to the DOM, you could reselect append to your cached object:
$relativetime.append("<my html>"); //or
$("<my html>").appendto($relativetime);
(P.s. .html() is for setting html. To set text, use .text()

Categories