Javascript code behaves proper in IE and improper in firefox - javascript

i need a clarification regarding my bug.
my requirement is to get the html tag names used in UI dynamically using javascript. Where my code got executed in IE, but it's not proper in Mozila Firefox.
My Code,
HTML CODE:
<table>
<tr>
<td>
<input type="text" />
</td>
<td>
<select>
<option>p_string1</option>
<option>p_string5</option>
</select>
</td>
</tr>
</table>
JS:
for (i = 0; i < table.rows[0].cells.length; i++)
{
pNode[i] = table.getElementsByTagName('td')[i].childNodes[0].nodeName;
}
I'm getting the value #text instead of the tag name Select. But getting the tagname INPUT properly..

I would assume this is because firefox (correctly) selects the first childNode, which is whitespace. If you remove ALL white space between the and the you'd probably get the correct tag.
EDIT, like this:
<td><input
I created some jsFiddles to demonstrate the effect:
http://jsfiddle.net/NUEwg/2/
http://jsfiddle.net/zbmeG/1/
EDIT 2:
You could consider using document.querySelectorAll. This is support in all browsers except IE6 and IE7. If you don't need support for these, something like this might work.
var inner_tags = document.querySelectorAll('td > *')
var first_tag = inner_tags[0].tagName;
Hope this helps.

use the tagName and firstChild element attributes:
http://www.w3schools.com/jsref/prop_element_tagname.asp
var cells = table.getElementsByTagName('td');
for (i = 0; i < table.rows[0].cells.length; i++)
{
var cell = cells[i];
if ( cell && cell.firstChild) {
result = null;
for ( position in cell.childNodes){
if (! result) result = cell.childNodes[position].tagName;
}
pNode[i] = result;
}
}
Notice that line hops and tabulation are noticed by some browsers as TextNodes, which have not tagName, because of that we cycle through the childnodes searching for a defined tagName attribute.
I updated the example at http://jsfiddle.net/9YJsd/1/

Related

jquery help to get element in array that contains certain class

jqTds =[
<td class=​"hidden-xs sorting_1">​text1​</td>​
<td class="​ ">​text2​</td>​
<td class=​" ">​text3​</td>​
<td class=​" ">​text4​</td>​
<td class=​" ">​​Edit​​</td>​
<td class=​" ">​​Delete​​</td>​]
How can I get all elements that has a "anchor" with class "edit-row" or "delete-row" and get all other that does not have it
// I am editing a script that uses DataTables.Js what I am trying to do is getting all elements from a table row into (var jqTds = $('>td:not(.hide_me)', nRow)) and now I want to include an input in all elements except the ones that has save-row class and edit-row class cos they are link to save/delete
thanks in advance
No idea why you have them in "an array", but if you run this while they are still in the DOM, use the :has pseudo selector:
var $tds = $('td:has(a:.edit-row,a:delete-row)');
var $otherTds = $('td').not($tds);
The first one reads. *find any td that has an anchor within it with class edit-row or an anchor within it with class delete-row".
The second one simply says, find all tds and exclude the first lot from the matches :)
You can use $.grep() to filter your array.
Using the function passed to $.grep() you can try and find your elements within the current <td>. If neither a.edit-row or a.delete-row are found return true, otherwise return false:
var filteredTds = $.grep(jqTds, function(td){
var $td = $(td);
return !$td.find('a.edit-row').length && !$td.find('a.delete-row').length;
});
JSFiddle
I was able to do like this:
for (var i = 0; i < editColumn.length; i++) {
if ($(editColumn[i]).find("a").hasClass("edit-row") == true) {
editColumn[i].innerHTML = '<a class="save-row" href="">Salvar</a>';
}
else if ($(editColumn[i]).find("a").hasClass("delete-row") == true) {
editColumn[i].innerHTML = '<a class="cancel-row" href="">cancelar</a>';
}

javascript-single onclick event to highlight cells in different tables

i have a requirement to highlight cells in different tables which are created dynamically. i have created tables and now looking the same to highlight with some condition. my code look like as follows,
<script type="text/javascript">
function compare()
{
var rows =document.getElementsByClassName('highlight').tBodies[0].rows, numOfRows = rows.length;
for (var i = 0; i < numOfRows ; i++)
{
if(rows[i].cells[1].innerHTML !== rows[i].cells[2].innerHTML )
{
rows[i].className='rowChange';
rows[i].cells[1].className = 'cellChange';
rows[i].cells[2].className = 'cellChange';
}}
}
</script>
<body>
<div><input type="button" value="highlight" onclick="compare" /></div>
<table id='main'>
<tr>
<td>table1</td>
<td><table class='highlight' id='child1'><tr><td>test1</td><td>test2</td><td>test3</td></tr></table></td>
</tr>
<tr>
<td>table2</td>
<td><table class='highlight' id='child2'><tr><td>test2</td><td>test2</td><td>test2</td></tr></table></td>
</tr>
----
----
----
<tr>
<td>table'n'</td>
<td><table class='highlight' id='childn'><tr><td>test'n'</td><td>test'n'</td><td>test'n'</td></tr></table></td>
</tr>
</table>
</body>
if i highlight using 'id' attribute that's working fine. but it's making code to be too complex. so please suggest me to me meet my goal efficiently. thanks in advance.
You are basically using the document.getElementByClassName incorrectly:
https://developer.mozilla.org/en-US/docs/Web/API/document.getElementsByClassName
The document.getElementByClassName does not return any tBodies, but the HTMLCollection of the mached elements i.e. an array of elements with the searched class.
You should also note that its IE9+ compadible, but I guess you already know that.
Anyway, the correct implementation to get the rows is this:
var rows = document.getElementsByClassName('highlight')[0].rows
As soon as I did that change it worked like a charm.
EDIT: Well the simplest way to get your code to work is to simply add in another loop. One for the tables and one for the table rows.
function compare() {
var tables =document.getElementsByClassName('highlight'), rows, numOfRows, i,j;
for(j = 0; j < tables.length; j++) {
rows = tables[j].rows;
numOfRows = rows.length;
for (var i = 0; i < numOfRows ; i++)
{
if(rows[i].cells[1].innerHTML !== rows[i].cells[2].innerHTML )
{
rows[i].className='rowChange';
rows[i].cells[1].className = 'cellChange';
rows[i].cells[2].className = 'cellChange';
}
}
}
}
But this is not actually how I would advise you to do this (on the assumption you are creating the tables on the client side dynamically). The problem is that you are looking up your tables with document.getElementByClassName however, as you pointed out, in your actual code, you are creating the tables dynamically, with means, at the time of the creation of the tables you could simply store a reference to those tables into an array and go through that instead. There really is no need for you to use document.getElementByClassName you are simply taxing the system with it.

Internet Explorer Javascript/ Dom Object add rows problem

Here is my Javascript code :
function generate(choice)
{
if(choice==1)
{
charge++;
var new_row=document.createElement("tr");
var name="row"+charge;
new_row.setAttribute("name",name);
new_row.setAttribute("id",name);
var col1=document.createElement("td");
var col2=document.createElement("td");
var col3=document.createElement("td");
var col4=document.createElement("td");
col1.setAttribute("width","205");
col2.setAttribute("width","191");
col3.setAttribute("width","182");
col4.setAttribute("width","127");
var list1=document.getElementById("rep0").cloneNode(true);
id="rep"+charge;
list1.setAttribute("id",id);
var list2=document.getElementById("item0").cloneNode(true);
name="items[]";
list2.setAttribute("name",name);
id="item"+charge;
list2.setAttribute("id",id);
list2.setAttribute("onChange","match_row(this.id);");
// clone_nodes(list2,"item0");
var text=document.createElement("input");
name="minutes[]";
text.setAttribute("name",name);
text.setAttribute("value","15");
id="minutes"+charge;
text.setAttribute("id",id);
text.setAttribute("type","text");
var text2=document.createElement("input");
name="charges[]";
text2.setAttribute("name",name);
text2.setAttribute("value","28.00");
id="charges"+charge;
text2.setAttribute("id",id);
text2.setAttribute("type","text");
//text2.setAttribute("onChange","charge_calculator();");
col1.appendChild(list1);
col2.appendChild(list2);
col3.appendChild(text);
col4.appendChild(text2);
new_row.appendChild(col1);
new_row.appendChild(col2);
new_row.appendChild(col3);
new_row.appendChild(col4);
charges1=document.getElementById("charges");
charges1.appendChild(new_row);
final_charge=charge;
}
else if(choice==2)
{
payment++;
var new_row2=document.createElement("tr");
var col11=document.createElement("td");
var col22=document.createElement("td");
var col33=document.createElement("td");
col11.setAttribute("width","205");
col22.setAttribute("width","206");
col33.setAttribute("width","297");
var list11=document.createElement("select");
name="payment_type[]";
list11.setAttribute("name",name);
id="payment_type"+payment;
list11.setAttribute("id",id);
list11.setAttribute("onChange","set_payment_type(this.id);");
clone_nodes(list11,"payment_type0");
var text1=document.createElement("input");
text1.setAttribute("type","text");
name="amount[]";
text1.setAttribute("name",name);
id="amount"+payment;
text1.setAttribute("id",id);
var list22=document.createElement("select");
name="account[]";
list22.setAttribute("name",name);
id="account"+payment;
list22.setAttribute("id",id);
list22.setAttribute("onChange","correspond2(this.id);");
clone_nodes(list22,"account0");
col11.appendChild(list11);
col22.appendChild(text1);
col33.appendChild(list22);
new_row2.appendChild(col11);
new_row2.appendChild(col22);
new_row2.appendChild(col33);
charges2=document.getElementById("payments");
charges2.appendChild(new_row2);
final_payment=payment;
}
}
And here is the html button code with which I'm calling
<input type="button" name="Add More" id="Add More" value="Add More" onClick="generate(1);" />
Everything is working like a charm in all other browsers Except Internet Explorer
please help me I'm stuck. I have work out out for IE also.
For your own sanity, use a library like jQuery to achieve this kind of things.
Please, do not use the appendChild method to add rows to a table, or cells to a table row. So you will avoid the need of explicitly creating a TBODY element, appending it to the table, then creating and appending TR elements to that TBODY.
There are standard DOM methods that are specifically intended for this use. Namely:
1.) var newRow = myTable.insertRow(index)
Inserts and returns a new empty row (TR element) at the given index.
2.) myTable.deleteRow(index)
Deletes the row at the given index.
3.) var newCell = myRow.insertCell(index)
Inserts and returns a new empty cell (TD element) at the given index.
4.) myRow.deleteCell(index)
Deletes the cell at the given index.
All those methods normally throw an error if the index argument is out of range. However in some browsers like IE8 the index is optional and if it is omitted the cell or row will be inserted or removed at the end of its parent.
Your code isn't very clear but I think you will append the tr elements to table. But you can't append a tr directly to a table in ie. You need to create a tbody element first add this to table and append then your tr to the tbody element.

odd even class for table rows

I have table with rows where as in between have hidden rows and because of that odd even css class not able to set. How can I avoid those hidden rows?
HTML
<tr class="oddRow">
<td>Avinash</td>
<td>18-Jun-2010</td>
<td>LI1004</td>
<td>5,600.00</td>
<td>Sort</td>
</tr><tr class="oddRow" style="display:none;">
<td>Ajith</td>
<td>18-Jun-2010</td>
<td>LI1006</td>
<td>5,001.00</td>
<td>!</td>
</tr><tr class="evenRow">
<td>Ankur</td>
<td>14-Jun-2010</td>
<td>LI1005</td>
<td>5,000.00</td>
<td>me</td>
</tr><tr class="oddRow">
<td>Ajith</td>
<td>18-Jun-2010</td>
<td>LI1006</td>
<td>5,001.00</td>
<td>!</td>
</tr>
I know this isn't tagged jQuery but this would be the easiest way to apply this solution...
You don't need two CSS classes here (odd and even), just one. Start by setting the CSS for every row to use the "oddRow" style declarations by default. The "evenRow" style declarations should simply overwrite the defaults.
Add this JS function
var zebraStripes = function($) {
$('table.stripes tr').removeClass('evenRow')
.filter(':visible:odd').addClass('evenRow');
// using the :odd selector as it is zero-based
}
You can then bind this function to the document ready event as well as any event that changes row visibility.
Edit
Updated to work with jQuery 1.7, example here - http://jsfiddle.net/UZNKE/6/
Assuming your question is asking what I posted in the comments, you'll have to have a more in-depth 'hide' function which will change the classes of all subsequent functions. I expect you'll want to use something like this:
function hideRow(rowNum)
{
var rows = document.getElementById('table-id').getElementsByTagName('table');
// get current class and hide the row
var currentClass = rows[rowNum].className;
rows[rowNum].style.display = 'none';
// set up classname array
var classNames = new Array("oddRow", "evenRow");
// make sure 'j' points to the next desired classname
var j = 0;
if (classNames[j] == currentClass)
j = 1;
// make all subsequent visible rows alternate
for (i=rowNum+1; i<rows.length; i++)
{
// ignore empty rows
if (rows[i].currentStyle.display == "none")
continue;
// set class name
rows[i].className = classNames[j];
j = (j+1) % 2;
}
}
Note: I haven't tested the code, but I commented it so you should be able to figure out what's going on

Faster way to populate <select> with Javascript

I have two <select> boxes on a form. Selecting an item in the first <select> box will determine what should appear in the second <select> (Using Ajax http_request).
In some cases there can be a large 500 (guess) items in the second select and it takes time 5-10 seconds to update in IE. Firefox seems to work perfectly.
I wonder if there is a faster way to achieve this. Currently the server creates a string passes it to the client which is then broken up and add each item to the select by creating an option element and then adding it to the <select>.
I did try to create the whole select item as a string on the server and add that to the form but for some reason it wouldn't work in Firefox (missed something?)
Thanks
500 elements is not a lot, even for IE. You must be doing something else to cause the lag.
I just tried with 500+ options in IE6, IE7, FF2 and FF3 and all were near instantaneous. I used this code:
var data = [
{ text: 'foo', value: 'bar' },
// ...
{ text: 'foo', value: 'bar' }
];
var select = document.getElementsByTagName('select')[0];
select.options.length = 0; // clear out existing items
for(var i=0; i < data.length; i++) {
var d = data[i];
select.options.add(new Option(d.text, i))
}
I would suggest profiling the bit of code that is fetching the data and populating the drop down. Something else might be taking up the time. For example, check that the code that "breaks up" the string value returned from the server is sharp (sounds like you're doing your own custom parsing there).
The first code is fine but this works better for me:
var data = [
{ text: 'uno', value: '1' },
{text: 'dos', value: '2' }
];
var select = document.getElementById('select-choice-1');
select.options.length = 0; // clear out existing items
for (var i = 0; i < data.length; i++) {
var d = data[i];
select.options.add(new Option(d.text, d.value))
}
Setting it using SelectElement.innerHTML would be the fastest... but that FAILS in IE.
Last I checked, you can do this in IE, if you wrap all the options in a bogus <div> tag, or set the entire .outerHTML of the select list in IE.
The problem with all these answers with SelectElement.innerHTML is that you cannot do this trick with SELECTs. The solution is to use innerHTML on the PARENT of the SELECT element itself. So in your ajax/jquery/whatever code create a string that contains ALL of the SELECT HTML, and then get the holder (a div or span or whatever) and set the innerHTML to the string you've constructed.
You will need to isolate the SELECT from the page and give it an explicit parent element (span or div) to prevent other html elements from being casualties when you destroy/reconstruct the SELECT element.
Short answer:
parentselectelement.removeChild(selectelement);
parentselectelement.innerHTML = "<select ...><options...></select>";
I would create the whole select on the server and inject it into the page. That approach bypasses annoying browser discrepancies, and reduces the complexity of the client-side code.
You did mention that you tried that, but it failed in firefox. I would suggest persevering in getting it to work, posting another question asking for help on that issue, or editing your question to show us what you made that didn't work in firefox.
Don't forget to append to document.createDocumentFragment() first, before appending that to the SELECT.
It would help greatly to see your code.
IF you are creating an <option> element and appending it each iteration, you should consider creating all the <option> elements at once, and then appending them all at once.
So (in psuedocode):
// Don't do this:
for choice in choices:
option = new Options(choice)
select.append(option)
// Do this instead
var options = array()
for choice in choices:
options.append( new Options(choice) )
for option in options:
select.append(option)
// Or you might try building the select element off-screen and then appending to the DOM
var options = array()
var select = new SelectElement()
for choice in choices:
select.append( new Options(choice) )
dom_element.append(select)
When I use the first version of this it works but can be very slow in updating the second select
<html>
<form id='myform' method='post' action='$_SERVER[PHP_SELF]'>
<table>
<tr><td><select onselect='CALL_AJAX_AND_UPDATE();'></select></td></tr>
<tr><td><select id='selectid'></select></td></tr>
</table>
</form>
</html>
<script type=\"text/javascript\">
function UPDATE( updatedata )
{
var itemid = document.getElementById('selectid');
var data = updatedata.split( '|' );
var len = data.length;
for( i=0; i < len; i ++ )
{
var opt = document.createElement('option');
opt.text = data[i];
try
{
itemid.add( opt, null );
}
catch(ex)
{
itemid.add( opt );
}
}
}
</script>
This version works in IE, but firefox doesn't seem to post the second selects data. Have I missed something with this.
<html>
<form id='myform' method='post' action='$_SERVER[PHP_SELF]'>
<table>
<tr><td><select onselect='CALL_AJAX_AND_UPDATE();'></select></td></tr>
<tr><td><div id='addselect'></div></td></tr>
</table>
</form>
</html>
<script type=\"text/javascript\">
function UPDATE( updatedata )
{
// update data is full select html
var itemid = document.getElementById('addselect');
itemid.innerHTML = updatedata;
}
</script>
I like Crescent Fresh's and Kemal Fadillah's answers since both use:
select.options.add(new Options(name, value))
As for the data object I recommend a small tweak as follows:
var data = {
'uno': 1,
'dos': 2
};
var select = document.getElementById('select-choice-1');
select.options.length = 0; // clear out existing items
for (var i in data) {
select.options.add(new Option(i, data[i]));
}
If you don't mind using CoffeeScript then the following code fills a select list with JSON data in a couple of lines.
HTML
<select id="clients"></select>
CoffeeScript
fillList=($list, url)=>
$.getJSON(url)
.success((data)->
$list
.empty()
.append("<option value=\"#{item.Id}\">#{item.Name}</option>" for item in data)
)
$ ->
fillList($('#clients'), '/clients/all')
Note : The loop inside the append generates the entire html string before calling the append method once. This is nice and efficient.
Example JSON
[
{"Id":"1","Name":"Client-1"},
{"Id":"2","Name":"Client-2"}
]

Categories