Sachu Sachu - 6 months ago 11
jQuery Question

how to bring static values for a dynamically created row in a table in mvc view

I have a table template and table as below in MVC view

Template for dynamic row

<table id="Newrelation" style="display:none">
<tr>
<td>
<select id="relation-%" style="width:100px" class="relation_type" name="survey_detail[#].relation" value></select>
</td>
<td>
<select id="agegroup-%" style="width:100px" class="age_group" name="survey_detail[#].age_group" value></select>
</td>
<td>
<select id="nodependent-%" style="width:100px" class="no_dependent" name="survey_detail[#].no_dependent" value></select>
<input type="hidden" id="new_relation" name="survey_detail.Index" value="%" />
</td>
<td><input id="delete" class="delete" value="X" type="button"></td>
</tr>
</table>


Actual table

<table id="relation" class="table table-striped table-hover table-bordered">
<tbody>
<tr>
<th style="width:100px">
Relation
</th>
<th style="width:150px">
Age Group
</th>
<th style="width:150px">
No: Dependent
</th>
</tr>
@if (Model != null)
{
for (int i = 0; i < Model.survey_detail.Count; i++)
{
<tr>
<td>
@Html.DropDownListFor(m => m.survey_detail[i].relation, (SelectList)@ViewBag.Relation,"--", new { @class = "m-wrap" })
</td>
<td>
@Html.DropDownListFor(m => m.survey_detail[i].age_group, (SelectList)@ViewBag.Agegroup,"--", new { @class = "m-wrap" })
</td>
<td>
@Html.DropDownListFor(m => m.survey_detail[i].no_dependent, (SelectList)@ViewBag.Number, "--", new { @class = "m-wrap" })
<input type="hidden" name="survey_detail.Index" value="@i" />
</td>
<td><input id="delete" class="delete" value="X" type="button"></td>
</tr>
}
}
</tbody>
<table>


Jquery to attach new row on button click

$('#add_rel').click(function (e) {
var body = $('#relation').children('tbody').first();
var index = (new Date()).getTime();
var clone = $('#Newrelation').clone();
clone.html($(clone).html().replace(/\[#\]/g, '[' + index + ']'));
clone.html($(clone).html().replace(/"%"/g, '"' + index + '"'));
clone.html($(clone).html().replace(/"relation-%"/g, 'relation-' + index));
clone.html($(clone).html().replace(/"agegroup-%"/g, 'agegroup-' + index));
clone.html($(clone).html().replace(/"nodependent-%"/g, 'nodependent-' + index));
var newrow1 = clone.find('tr');
body.append(newrow1);
});


And it attach new row to the table but all the select list comes blank eventhough the
@ViewBag.Relation,@ViewBag.agegroup,@ViewBag.Number
has data.

Please guide me to get values on the select list

Fiddle screen shot

enter image description here

Answer

Firstly, your use of DropDownListFor() will not work correctly (the first option will always be selected no mater what the value of the property is) as explained in this answer (note in your case you will not be able to use the EditorTemplate option).

To solve this and the main issue in your question, change your ViewBag properties from IEnumerable<SelectListItem> to IEnumerable<T> where T is an object containing just 2 properties, for example

public class OptionVM
{
    public int ID { get; set; }
    public string Name { get; set; }
}

and then the code in the GET method would be something like

ViewBag.Relation = db.Relations.Select(x => new OptionVM
{
    ID = x.RelationId,
    Name = x.SomeOtherPropertyToDisplay
});

In the view, for the generating the existing items, use

for (int i = 0; i < Model.survey_detail.Count; i++)
{
    ....
    @Html.DropDownListFor(m => m.survey_detail[i].relation, 
        new SelectList(ViewBag.Relation, "ID", "Name", Modelsurvey_detail[i].relation), 
        "--", 
        new { @class = "m-wrap" })
    ....
}

which will ensure the correct options is selected.

Now you can use those same ViewBag properties to add the <option> elements to your template when the page is first loaded.

// Get the first select element in the template
var relationSelect = $('#Newrelation').find('select').eq(0);
// Create a javascript array of the options
var relationOptions = @Html.Raw(Json.Encode(ViewBag.Relations));
// Create and append option elements
relationSelect.append($('<option></option>').val('').text('--'));
$.each(relationOptions, function(index, item) {
    relationSelect.append($('<option></option>').val(item.ID).text(item.Name));
});

and repeat for the 2nd and 3rd <select> elements in the template.

Side notes:

  1. It is not necessary to add id attributes to the <select> and <input type="hidden"> elements in the template and you should not be adding one to the <input type="button"> because that is generating invalid html (duplicate id attributes).
  2. Your creating a null ("--") option which suggest you will be validating that a selection has been made, in which case you should also be adding @Html.ValidationMessageFor() for each property (and adding the html that it generates to your template (refer this answer for more detail). If that is the case, you will also need to reparse the validator each time a new item is added (as shown in the previous link).
  3. Finally, I recommend you use a view model containing properties for the collections used to generate the options rather than using ViewBag.