IE8 does not clone elements - javascript

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.

Related

Why does jQuery return more than one element when selecting by type and ID? [duplicate]

I fetch data from Google's AdWords website which has multiple elements with the same id.
Could you please explain why the following 3 queries doesn't result with the same answer (2)?
Live Demo
HTML:
<div>
<span id="a">1</span>
<span id="a">2</span>
<span>3</span>
</div>
JS:
$(function() {
var w = $("div");
console.log($("#a").length); // 1 - Why?
console.log($("body #a").length); // 2
console.log($("#a", w).length); // 2
});
Having 2 elements with the same ID is not valid html according to the W3C specification.
When your CSS selector only has an ID selector (and is not used on a specific context), jQuery uses the native document.getElementById method, which returns only the first element with that ID.
However, in the other two instances, jQuery relies on the Sizzle selector engine (or querySelectorAll, if available), which apparently selects both elements. Results may vary on a per browser basis.
However, you should never have two elements on the same page with the same ID. If you need it for your CSS, use a class instead.
If you absolutely must select by duplicate ID, use an attribute selector:
$('[id="a"]');
Take a look at the fiddle: http://jsfiddle.net/P2j3f/2/
Note: if possible, you should qualify that selector with a type selector, like this:
$('span[id="a"]');
The reason for this is because a type selector is much more efficient than an attribute selector. If you qualify your attribute selector with a type selector, jQuery will first use the type selector to find the elements of that type, and then only run the attribute selector on those elements. This is simply much more efficient.
There should only be one element with a given id. If you're stuck with that situation, see the 2nd half of my answer for options.
How a browser behaves when you have multiple elements with the same id (illegal HTML) is not defined by specification. You could test all the browsers and find out how they behave, but it's unwise to use this configuration or rely on any particular behavior.
Use classes if you want multiple objects to have the same identifier.
<div>
<span class="a">1</span>
<span class="a">2</span>
<span>3</span>
</div>
$(function() {
var w = $("div");
console.log($(".a").length); // 2
console.log($("body .a").length); // 2
console.log($(".a", w).length); // 2
});
If you want to reliably look at elements with IDs that are the same because you can't fix the document, then you will have to do your own iteration as you cannot rely on any of the built in DOM functions.
You could do so like this:
function findMultiID(id) {
var results = [];
var children = $("div").get(0).children;
for (var i = 0; i < children.length; i++) {
if (children[i].id == id) {
results.push(children[i]);
}
}
return(results);
}
Or, using jQuery:
$("div *").filter(function() {return(this.id == "a");});
jQuery working example: http://jsfiddle.net/jfriend00/XY2tX/.
As to Why you get different results, that would have to do with the internal implementation of whatever piece of code was carrying out the actual selector operation. In jQuery, you could study the code to find out what any given version was doing, but since this is illegal HTML, there is no guarantee that it will stay the same over time. From what I've seen in jQuery, it first checks to see if the selector is a simple id like #a and if so, just used document.getElementById("a"). If the selector is more complex than that and querySelectorAll() exists, jQuery will often pass the selector off to the built in browser function which will have an implementation specific to that browser. If querySelectorAll() does not exist, then it will use the Sizzle selector engine to manually find the selector which will have it's own implementation. So, you can have at least three different implementations all in the same browser family depending upon the exact selector and how new the browser is. Then, individual browsers will all have their own querySelectorAll() implementations. If you want to reliably deal with this situation, you will probably have to use your own iteration code as I've illustrated above.
jQuery's id selector only returns one result. The descendant and multiple selectors in the second and third statements are designed to select multiple elements. It's similar to:
Statement 1
var length = document.getElementById('a').length;
...Yields one result.
Statement 2
var length = 0;
for (i=0; i<document.body.childNodes.length; i++) {
if (document.body.childNodes.item(i).id == 'a') {
length++;
}
}
...Yields two results.
Statement 3
var length = document.getElementById('a').length + document.getElementsByTagName('div').length;
...Also yields two results.
What we do to get the elements we need when we have a stupid page that has more than one element with same ID? If we use '#duplicatedId' we get the first element only. To achieve selecting the other elements you can do something like this:
$("[id=duplicatedId]")
You will get a collection with all elements with id=duplicatedId.
From the id Selector jQuery page:
Each id value must be used only once within a document. If more than one element has been assigned the same ID, queries that use that ID will only select the first matched element in the DOM. This behavior should not be relied on, however; a document with more than one element using the same ID is invalid.
Naughty Google. But they don't even close their <html> and <body> tags I hear. The question is though, why Misha's 2nd and 3rd queries return 2 and not 1 as well.
If you have multiple elements with same id or same name, just assign same class to those multiple elements and access them by index & perform your required operation.
<div>
<span id="a" class="demo">1</span>
<span id="a" class="demo">2</span>
<span>3</span>
</div>
JQ:
$($(".demo")[0]).val("First span");
$($(".demo")[1]).val("Second span");
Access individual item
<div id='a' data-options='{"url","www.google.com"}'>Google</div>
<div id='a' data-options='{"url","www.facebook.com"}'>Facebook</div>
<div id='a' data-options='{"url","www.twitter.com"}'>Twitter</div>
$( "div[id='a']" ).on('click', function() {
$(location).attr('href', $(this).data('options').url);
});
you can simply write $('span#a').length to get the length.
Here is the Solution for your code:
console.log($('span#a').length);
try JSfiddle:
https://jsfiddle.net/vickyfor2007/wcc0ab5g/2/

WordPress - jQuery function to multiple elements with same class/id

The code below is adding a placeholder to my #e_newsletter_email div. However I have added an additional signup box for the e-newsletter and the placeholder is not showing up on the second one. Is there a way to apply this code to work on both signup boxes?
jQuery(function($) {
$('#e_newsletter_email').attr( 'placeholder', 'You Email Address' );
});
I have tried to add this code to to force the id to add a class but again this only works on the first id. Any other thoughts?
jQuery(function($) {
$('#e_newsletter_email').addClass('e_newsletter_email');
});
Thanks
An Id can only be used once. Use classes for elements that do not need to be uniquely identified.
After some help from #mark.hch we where able to figure out how to create a workaround. Below is the final code:
<script type="text/javascript">
jQuery(function($) {
$('input').each(function() { if($(this).attr('id') == 'e_newsletter_email') { $(this).addClass('e_newsletter_email_custom'); } });
});
jQuery(function($) {
$('.e_newsletter_email_custom').attr( 'placeholder', 'You Email Address' );
});
</script>
First we needed to loop through each id and add a new class to the e_newsletter_email (which was being used twice). Then once we added the class to the id we where able to update the original function to use class instead of id and everything worked perfectly!
The true answer to the question is to use a class instead of an ID for both fields. As mentioned in the comments, an ID should be unique to each element on a page. In this case, however, the elements only contained an ID and the question then becomes how to add a class to the elements so a future selector can grab them all (or both) to manipulate them.
Using the ID selector $('#e_newsletter_email') only selects one element (as jQuery assumes there is only one element with that ID). So we need a more general selector - in this case, both elements are inputs, so the selector $('input') should grab at least those elements.
Since there could be more inputs on the page than the ones in question, we then need to filter out the ones we want; in this case, we compare the ID attribute of the elements (since we know, even though they're supposed to be unique, two actually contain the same ID).
Grabbing the ID of the element will work even if there are multiple elements with the same ID ($(this).attr('id') will always display the element's assigned ID, even if not unique).
So the code becomes:
//loop through all inputs
$('input').each(function() {
//if the input currently iterating over has the ID in question
if$(this).attr('id') == 'e_newsletter_email') {
//add the class for the input
$(this).addClass('e_newsletter_email_custom');
}
});

Grab the element with d3js

I'm trying to learn d3js library. Faced with the problem of the capture table's TD element by clicking. I usually use this way
window.addEventListener("load", function(){
document.getElementById("table_id").addEventListener("click",function(e){
var elem = e.target || e.srcElement;
if(elem.nodeName != "TD") return;
...
}
...
So i need to do something like that in d3js. But I don't know how to substitute .target and .srcElement methods.
What I do have
d3.select(#table_id).on('click',function(){
var elem = ???
In this i have my table. In d3.event such information click clientX=327, clientY=129. The d is undefined
Please, help me to grab TD element in var.
D3js is very flexible and you don't need to use d3.event.target every time.
As you asked, some details missed in your code:
1. Selection
There are two selection functions in d3 :
d3.select() it gets or finds specific tag or element or class or tag id, for example:
d3.select('div') returns first div or d3.select('.active') find tag have class named active. In your case you should used3.select('#table_id') you missed single quotation in select function.
The next d3 selection function is d3.selectAll() that act like d3.select() but the difference is this function select all the parameters, for example :
d3.selectAll('p') return all the p tags or all Id or classes get as parameter.
2. different between this and d
this is an argument that use to select specific tag you try to select or do some stuff on it and is more usable in selectAll function because you don't know which tag selected.
d is an object or DOM that contain all the properties and events.
So I changed your code and hope it's help you to learn d3 better.
d3.select("#table_id").on("click",function(){
var elem=d3.select(this);
if(elem.attr("name")!=="TD")
return;
});
more information here.

Disable a text area by it's class (not id)

I have 2 text area's that are generated automatically, and I need to use JavaScript to disable both when the page has loaded. The catch is because they are generated automatically I can't give them an ID because they would both have the ID - a big no.
Attempted Javascript:
document.getElementByClassName('option_window-size').disabled=true;
I know this works because if I change getElementbyClassName to ID then it will work if I give the text areas the ID as well. But as I say it needs to work off class. Also it can't work of the Name attribute because that is automatically generated per product and per page...
I have tried this but it just doesn't work and I can't figure out why not because it should as the only thing I have changed is from ID to CLASS
Text Areas
<textarea name="willbeautogenerated" class="option_window-size" cols="40" rows="5">willbeautogenerated</textarea>
Additional note: I have tried to count and assign them different IDs using PHP but it gets far to complex. Also it is only these two that need disabling, thus I can't just disable all text area's on the page.
I know this works because if I change getElementByClassName to ID then it will work if I give the text areas the ID as well. But as I say it needs to work off class.
getElementsByClassName returns a NodeList rather than a Node itself. You'll have to loop over the list, or if you expect just 1 item, choose index 0.
var nodes = document.getElementsByClassName("option_window-size"),
i = 0, e;
while (e = nodes[i++]) e.disabled = true;
jQuery makes this pretty simple:
$(".selector").prop("disabled", true);
ALTHOUGH! It should be noted that this note appears on the man pages for $.prop() and $.attr():
Note: Attempting to change the type property (or attribute) of an input element created via HTML or already in an HTML document will result in an error being thrown by Internet Explorer 6, 7, or 8.
This doesn't apply directly to your question, but you are changing prop/attrs on an input element, so be aware.
But it's still possible with plain old JS:
var els = document.getElementsByClassName("selector"); // note: Elements, not Element
for(var e = 0; e < els.length; e++)
{
els[e].disabled = true;
}
getElementsByClassName returns an NodeList, you just have to iterate over each element within.
You can use class selector,
$('.option_window').attr('disabled', true);
OR
$('.option_window')[0].disabled = true;
With Jquery you can do:
//make sure to use .prop() and not .attr() when setting properties of an element
$('.option_window').prop('disabled', true);
Disable textarea using jQuery:
$('.option_window-size').attr('disabled', true);
your missing a s in elements and the index where the element is like [0], for the first element.
document.getElementsByClassName('option_window-size')[0].disabled=true;
or
document.getElementsByName('willbeautogenerated')[0].disabled=true;
Disabel texarea using .prop() methode in jquery...
$('.option_window-size').prop('disabled', true);
You can use CSS:
.option_window-size{display:none;}

jQuery - Append Option to Option object

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.

Categories