clone select element and wrap - javascript

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>');
});

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");

Tooltips for dynamic elements

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

Dynamically adding onchange function to drop down with jQuery

I have a couple of drop down boxes with ids country1, country2, ... When the country is changed in a drop down the value of the country shoudl be displayed in an alert box.
if I add the onchange handler for one box like this it works fine:
$('#country1') .live('change', function(e){
var selectedCountry = e.target.options[e.target.selectedIndex].value;
alert(selectedCountry);
});
But I need to do this dynamically for all drop down boxes so I tried:
$(document).ready(function() {
$('[id^=country]') .each(function(key,element){
$(this).live('change', function(e){
var selectedCountry = e.target.options[e.target.selectedIndex].value;
alert(selectedCountry);
});
});
});
This doesn't work. No syntax error but just nothing happens when the seleted country is changed. I am sure that the each loop is performed a couple of times and the array contains the select boxes.
Any idea on that?
Thanks,
Paul
The reason .live() existed was to account for elements not present when you call the selector.
$('[id^=country]') .each(function(key,element){ iterates over elements that have an id that starts with country, but only those that exist when you run the selector. It won't work for elements that you create after you call .each(), so using .live() wouldn't do you much good.
Use the new style event delegation syntax with that selector and it should work:
$(document).on('change', '[id^=country]', function(e) {
// ...
});
Replace document with the closest parent that doesn't get dynamically generated.
Also, consider adding a class to those elements along with the id attribute.
Instead of incremental ids I'd use a class. Then the live method is deprecated but you may use on with delegation on the closest static parent or on document otherwise.
$('#closestStaticParent').on('change', '.country', function() {
// this applies to all current and future .country elements
});
You don't need an each loop this way; plus events are attached to all the elements in the jQuery collection, in this case all .country elements.

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.

jQuery - Find next select element

What I am trying to do is populate data in a select element. I'm using the following code, where a user selects a SubjectCategory from one drop down, which then should populate the next select element's html. The handler itself is working just fine, it returns the correct html I need to place inside the select element.
Also, keep in mind that I eventually clone both of these select elements and will need to populate them accordingly.
The problem is that $elem is always returning null.
I'm guessing that it's a problem with this line of code, however not quite sure (keeping in mind that I'm also cloning these two select elements):
var $elem = $this.closest('div').prev().find('select');
$(".SubjectCategory").live("click", function () {
var $this = $(this);
var $elem = $this.closest('div').next().find('select');
var a = $this.val();
$.get("/userControls/BookSubjectHandler.ashx?category=" + a, {}, function (data) {
$elem.html(data);
});
});
<div class="singleField subjectField">
<label id="Category" class="fieldSml">Subject Matter</label>
<div class="bookDetails ddl"><select id="ddlSubjectMatter" class="fieldSml SubjectCategory"></select></div>
<label id="Subjects" class="fieldSml">Category</label>
<div class="bookDetails ddl" id="subjectMatter"><select id="ddlSubjects" class="fieldSml Subjects"></select></div>
</div>
You're searching inside the <label>, not the next <div> as you want. next only gets one element after the current one.
Try this: It searches for the first div next to your parent element.
var $elem = $this.closest('div').nextAll('div').first().find('select');
Given that the source element has an id of ddlSubjectMatter and the target select element has an id of subjectMatter, it may be a lot simpler to capitalise the first letter of the second id (i.e. make SubjectMatter) then you get the second element by:
var elem = document.getElementById(this.id.replace(/^ddl/,''));
It makes the element relationship independent of the document layout.
Incidentally, it is invalid HTML to have select elements with no options, not that it is a big issue.
Why are you creating an extraneous $this variable? Unless you've omitted code that requires it for a different scope, just call $(this). That might be causing the problem, too.

Categories