Select Element doesn't work after clone - javascript

Hi! Guys I know nothing when it comes to JQuery... Please help me with this.
I created bootstrap form with a button add another field if the user want additional input fields. The new field are cloned from the original field.
The date-picker didn't work at first (on cloned field) so I add code to solve that.. (which I was luck to do and it took me 7hrs to get it correct)..
but then I found out even the cloned select box aren't working also.
-> Since the selector was using ID (#e1), I thought that was a reason so I changed it to class (.e1). That didn't help.
->So I tried the same method (like how I did on date-picker) but it also failed..
Here is the Code:
-> At Page header
<script src="assets/js/jquery-2.0.3.min.js"></script>
<script>
function cloneRow()
{
var row = document.getElementById("rowToClone"); // find row to copy
var num = Math.floor((Math.random() * 500) + 1);
var table = document.getElementById("tableToModify"); // find table to append to
var clone = row.cloneNode(true); // copy children too
clone.id = "row" + num; // change id or other attributes/contents
table.appendChild(clone); // add new row to end of table
clone.querySelectorAll('[id="id-date-picker-1"]')[0].id = "id-date-picker-" + num; //Put Unique ID
//For Selector
$(function(){
$('.e1').select2();
$('.clone').click(function() {
var clone = $('.select2').clone();
var cloned = clone.find('.e1');
cloned.removeClass('select2').removeAttr('id');
clone.appendTo('.elements');
$(cloned).select2();
});
});
}
</script>
The Row to be cloned
<tbody id="rowToClone">
<tr>
<td>
<div class="form-group" style="width: 100%;">
<select class="e1" style="width:100%;">
<option value="AL" />Alabama
<option value="AK" />Alaska
<option value="AZ" />Arizona
</select>
</div>
</td>
<td>
<div class="form-group" style="width: 100%;">
<select class="e1" style="width:100%;">
<option value="VA" />Virginia
<option value="WA" />Washington
</select>
</div>
</td>
</tr>
-> The trigger button
<button type="button" onclick="cloneRow()" class="btn btn-default purple"><i class="fa fa-plus"></i> Add </button>
->Page Footer
//On Page Footer
//--Jquery Select2--
$(".e1").select2(); //I added this line
$("#e1").select2();
$("#e2").select2({
placeholder: "Select a State",
allowClear: true
});
-> Please help me.. I will appreciate.

A couple of problems (your HTML for the options is invalid), but a lot of plugins, that change the DOM, simply do not like to be cloned. They store instance information in element data and are often not re-entrant (cannot reapply the plugin to elements that already have the DOM changes).
As taking existing rows to clone can get messy, I would suggest a slightly different approach to the cloning, that will avoid these problems.
Simply keep a separate template row in your page, that you can clone, inside a dummy script block:
<script id="rowToClone" type="text/template">
<tr>
<td>
<div class="form-group" style="width: 100%;">
<select class="e1" style="width:100%;">
<option value="AL">Alabama</option>
<option value="AK">Alaska</option>
<option value="AZ">Arizona</option></select>
</div>
</td>
<td>
<div class="form-group" style="width: 100%;">
<select class="e1" style="width:100%;">
<option value="VA">Virginia</option>
<option value="WA">Washington</option></select>
</div>
</td>
<td>
<div class="form-group" style="width: 100%;">
<input type="text" class="datapicker"/>
</div>
</td>
</tr>
</script>
type="text/template" is unknown, so the script is ignored by all browsers.
Then the clone becomes as simple as:
$('#clonerow').click(function(){
$('#table tbody').append($('#rowToClone').html());
// now apply any plugins to the new row
});
JSFiddle: http://jsfiddle.net/TrueBlueAussie/j1smswmt/2/
Here is an expanded version with datepicker applied to each new row:
$('#clonerow').click(function(){
$('#table tbody').append($('#rowToClone').html()).find('tr:last .datapicker').datepicker();
});
JSFiddle: http://jsfiddle.net/TrueBlueAussie/j1smswmt/3/
Notes:
Your options are currently invalid. You need to enclose the text inside matching <option> & </option> tags.
As you are using jQuery avoid using inline onclick handlers. They separate the event registration from the event handler for no real benefit. Do it the jQuery way instead.

In case anyone still experience this issue but would still want to use the jQuery clone:
If you are using Bootstrap, you actually just need to remove the bootstrap-select and then reinitialise the normal cloned select.
Just add these two lines of code after you do your clone:
clone.find('.bootstrap-select').remove();
clone.find('select').selectpicker();
Based on answer from this Github issue: https://github.com/silviomoreto/bootstrap-select/issues/605

Related

Input fields are not showing when copy a table row using javascript

I am working with table where copy a table row using javascript issue is that when i click on add more button then copy a table row but input fields are not showing here is my code of table
<table class="striped display" cellspacing="0" width="100%" id="myTable">
<tbody>
<tr>
<td class="input-field col s2">
<label>Module</label>
<select data-rel="chosen" name="moduleid[]" class="form-control">
<?php
$RowRes=mysqli_query($con,"Select id, name from tbl_module where status=1 order by id asc");
while($URow=mysqli_fetch_array($RowRes)){
echo "<option value=".$URow[0].">".$URow[1]."</option>";}?>
</select>
</td>
<td class="input-field col s2">
<label>Week Days</label>
<select id="week_days" data-rel="chosen" name="week_days[]" class="form-control" multiple="multiple">
<option value="1">Monday</option>
<option value="2">Tuesday</option>
<option value="3">Wednesday</option>
<option value="4">Thursday</option>
<option value="5">Friday</option>
</select>
</td>
<td><button type="button" name="add" id="more_btn" class="btn right">Add More</button></td>
</tr>
</tbody>
and here is the javascript code where append a table row on button click
<script type="text/javascript">
$(document).ready(function() {
var i=1;
$('#more_btn').click(function() {
i++;
$('#myTable tbody').append('<tr id="row'+i+'"><td class="input-field col s2"><label>Module</label><select data-rel="chosen" name="moduleid[]" class="form-control"><?php$RowRes=mysqli_query($con,"Select id, name from tbl_module where status=1 order by id asc");while($URow=mysqli_fetch_array($RowRes)){echo "<option value=".$URow[0].">".$URow[1]."</option>";}?></select></td><td class="input-field col s2"><label>Week Days</label><select data-rel="chosen" name="week_days[]" class="form-control" multiple="multiple"><option value="1">Monday</option><option value="2">Tuesday</option><option value="3">Wednesday</option><option value="4">Thursday</option><option value="5">Friday</option></select></td><td><button type="button" name="remove" id="'+i+'" class="btn btn-danger btn_remove">X</button></td></tr>');
$('.btn_remove').click(function(){
var button_id = $(this).attr("id");
$('#row'+button_id+'').remove();
});
});
});
Here is the image of issue
see that first row of table input fields are working perfectly but second row of table that copy when click on Add More button input fields are not working
You can just use JQuery to achieve what you want with the clone method and remove the embeded PHP code.
A simple fiddle can be found here https://jsfiddle.net/xpvt214o/809590/ that merely updates the id of the main <tr> itself. But the code looks as follows:
$(document).ready(function() {
var i=1;
$('#more_btn').click(function() {
i++;
$clone = $('#first').clone(true);
$clone.attr('id', "row" + i);
$clone.find('.btn_remove').attr('data-remove-id', 'row'+i);
$('#myTable tbody').append($clone);
});
$('#myTable').on('click','.btn_remove',function(){
var button_id = $(this).data("remove-id");
$('#'+button_id+'').remove();
});
});
The only id i'm manipulating here is the id of the table row itself. But using jQuery selectors you can change the ids etc. of any of the cloned elements.
I do have a sneaky suspicion your current code won't work as expected, as even in your example all the form inputs have the same names (you only seem to be updating the id of the table row). You may want to make the form names themselves more dynamic by appending the i elsewhere. But that is obviously a different question.
You might also want to consider just having one "Add more" button at the bottom of all the forms, rather than duplicating that as they all have the same id as well. And you don't want to end up with any unintended consequences bearing in mind the click handler is associated with that element.
In your select the php code will not execute:
<select data-rel="chosen" name="moduleid[]" class="form-control"><?php$RowRes=mysqli_query($con,"Select id, name from tbl_module where status=1 order by id asc");while($URow=mysqli_fetch_array($RowRes)){echo "<option value=".$URow[0].">".$URow[1]."</option>";}?></select>
you need to make an api and get data from server.
On first load it works php executed on server and html response generated and that sent to browser. but by adding elements with javascript will not be able to execute php code.

How can i display data using Jquery append()

I've data
{product_name: "mushroom", id_p: 13, product_weight: "5", product_unit: "kg"}
How can I display product_weight after i select product name
<td class="col-md-7">
<select style="width:50%;" class="productcategory" id="prod_cat_id" name="id_c[]">
<option value="0" disabled="true" selected="true">category</option>
#foreach($category as $c)
<option value="{{$c->id_c}}" name="id_c" id="id_c">{{$c->category_name}}</option>
#endforeach
</select>
<select style="width:48%;" class="productname" name="id_p[]">
<option value="0" disabled="true" selected="true"> product</option>
</select>
</td>
<td class="col-md-1">
<div id="weights_wrapper" class="productweight" >
</div>
</td>
i want to output productweight in weight_warpper
for(var i=0;i<data.length;i++){
op+='<option value="'+data[i].id_p+'" name="id_p" data-product_weight="'+data[i].product_weight+'" data-product_unit="'+data[i].product_unit+'">'+data[i].product_name+'</option>';
}
$("select.productname").on("change",function(){
var weight = $(this).find(":selected").data("product_weight");
var unit = $(this).find(":selected").data("product_unit");
var span = "<span>"+weight+unit+"</span>";
$("#target_div_where_to_display_weight").html(span);
});
if I add new product my id weights_wrapper will change into weights_wrapper1 i want to output like not sure how to loop this
$("#target_div_where_to_display_weight '+ i +' ").html(span);
here is my append
$(document).ready(function() {
$('#add-form').click(function() {
i++;
$('#add-me').append(
+'<div id="weights_wrapper'+ i +'" class="productweight" name="product_weight">'
)};
I had an answer prepared based on the snips you put in the question, which was as simple as one change, but after looking at the full code, I see you are adding multiple whole rows of product selections, which each having their own weight display div.
A few things need to be changed, and tackled. The biggest problem you are facing is that you need to isolate your index used for each product row you are going to have on the page. Simply relying on the overused 'i' is causing you issues, since 'i' is not initially defined to cover the static html's elements, and its reused in for loops, and such. Gets confusing!
The first time the page is made (the first row, with the static html) should have an initial index set for the id's to use. Then when you add more whole rows, they continue the index value from there.
Static first row:
<tr>
<td class="col-md-7">
... snip ...
<select style="width:48%;" id="productname_1" id_index="1" class="productname" name="id_p[]">
<option value="0" disabled="true" selected="true"> product</option>
</select>
</td>
<td class="col-md-1">
<div id="weights_wrapper_1" class="productweight"></div>
</td>
</tr>
This would be considered row one, indexed to 1. Then when you add another whole row using the js, you need to first initialize that:
var id_i = 1;// 1 meaning one row already exists in the static html
Then follow with the other js output where you build another row, be sure to follow the same format as the initial static row (same id naming convention). Substituting "id_i" for the "1", so that it builds the html with "productname_2" and "weights_wrapper_2" etc.
$('#add-form').click(function() {
id_i++;// will change to '2' on first click
$('#add-me').append( ... the html build ... );
}
If you will spot further above in the "select" element, I added "id_index='#'", which can be used by jquery, to use the right index number to reference which one of the "weights_wrapper_#" you want to put the weight info span into:
$("select.productname").on("change",function(){
... snip ...
var id_index = $(this).attr("id_index");
$("#weights_wrapper_"+ id_index).html(span);
}

Concise way to highlight label when items in dropdown changes?

I want to highlight labels with a color when the associated dropdown value changes.
<tr>
<td>
<select id="first_dd" data-bind="value: first">
<option>cat</option>
<option>dog</option>
<option>squirrel</option>
<option>birds</option>
</select>
</td>
<td>
<label id="first_lb">
soft</label>
</td>
</tr>
<tr>
<td>
<select id="second_dd" data-bind="value: second">
<option>lion</option>
<option>elephant</option>
<option>kangaroo</option>
<option>buffalo</option>
</select>
</td>
<td>
<label id="second_lb">
dangerous</label>
</td>
</tr>
I want to change the color of the first_lb when the first_dd items changed by the user.
How could I accomplish this in JavaScript/jQuery with less code?
Any suggestions highly appreciated.
So, here goes "less code".
Add change event handler to the select.
Try this:
$("#first_dd").change(function(){
$("#first_lb").css('color',"yellow");
});
DEMO
EDIT:
As your question asked only for first_dd and first_lb so I added code only for that part. To apply this to all selects use jquery .each().
If, you adding elements dynamically then you must use on to bind events, else it is enough to use .change().
So as you mentioned your requirements, do this:
$('select').each(function(){ //for each select elements in document
$(this).on('change',function(){ //bind change event
var id = $(this).attr('id').replace('dd','lb'); //get id for label
$("#"+id).css("color","yellow"); //highlight
})
})
DEMO
Make use of for attribute to connect labels with related select dom elements like
<select id="first_dd" data-bind="value: first">
<option>cat</option>
<option>dog</option>
<option>squirrel</option>
<option>birds</option>
</select>
<label for="first_dd">soft</label>
Add JS to detect Change and add class
$('select').each(function(){
$(this).on('change',function(){
$('label[for="'+$(this).attr('id')+'"]').addClass('changed')
})
})
And add appropriate CSS for changed class
.changed {
color: #000;
}

How to manage table row associated javascript (control ID) while do clone the row

Initially, table has only one tr (label/header) and then on click of add button click , i create new tr which looks as below. and all other consequence click of add will clone the last tr.
<tr>
<script type="text/javascript">
//fetch the value of select picker control and set into hidden field.
AJS.$('#' + '${field_uid}-resourcetypepicker-new1').change(function () {
AJS.$('#' + '${field_uid}-resourcetype-new1').val(AJS.$(this).attr('value'));
});
//fetch the value of select picker control and set into hidden field.
AJS.$('#' + '${field_uid}-locationpicker-new1').change(function () {
console.log(AJS.$(this).attr('value'));
AJS.$('#' + '${field_uid}-location-new1').val(AJS.$(this).attr('value'));
});
</script>
<td>
<input id="${field_uid}-resourcetype-new1"
name="${field_uid}"
type="hidden"
value="$r.getResourceType()" />
<select id="${field_uid}-resourcetypepicker-new1">
<option value="adad" #if ($r.getResourceType() == "adad") selected="selected"#end >adad</option>
<option value="dada" #if ($r.getResourceType() == "dada") selected="selected"#end >dada</option>
<option value="aadd" #if ($r.getResourceType() == "aadd") selected="selected"#end >aadd</option>
</select>
</td>
<td>
<input id="${field_uid}-location-new1"
name="${field_uid}"
type="hidden"
value="$r.getLocation()" />
<select id="${field_uid}-locationpicker-new1">
<option value="Internal(Local)" #if ($r.getLocation() == "Internal(Local)") selected="selected"#end >Internal(Local)</option>
<option value="Contractor(Local)" #if ($r.getLocation() == "Contractor(Local)") selected="selected"#end >Contractor(Local)</option>
<option value="Contractor(Offshore)" #if ($r.getLocation() == "Contractor(Offshore)") selected="selected"#end >Contractor(Offshore)</option>
</select>
</td>
<td>
<input id="${field_uid}-rate-new1"
name="${field_uid}"
type="text"
value="$r.getRate()" /> <!-- $textutils.htmlEncode($r.getRate()) -->
</td>
<td>
<input id="${field_uid}-effort-new1"
name="${field_uid}"
type="text"
value="$r.getEffort()" />
</td>
</tr>
PROBLEM:
In above stuff, existing javascript that points to specific control id '#' + '${field_uid}-resourcetypepicker-new1' means (render ID looks like customfield-id-111-new1). Now, problem is, each clone row will have different unique ID for select/picker list control. and this javascript will points to first row control only as AJS.$('customfield-id-111-new1'). But it should be AJS.$('customfield-id-111-new2') then for next row AJS.$('customfield-id-111-new3') .
so, what is the best way to write below jquery stuff which can points to each cloned control rather then pointing to first row controls only ? any way through tr reference control or any other way.
AJS.$('#' + '${field_uid}-resourcetypepicker-new1').change(function () {
AJS.$('#' + '${field_uid}-resourcetype- new1').val(AJS.$(this).attr('value'));
});
Also, in cloned row, it did not include this javascript , do i need to append after clone ?
Please let me know if any more details need.
NOTE: AJS.$ is equal to $. it is used in velocity template file in JIRA.
Thank You
In light of the updated question, see the following code
AJS.$('[id^="${field_uid}-resourcetypepicker-"]')
This selector can be used to get any item with ID that starts with ${field_uid}-resourcetypepicker so you don't have to worry about the last part of the id i.e. new1, new2 etc.
Secondly, your change event will bind to all those elements that are present on page load. But if you create elements dynamically (clone or whatever), the events won't work. You should use
AJS.$('[id^="${field_uid}-resourcetypepicker-"]').on('change', function () {
...
});
This will work for all the elements on the page that match the selector

Get all selects after a current select element in a row

Let's say I have a table like this with multiple selects in very row:
<table>
<tr>
<td>
<select name="selectA" id="selectA">
....
</select>
</td>
<td>
<select name="selectB" id="selectB">
....
</select>
</td>
<td>
<select name="selectC" id="selectC">
....
</select>
</td>
</tr>
<tr>
<td>
<select name="selectA2" id="selectA2">
....
</select>
</td>
<td>
<select name="selectB2" id="selectB2">
....
</select>
</td>
<td>
<select name="selectC2" id="selectC2">
....
</select>
</td>
</tr>
<tr>
<td>
<select name="selectA3" id="selectA3">
....
</select>
</td>
<td>
<select name="selectB3" id="selectB3">
....
</select>
</td>
<td>
<select name="selectC3" id="selectC3">
....
</select>
</td>
</tr>
</table>
What I want to do is, when a select element changes, I want to get all select elements in the same row after the changed select element and change something with them as well.
So if selectA changes, I want to get selectB and selectC. If selectB changes, I want to get selectC. And so on. How to do that with jQuery?
Try this:
$('select').change(function() {
$(this).parent().nextAll().find('select')...
});
i.e. take the element's .parent() (which will be the <td>), then for all of its following siblings .nextAll(), .find() all <select> elements within them.
There are many jquery plugins that facilitate creating cascading dropdowns, which, in a nutshell, is what you want to achieve.
Here's a google search on "cascading dropdown jquery"; pretty much every result is a jQuery plugin :)
A slight modification of the Alnitak solution would be to bind the event handler on table level instead, so that you end up with only one function bound doing the job:
$('table').change(function(event) {
$(event.target).parent().nextAll().find('select')...
event.stopPropagation();
});
This will get you all the selects that are in the same row:
$("table select").change(function(){
var $select_mates=$('select', $(this).closest('tr'));
});
If you don't want the element itself:
$("table select").change(function(){
var $me=$(this);
var $select_mates=$('select', $me.closest('tr')).not($me);
});
My solution uses the jQuery Selector Context.
EDIT: Now I recognized I haven't seen after a current select element :). Let's see:
$("table select").change(function(){
var $me=$(this);
var $select_mates=$('select', $me.closest('tr'));
var $select_after_mates=$select_mates.slice($select_mates.index($me)+1);
});
Ok, this works, I've finally figured out how to do this:
$("table select").change(function(){
$(this).parent().nextUntil().find("select option:first").attr("selected", "selected");
});
i would try something like
//"obj" being your <select> HTML element
jQuery(obj).parent().find("select").not(obj);
UPDATE
I know the answer is already there but i thought for completeness I'd add a fix:
//"obj" being your <select> HTML element
// .parent().parent() gets the row
// .find("select" finds all the selects contained somewhere in that row.
// .not(obj) removes your current <select>
jQuery(obj).parent().parent().find("select").not(obj);

Categories

Resources