Dynamic binding jquery plugins? - javascript

In jQuery you can dynamically bind an event listener to all future instances of divs with a class of 'subthing' by binding to a parent element and assigning a filter like so:
$(".thing").on("click", ".subthing", function(){
console.log('subthing clicked');}
);
If I have a jquery plugin that I would ordinarily bind with
$(".subthing").thingify();
Is there an established way ensure that all future instances of .subthing will also have the plugin attached to them?

Try:
document.body.addEventListener("DOMNodeInserted", function(event){
var $elementJustAdded = $(event.target);
if ($elementJustAdded.hasClass('subthing')) {
$elementJustAdded.thingify();
}
}, false);

Take a look at the livequery plugin
$(".subthing").livequery(function(){
$(this).thingify();
});
I think this is exactly what you need.

Related

How to select parent using on selector

I have a dynamic hover that gets activated based on whether a hidden element exists or not. I'm updating my code to incorporate dynamically created elements but have ran into an issue and don't know how to select a parent.
Previously I used $(".infotip").parent().hover but have updated to:
$(document).on("mouseenter", ".parent-selector", function() {
$(this).find(".infotip").addClass("active");
});
$(document).on("mouseleave", ".parent-selector", function() {
$(this).find(".infotip").removeClass("active");
});
So what needs to happen is I need ".parent-selector" to behave like $(".infotip").parent()
Since the content is dynamic and you mentioned you can't add a class to the parent when it's created, the only way I can think to do this would be to watch for any new elements that have been added and then bind your events.
This function will periodically look for any elements with the .infotip class that does not have our custom events_bound attribute already. If it finds one, it'll add the attribute and then bind the mouse events to the parent. I've included a fiddle illustrating this with dynamic content.
//check for changes in the dom
setInterval(function() {
$('.infotip:not([events_bound])').each(function() {
//add attribute so that we don't re-bind to this element
$(this).attr('events_bound', true);
//now bind the events to the parent
$(this).parent().mouseenter(function() {
$(this).find(".infotip").addClass("active");
})
$(this).parent().mouseleave(function() {
$(this).find(".infotip").removeClass("active");
})
});
}, 500);
https://jsfiddle.net/ybrwv0c8/1/
Of course if there is anything identifiable about the parent, then the best way would be to use a selector for your on. For instance, if there's a dynamically generated ID with a standard structure like parent_13835723, you could do a partial attribute selector like $('[id^=parent_]')
You might also be able to use use the jquery :has pseudoselector like so. However, this searches all descendants for an element, which may not work correctly depending on how your DOM is structured.
$(document).on("mouseenter", ":has('.infotip')", function() {
$(this).children('.infotip').addClass("active");
});
$(document).on("mouseleave", ":has('.infotip')", function() {
$(this).children('.infotip').removeClass("active");
});
However, according to the jquery docs here http://api.jquery.com/has-selector/:
The expression $( "div:has(p)" ) matches a <div> if a <p> exists anywhere
among its descendants, not just as a direct child.
Because :has() is a jQuery extension and not part of the CSS
specification, queries using :has() cannot take advantage of the
performance boost provided by the native DOM querySelectorAll()
method. For better performance in modern browsers, use $(
"your-pure-css-selector" ).has( selector/DOMElement ) instead.
I'm not sure whether the :has or setInterval method would have better performance.
How about
$(".infotip").parent().mouseleave(function() {
$(this).find(".infotip").addClass("active");
}
and
$(".infotip").parent().mouseleave(function() {
$(this).find(".infotip").addClass("active");
}
Reference : https://api.jquery.com/mouseleave/
You can use jQuery's custom :has selector:
$('document').on('mouseenter', ':has(.infotip)', function () {
$(this).find(".infotip").addClass("active");
});
$('document').on('mouseleave', ':has(.infotip)', function () {
$(this).find(".infotip").addClass("active");
});
I haven't tested this, as there is no HTML provided in the question, but the documentation seems to indicate it will do what you want.
As simple as
jQuery(".child").parent().on('mouseenter', function(){
jQuery(this).css('background', '#f00');
});
jQuery(".child").parent().on('mouseleave', function(){
jQuery(this).css('background', '#0ff');
});
DEMO
Edit:- Based on further clarification,
You can attach events to objects when you create them. If you are binding the same events to multiple objects at different times, just create a named function.
OR
A really dirty hack would be to to unbind and rebind the events everytime a hirerchy of elements is added to the DOM.
Something like
var init = function() {
jQuery(".child").parent().off().on('mouseenter', function(){
jQuery(this).css('background', '#f00');
});
jQuery(".child").parent().off().on('mouseleave', function(){
jQuery(this).css('background', '#0ff');
});
};
Just call the method init everytime you add something to the DOM.

How do I get jquery to recognize created on the fly element with .on?

I have the following code I am using to begin an animation process:
$('body').on('click','#contain span', function(){
var $target = $(this).parent().children('#contain_inner');
flyout.fadeOldBox($target);
flyout.createBox();
})
flyout.createbox() then creates a new instance of #contain_inner but that new instance is not available when my click function above tries to target it again. I know that if I were to use .live things would work but that is deprecated now and I don't really understand how I would use .on to accomplish what I need here.
I know I am using .on above already for the click, but I still don't understand how to bind it to the new #contain_inner div that will be create in flyout.createBox().
EDIT: showing flyout.createBox() code...all is working now!
createBox: function(){
$box = $('<div id="feed_contain_inner"></div>'); //was accidentally creating that as div class= instead of the id
$box.load('example')
$box.appendTo('#contain');
flyout.positionBox($box);
}
This is the same as live:
$(document).on('click', '.yourslector', callback);
Are you setting your .on() inside $(document).ready()? It will only trigger on new elements if it's set outside $(document).ready().

Automatically assign event handler to new element

Say I have some code like this which is called on $(document).ready()
$(".someClass").click(function(){
//do something
});
Later on I have some jquery to create an element with the class someClass. Is there anyway to automatically attach the click from above or do I have to manually attach it again?
Yes. It is possible.
$("body").on("click", ".someClass", function() {
// ...
});
Use latest version of jquery and on
$(document).on('click', '.someClass', function(e){
//do something
});
Live is deprecated but you can use it, anyway (not recommended).
$('.someClass').live('click', function(e){
//do something
});
There is live, which also listens for new elements
$(".someClass").live('click', function(){
//do something
});
But, as of jquery 1.7 it has been deprecated. It's advised to use on instead.
But in order to use on, you need a container for the elements you want to bind a handler. Of course you could use body or document but it's better to use a more specific element
$(".someClassContainer").on('click', '.someClass' function(){
//do something
});
There's two easy ways of doing this, the first is with on():
$(".someClassParentElementPresentInTheDOMonDOMReady").on('click','.someClass',
function(){
//do something
});
And the other is to simply assign the click-handler at the point of creation of the new element; I don't know how you're doing that, but an example is below:
$('#addElement').click(
function(){
var newElem = $('<div />',{'class' : 'someClass'}).click(function(){
// do something }).appendTo('.someClassParentElementPresentInTheDOMonDOMReady');
References:
on().

Declaratively setting jQuery.Data property for a HTML link

Assuming I have a HTML link in my rows inside a datagrid or repeater as such
DoSomething
Now also assuming that I have handled the click event for all my DoSomethings in jQuery as such
$(".DoSomething").click(function (e) {
//Make my DoSomethings do something
});
What is the correct technique for passing data to the click event that is dependent on the link clicked?
Without jQuery you would typically do something like this.
DoSomething
but this technique obviously doesn't work in the jQuery case.
Basically my ideal solution would somehow add values for to the jQuery.Data property for the link clicked but doing so declaratively.
Use HTML5 data- attributes. jQuery support is built-in for 1.4.3+
http://api.jquery.com/data/#data2
click here
$('.product-link').click(function (e) {
alert($(this).data('productid'));
});
You could use the attr() function.
http://api.jquery.com/attr/
$("#Something").attr("your-value", "Hello World");
$("#Something").click(function (e) {
//Make my DoSomethings do something
var value = $(this).attr("your-value");
alert(value); // Alerts Hello World
});
your question was not clear to me but may be this will help
$(".DoSomething").click(function (e) {
//Make my DoSomethings do something
$(this).data("key","value");
//later the value can be retrieved like
var value=$(this).data("key");
console.log(value);// gives you "value"
});

not work class .numeric after add new input. what do i do?

why after add new input, class .numeric (normal number formatting) in js code not worked?
This way for normal number formatting is right?
What is your suggestion?
i not want use of plugin.
DEMO
$("input:text.numeric").keyup(function () {
$val = $(this).val().match(/[0-9]/g).reverse().join("").match(/[0-9]{1,3}/g).join(",").match(/./g).reverse().join("");
$(this).val($val)
})
With respect
If you add something to the page after it is done loading you will need to use the live() function on your scripts to make them work on the new data.
If you do something like:
$('#container').append('<div class="clickme">The text goes here</div>');
or
$('#container').load('script.php');
...they are both considered adding to the page.
Using live(), your code would become:
$("input:text.numeric").live('keyup', function () {
$val = $(this).val().match(/[0-9]/g).reverse().join("").match(/[0-9]{1,3}/g).join(",").match(/./g).reverse().join("");
$(this).val($val)
});
Read more here: http://api.jquery.com/live/
You need a future-proof event observer. Since the keyup bind is assigned to existing nodes, any nodes you create afterwards will not be bound to that event. You need to use live or delegate
Change
$("input:text.numeric").keyup(function () {
to
$("input:text.numeric").live('keyup',function () {
or
$('.find_input').delegate('input:text.numeric','keyup',function () {
delegate() is much more resource-friendly than live() but you need to know the parent ahead of time. In your example, I'd recommend it.
Working demo: http://jsfiddle.net/AlienWebguy/zgWr3/4/
Use the delegate()[docs] method to bind the handler to the .column container.
Example: http://jsfiddle.net/zgWr3/3/
$('.column').delegate("input.numeric:text",'keyup',function () {
$val = $(this).val().match(/[0-9]/g).reverse().join("").match(/[0-9]{1,3}/g).join(",").match(/./g).reverse().join("");
$(this).val($val)
});
This way, any "input.numeric:text" elements inside of .column will invoke the handler irrespective of when they're added to the DOM.
I also changed the selector around a little. Seems more understandable to me.

Categories