Understand adding rows on click, confusion with .cloneNode(true); - javascript

Consider this http://jsfiddle.net/99CL3/224/, Which adds rows on click
HTML
<br /><br />
<table id="tbl">
<tr>
<td><input type="text" name="links" /></td>
<td><input type="text" name="keywords" /></td>
<td><input type="text" name="violationtype" /></td>
<td><input type="submit" class="button" value="Add another line" onclick="addField(this);" /></td>
</tr>
</table>
JS
function addField(n)
{
var tr = n.parentNode.parentNode.cloneNode(true);
document.getElementById('tbl').appendChild(tr);
}
I'm trying to understand why this code which adds rows on click actually works.
First I realize that it will take what I click (the input), and go two parent nodes above it.
so the first .parentNode points to td, and the next to tr. So basically we are making a table on click with these new properties. Now my question is basically what is the role of .cloneNode(true) here? I have read mozilla documentation, but I can't really understand from their example. Why can't I just append n.parentNode.parentNode right away?

Each element is unique. if you don't clone the element then the element is moved to the target location. So using clone here is necessary for creating another row.

.cloneNode(true) duplicate the selected [tr] tag, if you remove it, your code however works but its behavior is different because the [tr] you selected already belongs to your table.
By the way, you should change name/id of cloned row's input, to make them unique.
p.s: your jsfiddle has only one parentNode, instead of two.

Related

Update background color jquery input inside td tag

I have a table with tr that have this pattern
<tr>
<td width="37" align="left"></td>
<td width="200" align="left">
<input type="submit" name="s1" onclick="ChangeThis(this);" value="Update Color" id="s1" class="btn-blue">
<input name="info1" type="text" maxlength="6" id="info1" style="color:Red;background-color:#FFFFFF;font-weight:normal;width:90px;">
</td>
<td width="340" align="center">
<input name="extra1" type="text" maxlength="200" id="extra1" style="width:330px;">
</td>
<td class="hide"></td>
</tr>
What I want to do is onclick on this button which will have the same sequence matching the input example button id=s1 input id =info1
I want to change the background color. I prefer jquery or javascript is fine. I thought about the regex with starting with .. ^ ..
function ChangeThis(x) {
$(this).closest('td').find('input[type="text"]').css('backgroundColor', 'Yellow');
}
That doesn't work, I tried tr instead of td
UPDATE/EDIT
So Essentially what I want is that When the button is clicked that there are predefined things to change in the text
Font Color
Bold or not
Background Color
UPDATE
Ok, I think I understand what you'd like.
Let me know if this fiddle solves it:
https://jsfiddle.net/14ymd0pd/
Based on your description, I'm a little confused as to what you'd like.
I've created a JSFiddle with what I think is the intended functionality.
https://jsfiddle.net/tvu08yrm/
The main differences involved separating out the JavaScript, using the jQuery on event handler:
$('.color-btn').on('click', function(){
adding a new class (color-btn) so the buttons could be targetted and changing the functions which trraverse the DOM Elements.
A couple of notes:
You should not be using inline JavaScript. I've separated out the JavaScript in my fiddle.
Since I can only see a small section of code it's hard for me to say, but if the page isn't going to be displaying tabular data then don't display it in a table...use a div or ul or another relevant element, just not a table.
I haven't done it in my fiddle, but you should also move the inline css out of the markup and into an external css file.
The JavaScript is dependant on the structure of the table, if you change its structure you'll also need to update the jQuery selectors. This can be avoided by following a naming convention in the table rows and using these to target the appropriate elements instead of their relative positions.
Let me know if the fiddle answered your question :)
There are many solutions to get your code working.
First solution: use x instead of this inside the function
pro: code works
contra: bad coding style and you should not use inline javascript.
Second solution: change onclick="changeThis(this)" to onclick="changeThis.call(this)"
pro: the code works, and you can use this in function context
contra: you use this in function context... there are only a few situation to do that. this is not such a situation. and again: inline-javascript
Third solution: don't use onclick.
<tr>
<td width="37" align="left"></td>
<td width="200" align="left">
<input type="submit" name="s1" value="Update Color" id="s1" class="btn-blue">
<input name="info1" type="text" maxlength="6" id="info1" style="color:Red;background-color:#FFFFFF;font-weight:normal;width:90px;">
</td>
<td width="340" align="center">
<input name="extra1" type="text" maxlength="200" id="extra1" style="width:330px;">
</td>
<td class="hide"></td>
</tr>
$('input:submit[name="s1"]/* or a different selector... depends on your logic */').click(changeThis);
you should use the third one.

how to traverse the element in <tr>

html:
<tr id="head-58">
<td style="width:150px;">
<input type="button" name="delete" class="delete_person" value="58" />name<button type="button" style="margin: 1px 35px 5px;" name="delete" value="58" class="delete_icon button_style">Delete</button>
</td>
<td>
<input type="checkbox" name="first_aid" id="id_first_aid" />FirstAid
</td>
<td>
<input type="checkbox" name="sick_bay" id="id_sick_bay" /Sick bay
</td>
<td>
<input type="checkbox" name="ambulance" id="id_ambulance" />Ambulance
</td>
</tr>
Here onclicking the delete_person class,i want to show the hidden button with class delete_icon.Since class delete_icon can have more than one,i need to show the hidden button form clicked element.I tried with $this.closest('tr').find(".delete_icon").toggle(); which is not working.
Use:
$this.parents('tr').find(".delete_icon").toggle();
Your delete button is not a child of tr. Move it into tr, or use:
$(this).closest('tr').next('.delete_icon')
There is no $this variable unless you create it yourself. this refers to the target of the event, so use it in the jQuery function to create a jQuery object containing it:
$(this).closest('tr').find(".delete_icon").toggle();
However, you also need to move the button inside the table row for that to work. Now it looks like it's inside the table but outside any table cell, which is invalid HTML. (Some browsers may put it inside some table cell, other may move it outside the table entirely. The result is unpredictable, so unless you move the button inside a cell, it's not possible to write code that accesses it.)
Since the button is after the <tr>...</tr>
Use:
$(this).parent().next().toggle()

Jquery row selecting in a button onClick

I have a table (id of the table is county_table) with plenty of lines like this:
<tr>
<td><input class="text" type=text name=param1 maxlength=2 size=2></td>
<td><select class="text" name=param2><option value=1>Live<option value=2>Test</select></td>
<td><input class="text" type=text name=param3 ></td>
<td><input class="text" type=text name=param4 ></td>
<td><input class="text" type=text name=param5 ></td>
<td><input class="text" type=text name=param6 ></td>
<td colspan=2><input class="button" type=submit value=New onclick="function_new($('#county_table tr:eq(1)'))"></td>
</tr>
The onclick function would manage the table data, and maybe send an AJAX, so I need to get the all elements of the table.
The bad thing with that solution is that if I insert a new row the whole table row selection would be messed up, so I'd like to change the tr:eq(1), something like this.tr or something like that, is the button know his ancestor and get the given object?
I would appreciate any help.
You can use closest() to get the parent tr of the button being clicked.
var trOfButton = $(this).closest('tr');
Description of closest: For each element in the set, get the first
element that matches the selector by testing the element itself and
traversing up through its ancestors in the DOM tree, Reference.
I would recommend you to use $(this).parent().parent() for a better performance.
http://jsperf.com/parentparentvsclosest/2
But if you are looking for code simplicity, then you could go for $(this).closest('tr').
You can use:
- $(this).closest('tr');
OR
- $(this).parent().parent();
.closest() will give you closest tr to the button and .parent() will return parent element(td) and again it's parent will return that row

Removing duplicates and not valid entries from a select box, but not refreshing the whole box

I'm trying to write a web form, which will have selectable options based on users input from earlier in the form.
Where I'm getting stuck is;
I have a table room types, which is just td tags with input tags (type=text). These are filled in by a user, so I've no idea what they are..
I've got a button to add extra lines to this table (Jquery to add another td tag and input tag)
Users add as many lines as needed
The next part of the form is to fill in Rooms, and select the type for each room. The table layout is the same (except there are two columns, rather than one), and extra lines are added via another button with Jquery.
What I'd like to be able to do, is for new lines added to have two columns in the table. One input text field, and the other a select box with options taken from the table above.
I've managed to get this working to a point. But as users may go back to edit options from the original (room types) table, I need the select boxes to adjust their values based on what the original table currently says.
I can get this working by emptying and re-populating my select boxes everytime one of the input fields accessed (using OnBlur, which is probably not the most effective way to do this), but since it removes entries from the bxes, and then re-populates, any of the select boxes that have been populated already get reset. I only want invalid options (i.e. values that do not exist in the original table) to be reset.
I've been looking/playing at this for a long time now, but my programming abilities are only what I've taught from here and google, whilst messing around on a few very small things before...
My HTML code as it stands (well, part of my code, I've removed all the irrelevant code to keep it simple) is here:
<div id="rm_types_info">
<table id="room_types_table">
<tr>
<td><input type="text" class="room_types" onblur="edit_rooms_select();" /></td>
</tr>
</table>
<button type="button" onclick="rmtypes('room_types_table');">Add Another Room Type</button>
</div>
<div id="rooms_info">
<table id="rooms_table">
<tr>
<th>Room Number</th>
<th>Room Type</th>
</tr>
<tr>
<td><input type="text" /></td>
<td>
<select class="room_type_select">
<option value="Please Choose">Please Choose</option>
</select>
</td>
</tr>
</table>
<button type="button" onclick="rooms('rooms_table');">Add Another Room</button>
</div>
and my JQuery is;
<script>
var userscounter=2
var rmtypescounter=1
var roomscounter=2
function users(ID){
document.getElementById(ID).insertRow(userscounter).innerHTML = '<td><input type="text" /></td><td><input type="text" /></td>';
userscounter++;
};
function rmtypes(ID){
document.getElementById(ID).insertRow(rmtypescounter).innerHTML = '<td><input type="text" class="room_types" onblur="edit_rooms_select();" /></td>';
rmtypescounter++;
}
function rooms(ID){
document.getElementById(ID).insertRow(roomscounter).innerHTML = '<td><input type="text" /></td><select class="room_type_select"><option value="Please Choose">Please Choose</option></select></td>';
roomscounter++;
};
function edit_rooms_select(){
var roomtypelist = $('.room_type_select');
roomtypelist.empty()
$('#room_types_table tr td input').each(function(){
var text = $(this).val();
roomtypelist.append('<option value='+text+'>'+text+'</option>');
});
}
</script>
I've removed the Jquery that was removing the duplicates, since it was definately not working how it needs to...
I'm aware that I may be going about this completely the wrong way, and if using td tags or inputs etc is completely wrong, I'm happy to change the whole form it necessary.
I'm sure this isn't the most effective way to do what I need, but this is how I managed to get it to work...
My HTML...
<div id="rm_types_info">
<table id="room_types_table">
<tr>
<td><input type="text" name="2" class="room_types" onblur="edit_rooms_select();" /></td>
</tr>
</table>
<button type="button" onclick="rmtypes('room_types_table');">Add Another Room Type</button>
</div>
<div id="rooms_info">
<table id="rooms_table">
<tr>
<th>Room Number</th>
<th>Room Type</th>
</tr>
<tr>
<td><input type="text" /></td>
<td>
<select class="room_type_select" id="room_type_select1" >
<option value="1">Please Choose</option>
</select>
</td>
</tr>
</table>
<button type="button" onclick="rooms('rooms_table');edit_rooms_select();">Add Another Room</button>
</div>
And the JQuery scripts relevant. In particular, it was the final function "edit_rooms_select()", and specifically the "Add new options to each select" that I was struggling with.
<script>
var rmtypescount=3;
var room_type_select_count=2;
function rmtypes(){
$('#room_types_table tr:last').after('<tr><td><input type="text" name='+rmtypescount+' class="room_types" onblur="edit_rooms_select();" /></td></tr>');
rmtypescount++;
};
function rooms(){
$('#rooms_table tr:last').after('<tr><td><input type="text" /></td><td><select id="room_type_select'+room_type_select_count+'" class="room_type_select"><option value="1">Please Choose</option></select></td></tr>');
room_type_select_count++
};
function edit_rooms_select(){
$('#room_types_table tr td input').each(function(){
var name = $(this).attr('name');
var value = $(this).val();
//Add New Options to each select
$('#rooms_table select').each(function(){
var last = $(this).children('option:last').val();
if (name > last) {
$(this).append('<option value="'+name+'">'+value+'</option>');
};
});
//Change any room types that have been edited
$('.room_type_select option').each(function(){
var match = $(this).val();
if(name == match){
$(this).text(value)
};
});
//Remove Blank Entries
if(value == ''){
$('.room_type_select option[value='+name+']').remove();
};
});
};
</script>
I think that the edit_rooms_select function is much more expensive than it needs to be. For what I require, this isn't going to be a problem, but I would be very interested to see how other people suggest the lists are edited, following my requirements..
- All user inputs from the room_types_table must be options in the select boxes in the rooms_table
- Any input changed in the room_types_table must have its relevant option in the select boxes changed to match
- Any input that is left blank (or later deleted) from the room_types_table must be removed from the select boxes
- Any select box that has a selection which is then removed from the room_types_table must be reset back to its original "Please Choose" option.
If anyone can suggest better ways to do this, or can tidy my code in any way, I'd like to see the code, and also have it explained, as I'm very inexperienced with Javascript/Jquery.

JavaScript DOM insertBefore isn't working properly

It's my first question here, so pardon me for my mistakes if any.
I am trying to add rows to a table through JavaScript. The newly added row is to be added at the second-last position, the last row contains the button that creates new row. The last row has id "submitrow", but getting that element and passing it to insertBefore is somehow not working. passing lastChild as 2nd param to insertBefore also behaves odd.
In the body, this is the form:
<form>
<input type="hidden" name="submit_done" value="true" />
<table id="formtable">
<tr>
<td>Number : </td>
<td><input type="text" name="num[]" /></td>
</tr>
<tr id="submitrow">
<td><input type="button" value="Add one more" onclick="addRow()" /></td>
<td><input type="submit" value="Go!" /></td>
</tr>
</table>
</form>
Here is JavaScript function:
function addRow(){
var new_tr = document.createElement('tr');
var new_td1 = document.createElement('td');
var new_td2 = document.createElement('td');
var new_input = document.createElement('input');
new_td1.innerHTML = 'Number : ';
new_input.type = 'text';
new_input.name = 'num[]';
new_td2.appendChild(new_input);
new_tr.appendChild(new_td2);
new_tr.insertBefore(new_td1, new_td2);
var formtable = document.getElementById('formtable');
var submitrow = document.getElementById('submitrow');
submitrow.style.backgroundColor='red'; /*Works fine, paints button row red*/
formtable.insertBefore(new_tr, submitrow); /*fails, invalid argument*/
}
Now, the problem is:
insertBefore fails on last line. Please note, that insertBefore has been tried on new_tr object as wel, and it works fine. So the only possibe invalid argument can be submitRow, shich is painted red successfully just one line above the failing statement.
If for the failing call, instead of submitrow, if formtable.lastChild is used, it runs. But then somehow that lastChild includes upper row too. That means, if I put say 4 more rows and enter 1, 2, 3, 4, 5 in the test inputs, and then if you hit "Add one more" button, now a row is added between 4 and 5!
I have tried a lot to reason it, but could get no logic behind either of the situation.
In hope of a solution, thanking you all,
Abhay Bhave, India
The title should be changed in "JavaScript DOM insertBefore isn't used properly".
That's because, even if you didn't put in your DOM, the browser automatically creates a <tbody> element that wraps the rows of the table. So, it happens that #formtable is not the parent of #submitrow, and that's why you get an error.
Try this:
formtable.tBodies[0].insertBefore(new_tr, submitrow);
Or, more generally:
submitrow.parentNode.insertBefore(new_tr, submitrow);
(In browsers that support it, there's even this one:
submitrow.insertAdjacentElement("beforeBegin", new_tr);
Internet Explorer, Chrome, Safari and Opera support it, Firefox doesn't but it can be easily shimmed. I don't recommend using this stuff, anyway.)
And, as a general advice, always use the <tbody> tag when writing down tables:
<table id="formtable">
<tbody>
<tr>
<td>Number : </td>
<td><input type="text" name="num[]" /></td>
</tr>
<tr id="submitrow">
<td><input type="button" value="Add one more" onclick="addRow()" /></td>
<td><input type="submit" value="Go!" /></td>
</tr>
</tbody>
</table>
And, of course, <thead> and <tfoot> when you need them.

Categories