Cloning tr to add new item and replacing a select box - javascript

I Had a code where i had to clone the respected tr and create the new one, but the tr has the column which has a select and that selection has one value which when chosen converts the select box into the textbox and then whe i click add item, it adds another text text, i knowwhy it is hapening, because i am just cloning it.
how can i fix it, i am bit confused
here is my code
<table>
<tr><td><input type="text"></td></tr>
<tr>
<td><div id="stlineitems">
<label for="stlineitems">Item(s)</label></td>
<td><div class="onlyleft">
<select name="get_Items" id="get_Items" class="selectItemsList" data-rule-required="true" data-msg-required="Choose Item">
<option></option>
</select>
</div>
<div class="moveboxleft">
<select name="getSelection" class="form-control getSelectedprice">
<optgroup label="Class Price">
<option value="160.0000">$160.00</option>
</optgroup>
<optgroup label="Custom Price">
<option value="0">$0</option>
<option value="-2">My Price</option>
<option value="-1">Custom Price</option>
</optgroup>
</select>
</div><div class="moveboxleftinput" style="display:none;">
<input type="text" name="getSelection" value="" class="form-control">
</div>
<br/>
<div class="nextitem">Add Item</div></td>
</div>
</tr>
</table>
$('.createNewItemTag').click(function(){
var obj = $(this).parents('tr').first();
var clonedObj = $(obj[0].outerHTML);
clonedObj.find(".select2-container").remove();
clonedObj.find('.createNewItemTag').remove();
clonedObj.find('td').last().append("<a class='removeItem' href='javascript:void(0);'>Remove</a>");
clonedObj.find(".removeItem").click(function(){
$(this).parents('tr').first().remove();
});
obj.before(clonedObj);
initSelect2ForNextItem(clonedObj.find(".selectItemsList").first());
});
$(document).on('change','.getSelectedprice',function() {
if ($('.getSelectedprice option:selected').text() == "Custom Price"){
$('.moveboxleft').hide();
$('.moveboxleftinput').show();
}else {
$('.moveboxleft').show();
$('.moveboxleftinput').hide();
}
});

You do have some improperly nested HTML that should be fixed.
But as for the cloning. My advice is to never clone an item after it has been instrumented with any event handlers or other plugins (like Select2). The way to avoid that is to do the following:
Clone the row right away at page load (before registering event handlers and instrumenting).
Whenever you need a new row, clone the original clone. That way you still have the original clone to re-clone over and over.
Use event delegation as much as possible to register event handlers.
If you need to instrument any of the elements on a newly added row, do it after you have inserted it into the page.
In your case, you could have this:
var $table = $('table');
var $CLONED_ROW = $table.find('tbody>tr:first').clone();
$CLONED_ROW.find('.createNewItemTag').replaceWith(
'<a class="removeItem" href="#">Remove</a>');
$table.on('click', '.createNewItemTag', function(e) {
e.preventDefault();
var $row = $(this).closest('tr'),
$newRow = $CLONED_ROW.clone();
$newRow.insertBefore($row);
//initSelect2ForNextItem($newRow.find('.selectItemsList'));
});
$table.on('click', '.removeItem', function(e) {
e.preventDefault();
$(this).closest('tr').remove();
});
$table.on('change', '.getSelectedprice', function() {
var $select = $(this),
$row = $select.closest('tr');
if ($select.val() == '-1') {
$row.find('.moveboxleft').hide();
$row.find('.moveboxleftinput').show();
} else {
$row.find('.moveboxleft').show();
$row.find('.moveboxleftinput').hide();
}
});
//initSelect2ForNextItem($table.find('.selectItemsList'));
Notice the placement of the calls to initSelect2ForNextItem().
jsfiddle
A few more things:
You can use .closest(), instead of .parents().first().
When you hide/show the text input, you need to limit it to the current row.
It is better to use the value of a select element, rather than the text.

Your HTML is invalid. For example, you haven't closed the first div in your first td tag:
<tr>
<td>
<div id="stlineitems">
<label for="stlineitems">Item(s)</label>
<!-- Close div should go here -->
</td>
Try correcting your HTML and re-evaluate your code, then resubmit if you are still having problems.

Related

How do you get chosen.js to use javascript generated cloned content?

I am using chosen.js version 1.8.7
I am able to clone the content of a div to another div with all of the data and events using clone(true).I have changed all of the ID's to have a new ID on the cloned items.
The problem is when I select a javascript generated select list, it activates the original select list and not itself.
I have tried cloning without all of the data and events by using clone(). It clones but it doesn't allow the newly generated <select> to drop-down at all.
I have removed chosen.js and the clone(true) copies everything and each <select> list works individually but there is no filter capability.
<form method="post" name="add_items">
<div class="clone-test" id="cloned">
<select id="items1" name="contract_item[]" class="form-control chosen-select" data-placeholder="Choose a item...">
<option value="0">Select a Item</option>
<option value="1">Car 1</option>
<option value="2">Car 2</option>
<option value="3">Car 3</option>
</select>
</div>
<div class="col-md-6" id="new_items"></div>
</form>
<input type="button" onclick="clone_div()" name="add" value="Add Another Item" class="btn btn-primary" id="add_select">
<script type="text/javascript">
var regex = /^(.+?)(\d+)$/i;
var cloneIndex = $("#cloned").length;
function clone_div(){
$("#cloned").clone(true)
.appendTo("#new_items")
.attr("id", "cloned" + cloneIndex)
.find("*")
.each(function() {
var id = this.id || "";
var match = id.match(regex) || [];
if (match.length == 3) {
this.id = match[1] + (cloneIndex);
}
})
cloneIndex++;
$("#new_items").html(html);
$(".chosen-select").chosen();
}
</script>
I expect to have each individual <select> list to work independently having each list with filter capability using chosen.js. What I am getting is having the original select list activate no matter which javascript generated <select> list I choose.

duplicate drop-downs on button click

Currently I have this setting.
My page loads with 2 drop-downs aligned adjacent and an ADD button.
The ADD button adds a drop-down in the next row using the function addRow().
The function is probably the worst implementation though.
a) I want ADD button to add 2 similar drop-downs aligned adjacent as in the page initially, to the next row. (right now the code only adds 1 drop-down in the next row)
b) is there any way I can put my ADD button to be below the drop-downs I have instead of being next to the first row of drop-downs?
Below is the code
<div class="container">
<table>
<tr>
<td>
<select id="soflow">
<!-- This method is nice because it doesn't require extra div tags, but it also doesn't retain the style across all browsers. -->
<option>Select an Option</option>
<option>Option 1</option>
<option>Option 2</option>
</select>
<select id="soflow">
<!-- This method is nice because it doesn't require extra div tags, but it also doesn't retain the style across all browsers. -->
<option>Select an Option</option>
<option>Option 1</option>
<option>Option 2</option>
</select>
<button class = "button" type="button" onClick ="addRow(this)">Add</button></td>
</tr>
</table>
</div>
<script>
function addRow(btn) {
var parentRow = btn.parentNode.parentNode;
var table = parentRow.parentNode;
var rowCount = table.rows.length;
var row = table.insertRow(rowCount);
var cell1 = row.insertCell(0);
//var element2 = document.createElement("input");
var element2 = document.createElement("select");
element2.setAttribute("id", "soflow")
//element2.type = "select";
var option1 = document.createElement("option");
option1.innerHTML = "Option1";
option1.value = "1";
element2.add(option1, null);
var option2 = document.createElement("option");
option2.innerHTML = "Option2";
option2.value = "2";
element2.add(option2, null);
cell1.appendChild(element2);
}
</script>
Thank you for any help.
Give id to your <tr> to be cloned and to the table. Then use cloneNode() to clone the row and append it to the table.
<div class="container">
<table id="myTable">
<tr id="initialRow" class="select_row">
<td>
<select id="soflow" class="select1">
<!-- This method is nice because it doesn't require extra div tags, but it also doesn't retain the style across all browsers. -->
<option>Select an Option</option>
<option>Option 1</option>
<option>Option 2</option>
</select>
<select id="soflow" class="select2">
<!-- This method is nice because it doesn't require extra div tags, but it also doesn't retain the style across all browsers. -->
<option>Select an Option</option>
<option>Option 1</option>
<option>Option 2</option>
</select>
</td>
</tr>
</table>
<button class = "button" type="button" onClick ="addRow()">Add</button>
<button class = "button" type="button" onClick ="getValues()">Print values</button>
</div>
<script>
const table = document.querySelector('#myTable');
const rowToDuplicate = document.querySelector('#initialRow');
function addRow() {
var duplicate = rowToDuplicate.cloneNode(true);
duplicate.removeAttribute('id'); table.appendChild(duplicate);
}
function getValues() {
const rows = document.querySelectorAll('.select_row');
rows.forEach((row, i) => {
console.log(`row ${i}: select1 `, row.querySelector('.select1').value); console.log(`row ${i}: select2 `,row.querySelector('.select2').value);
})
}
</script>
You have two IDs which have the same name. Change the ID property to have different names for both select elements like <select id="soflow1"> && <select id="soflow2"> and refer to each element as soflow1 or soflow2 in your Javascript. Your JavaScript is referencing two ID elements and causing two dropdowns to open with one call.
IDs should be unique to only one element.
To use the same style across those dropdown elements add a class property which is the same to both select elements like <select id="soflow1" class="myDropdownClass"> && <select id="soflow2" class="myDropdownClass"> and create CSS for .myDropdownClass { //some style }
To put the button underneath the select elements you could do this in your table...
<table>
<tr>
<td><select id="soflow1" class="myDropdownClass" ... /></td>
<td><select id="soflow2" class="myDropdownClass" ... /></td>
</tr>
<tr>
<td colspan="2"><button>text</button></td>
</tr>
</table>
I like to add the event listener to the table since the click will bubble up the dom tree. Then check to see that it was an element with the class "add" that called the event. If it is then clone the row node of the table and append it to the table body. I also placed the button in the table footer so it always stays at the bottom. Hope this helps.
This method also allows you to change the structure of the table without having to rewrite the javascript to correctly climb the dom tree. Added a remove row button just for S&G.
In similar fashion to get the values without having ids on every select element you could use the elements index from a list of solflow elements as a unique identifier and the value.
Since you are creating dynamic elements by cloning the row, either the event listeners for the solflow need to be added to the new select elements or the table can handle the change event in which case you add the change handler once and the solflow change bubbles up no matter when the element was added. In similar fashion a submit button can be created with the table click handler grabbing all the values from the solflow elements in the table and indexing them to the number of solflow elements as either a key value store or as an array of solflow values matching the order in which the elements appear.
<table>
<tbody>
<tr>
<td>
<select class="solflow">
<option>Select an Option</option>
<option>Option 1</option>
<option>Option 2</option>
</select>
<select class="solflow">
<option>Select an Option</option>
<option>Option 1</option>
<option>Option 2</option>
</select>
</tr>
</tbody>
<tfoot>
<tr>
<td>
<button class="button add" type="button">Add</button>
<button class="button remove" type="button">Remove</button>
</td>
</tr>
</tfoot>
</table>
<script>
function tableClickHandler(e) {
if (e.target.classList.contains('add')) {
let tbody = this.querySelector('tbody');
let row = tbody.querySelector('tr');
tbody.appendChild( row.cloneNode(true) );
}
if (e.target.classList.contains('remove')) {
var tbody = this.querySelector('tbody');
var row = tbody.querySelectorAll('tr');
if (row.length > 1) {
tbody.removeChild(row[row.length-1]);
}
}
}
function tableChangeHandler(e) {
if (e.target.classList.contains('solflow')) {
let solflows = this.querySelectorAll('.solflow');
let solflow = e.target;
let index = -1;
solflows.forEach(function(el, ind){
if (el === solflow) { index = ind }
});
console.log(index, solflow.value);
}
}
document.querySelector('table').addEventListener('click', tableClickHandler);
document.querySelector('table').addEventListener('change', tableChangeHandler);
</script>
You can use a for loop to loop twice and create two selects. You should move the button outside of the table if you want it to always be under the selects (both added and initial ones) while adding new rows to the table for the selects.
Also, you can not have more than one element with one id. You initially have 2 elements with the id "soflow" and are going to add more when the Add button is clicked.
To count how many selects have been added, you just need a global variable that increase by one each time the for loop inside the function is run.
<div class="container">
<table id="selectTable">
<tr>
<td>
<select id="soflow">
<!-- This method is nice because it doesn't require extra div tags, but it also doesn't retain the style across all browsers. -->
<option>Select an Option</option>
<option>Option 1</option>
<option>Option 2</option>
</select>
<select id="soflow2">
<!-- This method is nice because it doesn't require extra div tags, but it also doesn't retain the style across all browsers. -->
<option>Select an Option</option>
<option>Option 1</option>
<option>Option 2</option>
</select>
<br/>
</td>
</tr>
</table>
<button class = "button" type="button" onClick ="addRow(this)">Add</button>
</div>
<script>
var addedSelects = 0;//total number of dropdowns added
function addRow(btn) {
var table = document.getElementById('selectTable');
var soflow = document.getElementById("soflow2");
var rowCount = table.rows.length;
var row = document.createElement('tr');
table.appendChild(row);
//var element2 = document.createElement("input");
var td = document.createElement('td');
row.appendChild(td);
for(let i = 0; i < 2; i++){
var element2 = document.createElement("select");
//element2.setAttribute("id", "soflow"+(i+1))
//element2.type = "select";
var option1 = document.createElement("option");
option1.innerHTML = "Option1";
option1.value = "1";
element2.add(option1, null);
var option2 = document.createElement("option");
option2.innerHTML = "Option2";
option2.value = "2";
element2.add(option2, null);
td.appendChild(element2);
addedSelects++;
}
}
</script>
This should do the trick
function addRow() {
//Select the table
var table = document.getElementsByTagName('table')[0];
//Append a row
table.innerHTML = table.innerHTML + '<tr>\
<td>\
<select>\
<option>Select an Option</option>\
<option>Option 1</option>\
<option>Option 2</option>\
</select>\
<select>\
<option>Select an Option</option>\
<option>Option 1</option>\
<option>Option 2</option>\
</select>\
</td>\
</tr>';
}
<div class="container">
<table>
<tr>
<td>
<select>
<!-- This method is nice because it doesn't require extra div tags, but it also doesn't retain the style across all browsers. -->
<option>Select an Option</option>
<option>Option 1</option>
<option>Option 2</option>
</select>
<select>
<!-- This method is nice because it doesn't require extra div tags, but it also doesn't retain the style across all browsers. -->
<option>Select an Option</option>
<option>Option 1</option>
<option>Option 2</option>
</select>
</td>
</tr>
</table>
<button class = "button" type="button" onClick ="addRow()">Add</button>
</div>
The ADD button always stays at the bottom because I moved it out of the table. I removed the id on the select tags, duplicate ids will give you errors, try using document.getElementsByTagName('select')[x] selector and use 0 (where x) to get the first drop down, 1 to get the second... I also just used text instead of creating the elements via JS because their much easier to read, create, and modify in my opinion. If you have any questions just ask.

Jquery how to display a specific input value with in a table

I am using a loop to display data in table and I would like a way to extract two elements specific to which dropdown option the user is clicking on. Firstly I would like to get the text value from within the selected tags. Secondly I would like to get the accompanying url which is the value of the hidden input field (#"lead_path").
Here is my table below. For example I would like a way to save both "/leads/50" and "Agent 456" into separate variables if a user clicked on this dropdown option. For brevity only the first table row in the loop is displayed, but each table row looks exactly the same as the one below.
<td>
Mellie Price IV</td>
<p><input type="hidden" name="lead_path" id="lead_path" value="/leads/50" /></p>
<td>12:24 am 03-09-2015</td>
<td>
<strong>Count:</strong> 0<br />
<strong>Most recent:</strong> $100,000+, Hamillburgh
</td>
<td> 9:24 am 03-16-2015</td>
<input type="hidden" name="agent_id" id="agent_id" value="6" />
<td><select name="agent[lead]" id="agent_lead">
<option value="1">Jeff Manson</option>
<option value="2">Kevin McCarthy</option>
<option value="3">Warsama Gabriel</option>
<option value="4">Chris Sass</option>
<option value="5">Agent123</option>
<option selected="selected" value="6">Agent456</option>
<option value="7">Agent789</option></select>
</td>
</td>
Here is my effort to try to solve this problem. My code gets me the text of the selected option but only displays the first url "/leads/50" and not any of the other ones. Any help would be greatly appreciated. Thanks!
$(document).ready(function() {
$("table").delegate("#agent_lead", "change", function(){
var agent_name = $("option:selected", this).text();
alert($('#lead_path').val());
});
Since you have the same elements in each tr, you should not use IDs like that since ID of an element must be unique, use class to select them.
So remove the id and assign the id values as class then, you need to find the tr of the changed agent_lead and find the lead_path inside it
<input type="hidden" name="lead_path" class="lead_path" value="/leads/50" />
<select name="agent[lead]" class="agent_lead">
then
$("table").delegate(".agent_lead", "change", function () {
var agent_name = $("option:selected", this).text();
alert($(this).closest('tr').find('.lead_path').val());
});
Also it looks like the hidden input is not inside a td, so move it inside the first td
<td>
Mellie Price IV
<input type="hidden" name="lead_path" id="lead_path" value="/leads/50" />
</td>
How about the following:
$(document).ready(function () {
$("#agent_lead").on('change',function (event) {
// var id = this.val();
var elem = $('#agent_lead option:selected');
alert(elem.val() + '/' + elem.text()+" "+$('#lead_path').val());
});
});
Here is the jsfiddle https://jsfiddle.net/oqjvw25n/1/

jQuery - order html table rows dynamically, not using ui-sortable

I'm trying to make a controllable html table list.
My List is like that:
<table>
<tr id="selection_18">
<td>
<select id="colors_18">
<option value="0">All</option>
<option value="1">Red</option>
<option value="2">Yellow</option>
</select>
</td>
</tr>
<tr id="selection_27">
<td>
<select id="colors_27">
<option value="0">All</option>
<option value="1">Red</option>
<option value="2">Yellow</option>
</select>
</td>
</tr>
<tr id="selection_5">
<td>
<select id="colors_5">
<option value="0">All</option>
<option value="1">Red</option>
<option value="2">Yellow</option>
</select>
</td>
</tr>
<tr>
<td>
<button onclick="orderRows();" />
</td>
</tr>
</table>
Scenario is like that: user select all colors for example;
for first row he selected red, for second row he selected yellow, for third row he selected again red, ... and for ninetieth row he selected yellow.
And user wants to order all rows by color again to see for example which color is selected how many times.
What should i write in javascript function orderRows(). I can use jQuery but not want to use jQuery UI sortable. Because in some of my list, it has 400 rows. I think it would be not good solution.
You can use this;
$("#order").on("click", function() {
$('tr').sort(function(a, b){
return $(a).find("option:selected").text() > $(b).find("option:selected").text();
}).appendTo('table')
});
$("#order").appendTo("table"); // this is for keep button place
Here is a working demo: jsfiddle
In demo, you can select colors, and click order button. After order, you can select your colors again and click order to shuffle.
Note: a, and b in function refers to specific two elements n and n+1 for each iteration. It means, it is comparing nth and (n+1)th element for each iteration. If n > n+1 element, n remains same, if not, n+1 moves place before n
The function below will build a hashmap that groups the IDs of the select elements based on the color selected. You could use that hashmap to render the table however you would like to.
See the working demo at:
JSFiddle
JS:
function orderRows(){
var colorArray = [ 'All', 'Red', 'Yellow' ];
var colorMap = {};
$('table select').each(function(){
var color = colorArray[$(this).val()];
if( colorMap[color] == undefined ){
colorMap[color] = [];
}
colorMap[color].push($(this).attr('id'));
});
$('div#display').html(JSON.stringify(colorMap));
}
HTML added (notice that the button was pulled out of the table):
<div>
<button onclick="orderRows()">orderRows</button>
</div>
<div id="display">
</div>
JSON displayed example:
{"Red":["colors_18","colors_5"],"Yellow":["colors_27"]}

How to add and remove the class of the select input using Jquery addClass( )?

I am using Uniform JS plugin for the form inputs. in the below code, i was trying to initialize the uniformjs styles in the dynamically created fields also.
In the below html code, there is a function called ext() which inserts a new row when the add button is clicked. I want the uniformjs style to get applied to those dynamically generated fields too. I tried and tried but its getting worst and its getting collapsed and the select boxes are not at all showing the selected value even after selecting ... :(
HTML
<table style="width:100%;border:1px solid;" id="table1">
<tr><td>
<select>
<option>Through Google</option>
<option>Through Twitter</option>
<option>Other…</option>
<option><Hi></option>
</select>
</td>
<td><button onClick="ext();">Add</button></td>
</tr>
</table>
JS
$(function()
{
$("input, textarea, select, button").uniform();
});
function ext()
{
$(function()
{
$("input, textarea, select, button").uniform();
});
rl = document.getElementById("table1").rows.length;
var a = document.getElementById("table1").insertRow(rl);
var b = a.insertCell(0);
b.innerHTML = '<div style="width:95%;margin-bottom:0px;padding:5px;"><div class="selector" id="uniform-clinic_visit"><span style="-moz-user-select: none;">Monthly</span><select name="clinic_visit[]" id="clinic_visit" onChange=""> <option>-Select-</option><option value="Weekly">Weekly</option> <option value="Monthly">Monthly</option></select></div></div>';
}
Resource - www.uniformjs.com
instead of "input, textarea, select, button" you can just use ":input" it covers all the input type elements.
please try something like below :
$(function(){
$(":input").uniform();
});
function ext()
{
rl=document.getElementById("table1").rows.length;
var a=document.getElementById("table1").insertRow(rl);
var b=a.insertCell(0);
b.innerHTML='<div style="width:95%;margin-bottom:0px;padding:5px;"><div class="selector" id="uniform-clinic_visit"><span style="-moz-user-select: none;">Monthly</span><select name="clinic_visit[]" id="clinic_visit" onChange=""> <option>-Select-</option><option value="Weekly">Weekly</option> <option value="Monthly">Monthly</option></select></div></div>';
$(function(){
$(":input").uniform();
});
}
Try this:
function ext()
{
$("#table1").append('<tr><td><div style="width:95%;margin-bottom:0px;padding:5px;"><div class="selector" id="uniform-clinic_visit"><span style="-moz-user-select: none;">Monthly</span><select name="clinic_visit[]" id="clinic_visit" onChange=""> <option>-Select-</option><option value="Weekly">Weekly</option> <option value="Monthly">Monthly</option></select></div></div></td></tr>');
$(":input").uniform();
}
I don't know how Uniform works, so just a guess: within your ext() function, move the following code:
$("input, textarea, select, button").uniform();
to be the last line of the function. That is, call .uniform() after you create the new elements. (Obviously I'm assuming here that it is the call to .uniform() that applies the styles you are talking about.)
Note also that within your ext() function you currently surround the above line with a document ready function and you don't need to do that.

Categories

Resources