Tooltips for dynamic elements - javascript

I'm having tooltips on my page
var btnArr = ["#b1", "#b2"];
var ttArr = ["Submit", "Clear"];
$.each(btnArr, function (i, v) {
$(btnArr[i]).prop('title', ttArr[i]);
$(v).tooltip({
text: ttArr[i]
});
});
How can I have the tooltips working for dynamically created elements?

You can bind the tooltip widget to a top-level element and use the items option to filter what elements you want to show it on:
$(document).tooltip({
items: ".myTooltipButtonClass"
});
This could be document or a container element or even multiple container elements. The other alternative is to reinstantiate a new widget each time you dynamically create a new button with a tooltip, but that's in most cases unnecessarily complicated
Here's an update on the fiddle: http://jsfiddle.net/h5qbhvmc/
On a side note text isn't a valid option and doesn't do anything. Ref. the list of valid options

Related

Selecting the next input of an event.target

I have (an array of) two inputs product and category.
The product one is an autocomplete.
I would like to fill in the category when a product is selected.
the problem that the event.target is not a jquery object, so it seems I can't apply the jQquery's .next("input")
Here is my code:
var addedProduct = $(".produit:last > input");
addedProduct.autocomplete( {
source: Object.keys(availableProducts),
select: function(event, ui){
var category = event.target.next("input"); // something like this ???
category.value = availableProducts[ui.item.value]; //{"product1":"category1",...}
}
})
The inputs location is like this:
You can create a new jQuery object from the event target with $(event.target). You'll be able to call .next on it afterwards
The other solution without jQuery is to use the native DOM API. You can select the next element with nextElementSibling. The only requirement is that the element you want to target must be immediately the next element.
EDIT: From the DOM structure provided you can use .parent().next() to select the next element at the parent level. Then on this new element use .find() to select the wanted input. Note that the code is highly tied to the DOM structure. You could use the id to directly select the element.
$(event.target).parent().next().find("input");

clone select element and wrap

I clone multiple select elements in the following manner. This work perfectly:
Demo: https://jsfiddle.net/DTcHh/36308/
// get all items of specific class
var $selectedClassDiv = $('.to-clone');
// find select eles and clone into div
$('#cloned-list').html($selectedClassDiv.find('select').clone());
// loop through cloned select eles to set the correct selected option
$selectedClassDiv.find("select").each(function(i) {
var select = this;
$('#cloned-list').find("select").eq(i).val($(select).val());
});
The problem I have is that I would like to wrap these select items in a div that has a custom class. I've tried multiple methods to no avail, my latest attempts below.
Has no effect
$('#cloned-list').html($selectedClassDiv.find('select').clone().wrap('<div class="customClass"></div>'));
Demo: https://jsfiddle.net/DTcHh/36309/
Causes error
$('#cloned-list').html($selectedClassDiv.find('select').clone().parent().wrap('<div class="customClass"></div>'));
Demo: https://jsfiddle.net/DTcHh/36310/
I am interested in a solution that wraps a div around the select items. Cloning the parent div and adding a class isn't an option.
You could add it within your current loop:
https://jsfiddle.net/DTcHh/36311/
$selectedClassDiv.find("select").each(function(i) {
var select = this;
$('#cloned-list').find("select").eq(i).val($(select).val()).wrap('<div class="customClass"></div>');
});

Assign java scripts to cloned HTML element

I have a html div and I clone it using Jquery. That div contains labels and text fields. ids of all of them generated and assigned dynamically. I have no problem with that.
A java script is assigned to a text field of original div. The cloned text fields does not have the javascript assigned to it.
the script I need to assign:
<script>
$(function() {
$("#datepick_onBooking,#datepick_Pay1,#datepick_Pay2,#datepick_totPay,#datepick_deedFees").datepicker();
});
</script>
the script I use to make clones:
<script>
var i = 3;
//When DOM loaded we attach click event to button
$(document).ready(function() {
$('#addAnotherPayment').click(function() {
var cloned = $('.PayDiv0').first().clone();
var noOfDivs = $('.PayDiv0').length+2;
cloned.insertBefore("#totPayForm");
// append count to the ids
cloned.attr('id', 'PayDiv' + noOfDivs);
cloned.find('label').attr('id', 'PayLbl' + noOfDivs);
cloned.find('input[type="text"]').attr('id', 'datepick_Pay'+ noOfDivs);
cloned.find('input[type="number"]').attr('id', 'amount_Pay'+ noOfDivs);
cloned.find('.PayLbl2').html("Payment No " + i++ + ':');
});
});
</script>
datepick_Pay1, datepick_Pay2, datepick_totPay, datepick_deedFees are static elements and they have been assigned to the script. I create text fields using cloning as datepick_Pay3,datepick_Pay4, and so on.
I cannot figure out how to dynamically assign the script to that newly created elements.How can I do that?
A Boolean indicating whether event handlers and data should be copied along with the elements.
change this line.
var cloned = $('.PayDiv0').first().clone(true);
when you clone something especially elements which having events
use parameter as
clone(true)
But this will be harmfull based on how event is attached on the actual element when copying the events to the cloned element may affect the actual.
You need to clone with events. http://api.jquery.com/clone/
var cloned = $('.PayDiv0').first().clone(true);
Then your script needs to be changed to work for dynamic elements. Here as soon as input elements gets focus, asssign the datepicker based on wild card id selector, if it doesn't already have one.
$(function() {
$('body').on('focus',"input[id^=datepick_]", function(){
if(!$(this).hasClass('.hasdatepicker'))
{
$(this).datepicker();
}
});
});

Trouble with javascript click() method / html

Thank you in advance for looking at this.
My webapp allows a user to select choices from four different drop-down menus. When the user makes a selection, the program successfully performs the following click() function which creates a new span element within a div element:
var activeFilterNames = [];
$('.filter').click(function()
{
if (!this.classList.contains('disabled'))
{
//above checks to see if link has already been clicked
//and is therefore disabled. If not, go ahead.
activeFilterNames.push(this.textContent);
//above adds name of selected link to array
i = activeFilterNames.length;
var newFilter = document.createElement('span');
newFilter.id = activeFilterNames[i-1];
newFilter.className = this.className+" activated";
//above adds a new class to identify the filter as 'activated'
//above retains existing classname to identify
//which of the four filters it came from
newFilter.innerHTML = activeFilterNames[i-1];
//above creates display text to be rendered in browser
document.getElementById('active_filters').appendChild(newFilter);
//above is the div in which span will be appended to other spans.
$("#active_filters > span").removeClass('filter');
//above removes .filter class so that this newly created span does
//not respond to the .filter click() function.
$(this).addClass('disabled');
//above adds 'disabled' class to the originally
//clicked link, causing it to skip this block of code
}
}
);
Everything appears to work fine up to this point (though I may be missing something). Essentially I am creating span elements that come out looking like this in html:
<span id="id_name" class="menu_name activated">Rendered Name</span>
And since the above span does not have the filter class, I then try to create a new function in javascript (just as a test) to make the element responsive:
$('.activated').click(function()
{
alert('hi');
}
);
But no luck. I've tried to re-render the dynamically created elements by nesting div or a inside the span, modifying the code as needed, but still nothing. I would like to keep the span because it's the only way I've found to wrap these dynamically generated elements to a second line within the div (#active_filters) where they are being created.
Can anyone see what I'm doing wrong given that I want to make the activated click() function responsive within each newly created span element?
Your binding will not work if you attempt to bind to DOM elements contained in $('.activated') before creating them. What this usually means is that you need that event listener to bind after creating. If you're dynamically creating DOM elements, you need to do something like this:
var activeFilterNames = [];
$('.filter').click(function()
{
if (!this.classList.contains('disabled'))
{
activeFilterNames.push(this.textContent);
i = activeFilterNames.length;
var newFilter = document.createElement('span');
newFilter.id = activeFilterNames[i-1];
newFilter.className = this.className+" activated";
newFilter.innerHTML = activeFilterNames[i-1];
document.getElementById('active_filters').appendChild(newFilter);
$('.activated').unbind('click');
$('.activated').click(function()
{
alert('hi');
}
);
$("#active_filters > span").removeClass('filter');
$(this).addClass('disabled');
}
}
);
Notice, before binding we unbind. This makes sure that if you do this multiple times, you aren't binding 2, 3, 4 times to the same DOM element.
You need to attach click event on dynamically created elements. In jQuery this can be done using on method if you will pass your selector as second argument and attach click to some parent element, body for example:
$( 'body' ).on( 'click', '.activated', function()
{
alert('hi');
}
);

JQuery Event Listeners in a For Loop

I am trying to create some basic button rollover functionality using Jquery and toggleClass. I am building a list of elements by cloning a DIV from my HTML and duplicating it multiple times (its populating a list of data from a database). To do this I am using a for loop. Here is the currently working code.
var displayNode = document.getElementById('phoneDisplayContainer');
for(var i=0; i<length; i++) {
//Clone the original container display.
var clonedDisplay = displayNode.cloneNode(true);
clonedDisplay.setAttribute('id', 'phoneDisplayContainer' + i);
//Remove hidden class from cloned Element. NOT CROSS BROWSER!
clonedDisplay.classList.remove('hidden');
var children = clonedDisplay.getElementsByTagName('div');
//Fill new nodes children containers with data.
children[1].innerHTML = contact.phone[i].type;
children[2].innerHTML = contact.phone[i].number;
children[3].setAttribute('onclick', 'PhoneUtility.edit(' + i + ');');
children[3].setAttribute('id', 'phoneEditDisplay' + i);
children[4].setAttribute('onclick', 'PhoneUtility.remove(' + i + ');');
//Hidden elements
var hidden = new Array(children[3], children[4]);
//Set rollover events.
clonedDisplay.setAttribute('onmouseover', '$("#' + children[3].id + '").toggleClass("hidden");');
clonedDisplay.setAttribute('onmouseout', '$("#' + children[3].id + '").toggleClass("hidden");');
//Append the new node to the display container
phoneContainer.appendChild(clonedDisplay);
}
}
Is there a way to use Jquery event listeners instead of having to set onmouseover and onmouseout directly on the element?
I tried this:
$(clonedDisplay).mouseover(function() {
$(children[3]).toggleClass('hidden');
});
With no luck. It just displays performs the rollover effect on the last element in the list. This is actually my first attempt at using jQuery so any other suggestions to ways I could jQuery inside the code would be helpful too.
EDIT: I'd also like to toggle multiple children from the arraylist mentioned in the for loop. How would I set this up? I can't seem to pass an array to the jquery command without getting errors.
The following code after your for loop should let you assign all the mouseover and mouseout handlers in one go to apply to all the clones:
$('div[id^="phoneDisplayContainer"]').mouseover(function() {
$(this).find("div").eq(3).toggleClass("hidden");
}).mouseout(function() {
$(this).find("div").eq(3).toggleClass("hidden");
});
// or, given that both handlers do the same thing:
$('div[id^="phoneDisplayContainer"]').on("mouseover mouseout", function() {
$(this).find("div").eq(3).toggleClass("hidden");
})
(If you're using jQuery older than 1.7 use .bind() instead of .on().)
The above says to find all the divs with an id beginning with "phoneDisplayContainer" and assign event handlers. Within the handler, find the fourth descendant div and toggle the class.
You don't show your HTML or CSS, but you could do this all in your CSS if you like. Assuming you can assign a common class ("parentDiv") to the divs that you want to trap the hover event on, and a common class ("childDiv") to their child div (the one to be hidden), you can do this:
.parentDiv .childDiv { visibility: hidden; }
.parentDiv:hover .childDiv { visibility: visible; }
(Obviously you can give more meaningful class names to fit your structure.)
Otherwise, again if you can assign those classes to the appropriate divs then after your loop you can do this with jQuery:
$(".parentDiv").on("mouseover mouseout", function() {
$(this).find(".childDiv").toggleClass('hidden');
});
Basically the same as what I said initially, but using classes for selectors. If you feel like I'm pushing a class-based solution on you that's because I am: it tends to make this sort of thing much easier.

Categories