I have a 2 select boxes. The first select box alters the second. The second can have a small set of variable options.
What I have done is when the page loads I save the options as a variable.
var optionList = $('select[name="location"] option');
When the first select box changes. I then do something like below matching the value of the first select box to a switch statement then knocking out and adding new options to select box 2.
case 'add':
$('select[name="location"] option').remove();
$(optionList).each(function() {
$('select[name="location"]').append($(this));
});
$('select[name="location"] option:not(option[value="cart"])').remove();
break;
This all works fine.
What I need to do now is add an option to the optionList. I have tried both append and after. Append adds a new option inside the last option. After causes a jQuery error. Any idea how I do this?
var html = '<option value="'+v+'">'+l+'</label>';
$(optionList).append(html); // Fails
$(optionList).after(html); // jQuery error line 3
Firstly, you are appending an option tag, with a closing label tag, it should be:
var html = '<option value="'+v+'">'+l+'</option>';
Secondly, with the code you have it will append your new option after every existing option (as optionList is an array of all the existing option elements).
Instead you should just append it to the select element, like this:
$('select[name="location"]').append(html);
$('select[name="location"] option'); is selecting the options which are part of that select. So when you do $(optionList).append(html);, you are appending "html" to the each option in that results list.
Personally, I'd typically do something like:
var $mySelect = $('select[name="location"]');
var optionList = $mySelect.find('option');
...
$mySelect.append(html);
but you could also do something like this:
var optionList = $('select[name="location"] option');
...
optionList.filter(':first').parent().append(html);
The second option is less performant though.
optionList.push(html) didn't work because optionList is a jQuery-wrapped array of options (each one a jQuery-wrapped option), not a select's list of options within document.forms.
optionList.push($(html)) worked beause you wrapped the raw DOM element "html" with jQuery, and thus you were just adding another jQuery-wrapped option to optionList. You could save a character (and be a bit more jQueryish) if you instead did optionList.add($(html)). However, either of those would only add the "html" element to the optionList collection; it wouldn't actually add "html" to the DOM.
Last, two side notes... First, appending like you're doing in that loop is a really bad idea; you're hitting the DOM, and also triggering a repaint, on each time through the loop. You're far better creating an array of options, then doing something like
jQuery.fn.append.apply($('select[name="location"]'), objectArray);
That only does a single hit on the page, and triggers only one repaint. See http://www.learningjquery.com/2009/03/43439-reasons-to-use-append-correctly for more.
Second, $(optionList) is redundant and costs you some performance. optionList is already a jQuery object - ie, $('select[name="location"] option'). $(optionList) invokes the jQuery constructor, only to have it realize that optionList is already a jQuery object, and internally it is then converting your use of $(optionList) into jQuery actually just using optionList.
Related
I'm new to jQuery and am trying to create jQuery UI buttons dynamically and them to a list. I can create one list item but no more are appended after it. What am I doing wrong?
$('#buttonList').append('<li><button>'+ username + '</button>')
.button()
.data('type', userType)
.click(function(e) { alert($(this).data('type')); })
.append('<button>Edit</button></li>');
<div>
<ul id="buttonList">
</ul>
</div>
This only creates one list item with two buttons (although the second button seems to be encased in the first one, but I can probably figure that issue out). How do I get it to create multiple list items with their own unique 'data' values (i.e. I can't do a find() on a particular button class and give it data values as all buttons would then have the same data)?
I suggest to exchange the position of what you are appending and where you are appending to. This way, you retain the appended object, and should be able to work with it as a standard jQuery selector. From your code i commented out the .button() and the .append() lines, because i'm not sure what you want to do with them. Should you need help adding those lines, just drop a comment to my answer ;)
Oh, i almost forgot: i use var i to simulate different contents for username and userType data.
A JSFiddle for you is here: http://jsfiddle.net/cRjh9/1/
Example code (html part):
<div>
<p id="addButton">add button</p>
<ul id="buttonList">
</ul>
</div>
Example code (js part):
var i = 0;
$('#addButton').on('click', function()
{
$('<li><button class="itemButton">'+ 'username' + i + '</button></li>').appendTo('#buttonList')
//.button()
.find('.itemButton')
.data('type', 'userType'+i)
.click(function(e) { alert($(this).data('type'));
})
//.append('<button>Edit</button></li>')
;
i++;
});
You need complete tags when you wrap any html in a method argument. You can't treat the DOM like a text editor and append a start tag, append some more tags and then append the end tag.
Anything insterted into the DOM has to be complete and valid html.
You are also not understanding the context of what is returned from append(). It is not the element(s) within the arguments it is the element collection you are appending to. You are calling button() on the whole <UL>.
I suggest you get a better understanding of jQuery before trying to chain so many methods together
Just a very simplistic approach that you can modify - FIDDLE.
I haven't added the data attributes, nor the click function (I'm not really sure I like the
inline "click" functions - I generally do them in jQuery and try to figure out how to make
the code efficient. Probably not very rational, but I'm often so).
JS
var names = ['Washington', 'Adams', 'Jefferson', 'Lincoln', 'Roosevelt'];
for( r=0; r < names.length; r++ )
{
$('#buttonList').append('<li><button>'+ names[r] + '</button></li>');
}
$('#buttonList').append('<li><button>Edit</button></li>');
IE has confused me. I have two lists. One container.
The first list is filled with <option> of the branches. Mother branches.
The second list is empty for now.
The container which is a <div> is then filled with <option> of all child branches of all mother branches. There are many of them. But this container is hidden.
I have written jQuery code, to select the set of matched elements which are the child of the selected mother branch, and clone them into the child branch list.
check this fiddle to see it in action : http://jsfiddle.net/mostafatalebi/6WQ9x/
Here is the JavaScript code:
$(document).ready(function(){
$('#branches').on('change', function(){
var branch = $(this).val();
var subholder = $('#subbranch-holder');
// $('#sub').empty();
$('#sub').html("<option value='false'>انتخاب زیر شاخه ها</option>");
// console.log(subholder.children('option').length);
subholder.children('option').each(function(){
if($(this).attr('id') == 'par'+branch) {
var tempItem = $(this);
// $("#sub").append('this is : ');
$(this).clone().appendTo("#sub");
}
});
});
});
It works every where except IE.
the INTERESTING POINT IS THAT when I put the following line instead of the clone(), IE works:
$("#sub").append('IE is the worst browser');
It seems IE is in problem with $(this) and clone()
Older versions of jQuery have been tested. All have the same issue.
I have found the answer to this problem.
It seems <option> behaves quite differently than the other.
What I did was that, I used <input> tag instead of the tag, filled the "value" attribute with ID of child-branch, and filled the "id" attribute with parent_id of the child-branch preceded with "par" string, and eventually used "name" attribute to fill it with title of the child branch. Correspondingly I retrieved them in jQuery and it worked.
All of this efforts have been taken to fit it into IE8 whose usage is very limited, but still the customer insisted.
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.
I have some code that grabs the first select on the page and clones it so that I can reset it later on if needed.
mySelect = jQuery('select').get(0);
origSelect = jQuery(mySelect).clone();
jQuery(mySelect).change(function(){
//some code
}
When I fire the code to reset the select with:
jQuery(mySelect).replaceWith(origSelect);
The onChange function stops working. I've determined that it's because it is now referred to as origSelect and responds to onChanges for that name. Do I have any options here for replacing the content of mySelect with the content of origSelect without changing the name it's referred to by?
Pass a parameter true to the clone method.
origSelect = jQuery(mySelect).clone(true); //This will clone the select with data and events
or replace the innerHTMl of origSelect with that of mySelect.
jQuery(origSelect).html(jQuery(mySelect).html());
Use $(mySelect).live('change', ...) instead of $(mySelect).change(...).
What I am trying to do is clone 3 drop-down boxes and add them beneath the original set.
At the moment it works but the clones do not maintain the functionaility of the original set.
What the originals do is check the selected value of the first drop-down box in order to populate the drop-down lists for the other two.
Fiddle is below but adding the clones doesn't seem to work for some reason I can't figure out, it works on the page I am working on.
http://jsfiddle.net/pV6x5/6/
Thanks,
Martin
UPDATE
updated the fiddle, it was missing the advancedsearch div: http://jsfiddle.net/pV6x5/7/
Use jQuery live to keep the event's bound to the new elements. With live it binds the event to all present and future elements where just defining a handler for change will only bind for the current elements (you can also just reattach the events every time you create an element but why do it when live takes care of it for you)
$tags.live("change",function(){ /* your stuff here */});
UPDATE Here is the change function and if block:
$(document).ready(function()
{
$tags = $("select[name='tags']");
$tags.live("change",function()
{
$operands = $(this).parent().find("select[name='operands']");
$values = $(this).parent().find("select[name='values']");
if ($(this).val() == "agent")
{
$(this).parent().find("select[name='operands'] option").remove();
$("<option>=</option>").appendTo($operands);
$("<option>!=</option>").appendTo($operands);
$(this).parent().find("select[name='values'] option").remove();
$("<option>excel</option>").appendTo($values);
$("<option>msword</option>").appendTo($values);
$("<option>ppt</option>").appendTo($values);
$("<option>pdf</option>").appendTo($values);
$("<option>image</option>").appendTo($values);
$("<option>txt</option>").appendTo($values);
$("<option>html</option>").appendTo($values);
$("<option>csv</option>").appendTo($values);
$("<option>ooxml</option>").appendTo($values);
$("<option>flash</option>").appendTo($values);
$("<option>wmf</option>").appendTo($values);
}
I believe you need to use the .live() bind, so that it attaches the events to the objects made "in the future."
http://api.jquery.com/live/
So rather than .change() you need .live('change')