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.
Related
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.
Is there any way to find the text content of a td and then make that text the first line or option in a select drop down?
<table class="options">
<tbody>
<tr>
<td><b>Colour:</b></td>
<td>
<select>
<option selected="" value="">Select:</option>
<option value="1">Black</option>
<option value="2">White</option>
</select>
</td>
</tr>
</tbody>
</table>
The first td content (Colour:) needs to go in place of the first option (Select:), basically. I don't have full control over the select list myself so I'm having to try doing this dynamically. Trying to save on space. Ideally I'd like to remove the td as well after moving the content.
Just get the caption from the previous cell and put it to the first option. Check it out here: https://jsfiddle.net/w07vg0ef/
Try this:
// do for all selects on the page
$('select').each(function (index, element) {
// store the select
var select = $(element)
// get the caption from the previous cell
var caption = select.parent().prev('td').text()
// put the caption to the first option
select.find('option').first().html(caption)
})
$('select').prepend('<option selected=selected>'+$('select').closest('tr').find('td:nth-child(1)').text()+'</option>');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="options">
<tbody>
<tr>
<td><b>Colour:</b>
</td>
<td>
<select>
<option selected="" value="">Select:</option>
<option value="1">Black</option>
<option value="2">White</option>
</select>
</td>
</tr>
</tbody>
</table>
try this
If you're looking to do it only by JavaScript then take a look at this:
Add option as the first value but as a new value:
var getColor = document.getElementsByTagName("td")[0];
var selectedColor = getColor.getElementsByTagName("b")[0].innerHTML;
var select = document.getElementsByTagName("select")[0];
var option = document.createElement("option");
option.text = selectedColor;
select.add(option, select[0]);
<table class="options">
<tbody>
<tr>
<td><b>Color:</b></td>
<td>
<select>
<option selected="" value="">Select:</option>
<option value="1">Black</option>
<option value="2">White</option>
</select>
</td>
</tr>
</tbody>
</table>
Add option as a replace value of the current first value:
var getColor = document.getElementsByTagName("td")[0];
var selectedColor = getColor.getElementsByTagName("b")[0].innerHTML;
var select = document.getElementsByTagName("select")[0];
var option = select.options[0];
option.innerHTML = selectedColor;
<table class="options">
<tbody>
<tr>
<td><b>Color:</b></td>
<td>
<select>
<option selected="" value="">Select:</option>
<option value="1">Black</option>
<option value="2">White</option>
</select>
</td>
</tr>
</tbody>
</table>
Here's a quick pure javascript solution. If possible, I would add a class to the TD so you could target it better or something like that.
var firstTD = document.getElementsByClassName('options')[0].getElementsByTagName('td')[0];
var text = firstTD.innerHTML;
var selectBox = document.getElementsByTagName('select')[0];
var option = document.createElement('option');
option.setAttribute('value', '');
option.innerHTML = text;
selectBoxFirstChild = document.getElementsByTagName('select')[0].children[0];
selectBox.insertBefore(option, selectBoxFirstChild);
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.
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"]}
I'll try to explain the problem. I have this select in html:
<select id="seasons" multiple="multiple">
<option value="s01">Stagione 1</option>
<option value="s02">Stagione 2</option>
<option value="s03">Stagione 3</option>
<option value="s04">Stagione 4</option>
<option value="s08">Stagione 8</option>
</select>
So as you can see it's a multiple select. Now I have to check wich is selected and display only the selected item while, those not selected, must be hidden.
The element that I have to show or hide, has a class equal to the value of these option (the element it's a table):
<table class="s01">
...
</table>
.val() method for multiple select elements returns an array of the selected values, you can .join() the values and filter the tables using the generated selector.
$('#seasons').on('change', function() {
var selector = this.selectedIndex > -1 ? '.' + $(this).val().join(',.') : null;
$('table').hide().filter(selector).show();
});
http://jsfiddle.net/Frm5a/
try this
$(function(){
$('table').hide(); //<--this hides all the table
$('#seasons').change(function(){
$.each($(this).val(),function(i,v){
$('.'+v).show();
}
});
});
since, $('table').hide(); hides all the table present in the document... you can add same class to specific tables that you want to hide and use class selector $('.tableClass').hide()..
You can add a class s to all the target elements along with the sxx class then
<table class="s s02">
<tr>
<td>01</td>
</tr>
</table>
then
var $els = $('.s').hide();
$('#seasons').change(function () {
var selected = $(this).val(),
$sel;
if (selected && selected.length > 0) {
$sel = $els.filter('.' + selected.join(', .')).show();
$els.not($sel).hide();
} else {
$els.hide();
}
})
Demo: Fiddle