Event For DOM Object Creation - javascript

How would one fire an event that fires every time a div is created?
I was thinking something along the lines of this, but clearly not.
$("#content").on("create", "div.block", function () {
$(this).css({"background-color":"#FF0000"});
});
I have discovered MutationObserver (https://stackoverflow.com/a/11546242/165737), however as seen in the comments this does not work in IE.

you could use a mutation event (DOMNodeInserted)... however IE might not fully capable of dealing with that.
http://jsfiddle.net/kasperfish/AAd8f/
$(function() {
$('#btn').click(function(){
$('body').append('<div style="width:30px;height:30px;border:1px solid black"></div>');
});
$(document).on('DOMNodeInserted', function(e) {
$(e.target).addClass('blue');
});
});
I like to note that it is better to use callback events instead of listening to the DOM. You'll need to write a callback after a div is inserted in the DOM. I don't think there is an other (non-hacky) way to accomplish this.

You may try something like this instead of MutationObserver to get notified when ever a div.block has been added to the div#content
$(function(){
var c = $('#content'), l = c.find('.block').length;
setInterval(function(){
var lOld = l;
if(c.find('.block').length > lOld) {
l = c.find('.block').length;
c.find('.block').css({"background-color":"#FF0000"});
}
}, 100);
});
An example and here is another example with multiple Background color effect.

Related

How to receive the error event for not loaded images at top performance

I want to replace the src attribute of all <img> elements in a certain element, that have not been loaded, because the source was not found (404).
There are quite a few topics on this here:
Check if an image is loaded (no errors) in JavaScript
jQuery or Javascript check if image loaded
Most of the answers add an eventListener on the images that wait for an error event. Ideally we'd just write something like this:
Not working example of an delegated event listener:
$("#element").on("error", "img", function(){
console.log("hey, there was an error in this image: "+$(this));
})
Another user was kind enough to point this out.
This is not working because the error event seem not to bubble, like the click event for example.
So with this knowlege, the only thing left seems to be, to iterate each image and check it for errors.
Whats the point (tl;dr)?
And here my question: What is the fasted method to iterate all images of a certain object for errors with javascript (yes, you may use jQuery). By fastest I mean: the iteration should be quite quick and unnecessary event listeners should not be placed (my problem).
This is my example code:
$(function(){
var $element = $("#element");
var replaceImgSrc = "http://www.placehold.it/100x100&text=replaced";
var allImages = $element.find("img");
for (var i = 0; i < allImages.length; i++) {
$(allImages[i]).one('error', function () {
$(this).attr("src", replaceImgSrc).addClass("not-loaded")
});
}
});
And here is a jsFiddleDemo: http://jsfiddle.net/qq2ccx05/
The performance in the jsFiddle is awful, it's better in production.
I'd like to know if there is a smarter way to solve this problem.
You could capture 'onerror' event, doesn't seem really more optimized:
var replaceImgSrc = "http://www.placehold.it/100x100&text=replaced";
$('#element')[0].addEventListener(
'error',
function(event){
var elm = event.target;
if( elm.tagName == 'IMG'){
elm.src = replaceImgSrc;
}
},
true // Capture event
);
jsFiddle

jQuery add event and instantly execute it

Often there is situation when I need to add some event with some customizations and then apply those customizations on page ready.
Usually I was doing it like:
$(window).resize(function(){
//some code
}).resize(); //trigger it when event defined
Problem with this solution is that if I have many resize events, then if I trigger it like this - it will re-execute all previously defined events too.
So another solution could be:
var myCallback = function(){ /*some code*/ };
$(window).resize(function(){
myCallback();
});
myCallback();
And it does it correctly but I find it not so good looking code and also there is no this inside function changed to event target DOM element that is very useful quite often.
Great would be something like
$(window).addEventAndFireOnce("resize", function(){});
such function is not so hard to implement, but I'm wondering if there is something like this there already in js or jQuery.
I don't know if I'm alone in this, but if I need to do that (and it's not uncommon) I bind a custom event name (possibly with a scope) at the same time as I bind the real event ("click" or "change" or whatever):
var myCallback = function(ev) { ... };
$(window).on("resize my-resize", myCallback).trigger("my-resize");
That's particularly useful when you're handling something like a "click" event on a checkbox. Triggering the "click" will actually update the checkbox "checked" state, which is not generally what you'd want to do. There's the jQuery .triggerHandler() method, but for whatever reason that only works on the first element in the jQuery object, so you can't trigger the handlers for all the checkboxes in a form with one call.
I would write it like so:
var myCallback = function(){ /*some code*/ };
$(window).resize( myCallback );
myCallback();
I think what you are looking for here is namespaced handlers
var log = (function() {
var $log = $('#log');
return function(msg) {
$('<p/>', {
text: msg
}).appendTo($log)
}
})();
$(window).resize(function() {
log('handler 1');
});
$(window).resize(function() {
log('handler 2');
});
$(window).on('resize.myspecial', function() {
log('handler 3');
}).trigger('resize.myspecial');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="log"></div>

how to remove all ClientEvents from anchors in an HTML String with jQuery

I've been struggling with what seems to be a simple problem for a few hours now. I've written a REGEX expression that works however I was hoping for a more elegant approach for dealing with the HTML. The string would be passed in to the function, rather than dealing with the content directly in the page. After looking at many examples I feel like I must be doing something wrong. I'm attempting to take a string and clean it of client Events before saving it to our Database, I thought jQuery would be perfect for this.
I Want:
Some random text click here and a link with any event type
//to become:
Some random text click here and a link with any event type
Here's my code
function RemoveEvilScripts(){
var myDiv = $('<div>').html('testing this Do it! out');
//remove all the different types of events
$(myDiv).find('a').unbind();
return $(myDiv).html();
}
My results are, the onClick remains in the anchor tag.
Here's a pure Javascript solution that removes any attribute from any DOM element (and its children) that starts with "on":
function cleanHandlers(el) {
// only do DOM elements
if (!('tagName' in el)) return;
// attributes is a live node map, so don't increment
// the counter when removing the current node
var a = el.attributes;
for (var i = 0; i < a.length; ) {
if (a[i].name.match(/^on/i)) {
el.removeAttribute(a[i].name);
} else {
++i;
}
}
// recursively test the children
var child = el.firstChild;
while (child) {
cleanHandlers(child);
child = child.nextSibling;
}
}
cleanHandlers(document.body);​
working demo at http://jsfiddle.net/alnitak/dqV5k/
unbind() doesn't work because you are using inline onclick event handler. If you were binding your click event using jquery/javascript the you can unbind the event using unbind(). To remove any inline events you can just use removeAttr('onclick')
$('a').click(function(){ //<-- bound using script
alert('clicked');
$('a').unbind(); //<-- will unbind all events that aren't inline on all anchors once one link is clicked
});
http://jsfiddle.net/LZgjF/1/
I ended up with this solution, which removes all events on any item.
function RemoveEvilScripts(){
var myDiv = $('<div>').html('testing this Do it! out');
//remove all the different types of events
$(myDiv)
.find('*')
.removeAttr('onload')
.removeAttr('onunload')
.removeAttr('onblur')
.removeAttr('onchange')
.removeAttr('onfocus')
.removeAttr('onreset')
.removeAttr('onselect')
.removeAttr('onsubmit')
.removeAttr('onabort')
.removeAttr('onkeydown')
.removeAttr('onkeypress')
.removeAttr('onkeyup')
.removeAttr('onclick')
.removeAttr('ondblclick')
.removeAttr('onmousedown')
.removeAttr('onmousemove')
.removeAttr('onmouseout')
.removeAttr('onmouseover')
.removeAttr('onmouseup');
return $(myDiv).html();
}

Make (possibly dynamically loaded) element clickable via JavaScript, but give precedence to links contained within

I am adding a custom data attribute data-js-href to various HTML elements, and these elements should behave just like a link when clicked. If a link within such an element is clicked, the link should take precedence and the data-js-href functionality should be ignored, though. Furthermore, the solution also needs to work with elements that are dynamically added at a later time.
So far, I have come up with the following solution. It basically checks if the click was performed on a link, or any child element of a link (think <a href='…'><img src='…' alt='…' /></a>).
// Make all elements with a `data-js-href` attribute clickable
$$('body').addEvent('click:relay([data-js-href])',
function(event, clicked) {
var link = clicked.get('data-js-href');
if (link && !event.target.match('a')) {
var parents = event.target.getParents();
for (var i = 0; i < parents.length && parents[i] != clicked; i++) {
if (parents[i].match('a')) {
return;
}
}
document.location.href = link;
}
});
It works, but it feels very clumsy, and I think that there has to be a more elegant solution. I tried something along the lines of
$$('body').addEvent('click:relay([data-js-href] a)',
function(event, clicked) {
event.stopPropagation();
}
but to no avail. (I littered the code with some console.log() messages to verify the behavior.) Any idea is welcome.
you can do this with 2 delegated events - no reverse lookups and it's cheap as they will share the same event. the downside is, it is the same event so it will fire for both and there's no stopping it via the event methods (already bubbled, it's a single event that stacks up multiple pseudo event callbacks and executes them in order--the event has stopped but the callbacks continue) That's perhaps an inconsistency in mootools event vs delegation implementation but it's a subject of another issue.
Workarounds for now can be:
to have the 2 event handlers communicate through each other. It will scale and work with any new els added.
to add the delegators on 2 different elements. eg. document.body and #mainWrap.
http://jsfiddle.net/dimitar/J59PD/4/
var showURL = function(howLong) {
// debug.
return function() {
console.log(window.location.href);
}.delay(howLong || 1000);
};
document.id(document.body).addEvents({
"click:relay([data-js-href] a))": function(e) {
// performance on lookup for repeat clicks.
var parent = this.retrieve("parent");
if (!parent) {
parent = this.getParent("[data-js-href]");
this.store("parent", parent);
}
// communicate it's a dummy event to parent delegator.
parent.store("linkEvent", e);
// let it bubble...
},
"click:relay([data-js-href])": function(e) {
// show where we have gone.
showURL(1500);
if (this.retrieve("linkEvent")) {
this.eliminate("linkEvent");
return;
}
var prop = this.get("data-js-href");
if (prop)
window.location.href = prop;
}
});
Discussed this with Ibolmo and Keeto from the mootools team on IRC as well when my initial attempt failed to work and both callbacks fired despite the event.stop: http://jsfiddle.net/dimitar/J59PD/
As a result, there was briefly a ticket open on the mootools github issues: https://github.com/mootools/mootools-core/issues/2105 but it then went into a discussion of what the right thing to do from the library standpoint is and how viable it is to pursue changing the way things work so...

Add click event to Div and go to first link found

I think I've been too much time looking at this function and just got stuck trying to figure out the nice clean way to do it.
It's a jQuery function that adds a click event to any div that has a click CSS class. When that div.click is clicked it redirects the user to the first link found in it.
function clickabledivs() {
$('.click').each(
function (intIndex) {
$(this).bind("click", function(){
window.location = $( "#"+$(this).attr('id')+" a:first-child" ).attr('href');
});
}
);
}
The code simply works although I'm pretty sure there is a fairly better way to accomplish it, specially the selector I am using: $( "#"+$(this).attr('id')+" a:first-child" ). Everything looks long and slow. Any ideas?
Please let me know if you need more details.
PS: I've found some really nice jQuery benchmarking reference from Project2k.de here:
http://blog.projekt2k.de/2010/01/benchmarking-jquery-1-4/
Depending on how many of these div.click elements you have, you may want to use event delegation to handle these clicks. This means using a single event handler for all divs that have the click class. Then, inside that event handler, your callback acts based on which div.click the event originated from. Like this:
$('#div-click-parent').click(function (event)
{
var $target = $(event.target); // the element that fired the original click event
if ($target.is('div.click'))
{
window.location.href = $target.find('a').attr('href');
}
});
Fewer event handlers means better scaling - more div.click elements won't slow down your event handling.
optimized delegation with jQuery 1.7+
$('#div-click-parent').on('click', 'div.click', function () {
window.location.href = $(this).find('a').attr('href');
});
Instead of binding all the clicks on load, why not bind them on click? Should be much more optimal.
$(document).ready(function() {
$('.click').click(function() {
window.location = $(this).children('a:first').attr('href');
return false;
});
});
I would probably do something like;
$('.click').click(function(e){
window.location.href = $(this).find('a').attr('href');
});

Categories