Solved

jquery add table row with json data in dropdowns

Posted on 2011-03-07
9
1,300 Views
Last Modified: 2013-11-11
Hi, I have a web form with a table that the user can add additional rows to. The first row of the table consists of dependent dropdowns. The dropdowns are populated with json data from a referenced file. The code that I am using for it is as follows:

   
 $("#section").change( function () {
    var sSec =$(this).val();
    
    $("#divParts").hide();
    $("#divDesc").hide(); 
    $("#divGroup").hide(); 
    if(sSec=="select") {
    $("#divCategory").hide();
    } else {
    $.getJSON("static/site_category.json",  function(json) {
    var catJson = json[sSec];
    var options = "<option value=\"select\">Select Area Type</option>";
    for(i=0;i<catJson.length;i++) {
    options +="<option value=\""+catJson[i].ky+"\">"+catJson[i].val+"</option>"
    }
    
    $("#category").html(options);
    $("#divCategory").show();    
    });
    }
    }); 

Open in new window


This is only one dropdown, but it illustrates that I am trying to hide/show other dropdowns based on user selection.

For the add row function, I use this code:

     
 var currentItem = 1; 
     $("#addRow").live("click", function() {
    	  
    	   currentItem++; 
    	   var currentItem = 1; 
          //clone last row to variable
       var row = $('#details tbody>tr:last').clone(true);
          //clear text boxes
        $("td input:text", row).val("");
        //clear selection boxes
         $("select option:selected", row).attr("selected", false);
          //clear empty cells
    
          //add row
     row.insertAfter('#details tbody>tr:last');
        return false;
     }); 

Open in new window


To make this bit of code work, I have created a hidden field that acts as a counter. When the user clicks on the add row button, the counter increases and theoretically, a new row is added and the first section of code I pasted will work for each additional row. However, the results are not like that at all. Instead, when the row is added and the user makes a selection on the new row, the values are updated in the first row. I then tried to add a dynamic ID to the dropdown selection ID each time that the add row button is clicked so that the ID would match the hidden counter field, but the results were not correct either. In this scenario, the values of each added row were changed when the first row dropdown values were changed.

I appreciate any help to get this code working as desired - which would be a simple added row where the dropdown selections only update on the row that they are found on. Thank you.
0
Comment
Question by:wbpw
  • 5
  • 4
9 Comments
 
LVL 82

Expert Comment

by:leakim971
ID: 35060029
Could you post a row or better the main HTML code ?
0
 

Author Comment

by:wbpw
ID: 35060153
Yes, here is the row to be duplicated:
<tr class="rec-rows"> 
<td width="" align="left">
<div><select id="section" name="section" style="margin-top:15px;">
<option value="select">Select Area</option>
<option value="a">a</option>
<option value="b">b</option>
<option value="c">c</option>
</select>
</div>
</td> 
<td width="" align="left">
<div id="divCategory" style="display:none;margin-top:15px;">
<select id="category" name="category"></select>
</div>
</td> 
<td width="" align="left">
<div id="divGroup" style="display:none;margin-top:15px;">
<select id="group" name="group"></select>
</div>
</td> 
<td width="" align="left">
<div id="divParts" style="display:none;margin-top:15px;">
<select id="parts" name="parts"></select>
</div>
</td> 
<td width="" align="left">
<div id="divDesc" style="display:none; margin-top:15px;">
<select id="desc" name="desc"></select>
</div>
<div id="divText" style="display:none">
Type Description:
<input type="text" value="" id="text" name="text" style="width: 100px;" />
</div>
</td> 
<td width="" align="left">Qty:<input type="text" name="quantity" style="width:30px" id="quantity"/></td> 

</tr> 

Open in new window

0
 
LVL 82

Accepted Solution

by:
leakim971 earned 500 total points
ID: 35060515
First as you know << id >> must be unique in a document. You should (MUST) not have the same id for more than one element.
You may use the row as context to select the right element. For example to clear all input in the current row (this) : $("input", $(this).parens("tr")).val("");

Check this (I use class instead id) :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<script language="javascript" src="http://code.jquery.com/jquery-1.5.min.js"></script>
<script language="javascript">
	$(document).ready(function() {
		$(".section").change( function () {
			context = $(this).parents("tr");
			var sSec = $(this).val();
			$(".divParts", context).hide();
			$(".divDesc", context).hide(); 
			$(".divGroup", context).hide(); 
			if(sSec=="select") {
				$(".divCategory", context).hide();
			}
			else {
				$.getJSON("static/site_category.json", function(json) {
					var catJson = json[sSec];
					var options = "<option value=\"select\">Select Area Type</option>";
					for(i=0;i<catJson.length;i++) {
						options += "<option value=\""+catJson[i].ky+"\">"+catJson[i].val+"</option>";
					}
					$(".category", context).html(options);
					$(".divCategory", context).show();
				});
			}
		});
	
		$("#addRow").live("click", function() {
			var row = $('#details tbody>tr:last').clone(true);
			$("td input:text", row).val("");
			$("select option:selected", row).attr("selected", false);
			$("#details").append(row);
		});
	
	});
</script>
</head>
<body>
<input type="button" value="Add row" id="addRow" />
<br />
<table id="details">
<tr class="rec-rows"> 
<td width="" align="left">
<div><select class="section" name="section" style="margin-top:15px;">
<option value="select">Select Area</option>
<option value="a">a</option>
<option value="b">b</option>
<option value="c">c</option>
</select>
</div>
</td> 
<td width="" align="left">
<div class="divCategory" style="display:none;margin-top:15px;">
<select class="category" name="category"></select>
</div>
</td> 
<td width="" align="left">
<div class="divGroup" style="display:none;margin-top:15px;">
<select class="group" name="group"></select>
</div>
</td> 
<td width="" align="left">
<div class="divParts" style="display:none;margin-top:15px;">
<select class="parts" name="parts"></select>
</div>
</td> 
<td width="" align="left">
<div class="divDesc" style="display:none; margin-top:15px;">
<select class="desc" name="desc"></select>
</div>
<div class="divText" style="display:none">
Type Description:
<input type="text" value="" class="text" name="text" style="width: 100px;" />
</div>
</td> 
<td width="" align="left">Qty:<input type="text" name="quantity" style="width:30px" class="quantity"/></td> 
</tr> 
</table>
</body>
</html>

Open in new window

0
 

Author Comment

by:wbpw
ID: 35061109
Thank you leakim! Your solution solved two of my problems: 1) the clearing of values for each added row and 2) when a row is added, that specific row's content is updated.

However, I still have one other issue. The code you have provided does in fact leave the first dropdown visible. However, The onChange function is still .class specific. That is, when a new row is added and the user selects an option from any of the added rows, then all of the .classes that hide/show re-populate with the last selected values. How am I able to give a unique value to the first line in the code below so that when a user is finished selecting values from a row, they do not hide/show when they are selecting values from another row?

            
$(".section").change( function () { /// this needs to be unique
			context = $(this).parents("tr");
			var sSec = $(this).val();
			$(".divParts", context).hide();
			$(".divDesc", context).hide(); 
			$(".divGroup", context).hide(); 
			if(sSec=="select") {
				$(".divCategory", context).hide();
			}
			else {
				$.getJSON("static/site_category.json", function(json) {
					var catJson = json[sSec];
					var options = "<option value=\"select\">Select Area Type</option>";
					for(i=0;i<catJson.length;i++) {
						options += "<option value=\""+catJson[i].ky+"\">"+catJson[i].val+"</option>";
					}
					$(".category", context).html(options);
					$(".divCategory", context).show();
				});
			}
		});

Open in new window

0
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 
LVL 82

Expert Comment

by:leakim971
ID: 35061404
>However, The onChange function is still .class specific. That is, when a new row is added and the user selects an option from any of the added rows, then all of the .classes that hide/show re-populate with the last selected values.
>$(".section").change( function () { /// this needs to be unique

Wrong, we check change event for all element having section as class but only one (with it's own context) is fired. That's why we're able to use $(this)
If we want to be sure, check length of selected element with for example : alert( $(".divParts", context).length )
0
 
LVL 82

Expert Comment

by:leakim971
ID: 35061522
Maybe I don't unserstood something (like usual :))
leakim971-417243.flv
0
 

Author Comment

by:wbpw
ID: 35072808
leakim, thank you for the visual. I just spent time trying to duplicate your results. I did get what you did! However, I also found where my error is. It seems I am getting the results I am getting when I place that table into the rest of the form, which is within another table. Below is the code the causes the results I was getting:

<form id="form" name="form">
<table width="100%" border="1" cellpadding="5" cellspacing="5" id="table1">
<tbody> 
<tr>
<td align="center" valign="top">
<input type="button" value="Add" id="addRec" style="width:150px;">
<input type="button" value="Delete" style="width:150px;">
</td>
<td valign="top">
<TABLE id="survey" style="margin-top:100px;">
<TR>
<TD colspan="2"> Name: </TD>
<TD colspan="2"><span class="requiredField">
<textarea name="area[]" cols="65" id="area[]"></textarea>
</span></TD>
</TR>
<TR>
</TR>
<TR>
<TD colspan="4" bgcolor="#0066FF">&nbsp;</TD>
</TR>
<TR>
<TD colspan="4">
<table width="100%" border="0" cellspacing="0" cellpadding="0" >        
<tr>
</table>
<table width="100%" border="0" cellspacing="0" cellpadding="0" id="details">
<tr><td><input name="addRow" type="button" class="add" value="+" id="addRow"></td></tr>
<tr class="rec-rows"> 
<td width="" align="left">
<div><select class="section" name="section" style="margin-top:15px;">
<option value="select">Select Area</option>
<option value="a">a</option>
<option value="b">b</option>
<option value="c">c</option>
</select>
</div>
</td> 
<td width="" align="left">
<div class="divCategory" style="display:none;margin-top:15px;">
<select class="category" name="category"></select>
</div>
</td> 
<td width="" align="left">
<div class="divGroup" style="display:none;margin-top:15px;">
<select class="group" name="group"></select>
</div>
</td> 
<td width="" align="left">
<div class="divParts" style="display:none;margin-top:15px;">
<select class="parts" name="parts"></select>
</div>
</td> 
<td width="" align="left">
<div class="divDesc" style="display:none; margin-top:15px;">
<select class="desc" name="desc"></select>
</div>
<div class="divText" style="display:none">
Type Description:
<input type="text" value="" class="text" name="text" style="width: 100px;" />
</div>
</td> 
<td width="" align="left">Qty:<input type="text" name="quantity" style="width:30px" class="quantity"/></td> 
</tr> 
</table>
</TD>
</TR>
</TABLE>
</td>
</tr>
</tbody> 
</table>
</form>

Open in new window


Try this with your code and then you will see what I was getting. This leads me to think that this issue can be resolved by further declaring the context variable? Perhaps something like

context = $(this).parents("table:tr tr");

Open in new window


I am not sure. Let me know if you see what I mean about the results I was getting. Thanks!
0
 

Author Comment

by:wbpw
ID: 35072970
What I posted above is not close to what I need to do. However, it is official that the code doesn't work correctly when the table is nested within another table. Do you know how I would fix this? I am also still looking for a solution, will let you know if I find one.
0
 
LVL 82

Expert Comment

by:leakim971
ID: 35073267
Thanks for your feedback. Use :
$(this).parents("tr").filter(":first")

Open in new window

instead
$(this).parents("tr")

Open in new window

0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

What is a Lightbox? A Lightbox is the effect you see when you click, for example, an image and the screen fades out and up pops the same image but in its full size dimensions. There are lots of Lightbox effects for jQuery. Problem is they are a…
How to build a simple, quick and effective accordion menu using just 15 lines of jQuery and 2 css classes
The viewer will learn how to dynamically set the form action using jQuery.
The viewer will learn the basics of jQuery including how to code hide show and toggles. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

24 Experts available now in Live!

Get 1:1 Help Now