Alexander Demerdzhiev Alexander Demerdzhiev - 3 months ago 7
C# Question

Bind string property to dynamically filled dropdownlist does not set value

I am creating an empty child dropdown, which is filled dynamically according to its parent. When the form is submited, the property

Platform
is always null. Why?

Here is my ViewModel:

public class SkillsViewModel
{
public int SkillId { get; set; }
public string Platform { get; set; }
}


Here is my view:

@using (@Html.BeginForm("AddSkill", "AddSkills"))
{
@Html.DropDownListFor(m => m.SkillId,
new SelectList(ViewBag.SkillsFound, "Id", "SkillName"), "Select skill",
new { @class = "form-control", @onchange = "SkillSelected()" })

@Html.DropDownListFor(m => m.Platform,
new SelectList(Enumerable.Empty<SelectListItem>()),
new { @class = "form-control" })

<input type="submit" name="submit" value="Add skill" class="btn btn-success" />
}


And Controller:

[HttpPost]
public ActionResult AddSkill(SkillsViewModel model)
{
// model.Platform is always null
// to be implemented...
return RedirectToAction("Index");
}


Here is the scrip that populates the dropdown.It works right - adding a list of strings to the dropdown

function SkillSelected() {

var idSelected = $('#SkillId').val();

if (idSelected == 0)
{
$("#Platform").html("");
}

$.post("../GetSkillPlatforms", { skillid: idSelected }, function (data) {
$("#Platform").html("");
$.each(data, function (i, data) {
$("#Platform").append(
$('<option></option>').val(data.Id).html(data));
});
});
}


EDIT:

here is the controller that returns the list of strings.

public class GetSkillPlatformsController : Controller
{
[HttpPost]
public ActionResult Index(int skillId)
{
var Db = new DbContext();

List<Platform> PlatformsFound = Db.Platforms.Where(pl => pl.PlatformSkill.Id == skillId).ToList();

List<string> PlatformsNames = new List<string>();

foreach(Platform pl in PlatformsFound)
{
PlatformsNames.Add(pl.PlatformName);
}

return Json(PlatformsNames);
}
}

Answer

Your controller method is returning a collection of string, and in the script you use of

$.each(data, function (i, data) {
    $("#Platform").append($('<option></option>').val(data.Id).html(data));
});

is setting the value attribute of each option to null (value="") because data is a string and string does not contain a property named Id.

Change the script to

$.each(data, function (i, data) {
    $("#Platform").append($('<option></option>').text(data));
});

which omits the value attribute, and by default will submit the value of the selected text (or you could use .append($('<option></option>').val(data).text(data))

In addition, you can simplify the controller code to

[HttpPost]
public ActionResult Index(int skillId)
{
    var Db = new DbContext();
    var model = Db.Platforms.Where(pl => pl.PlatformSkill.Id == skillId).Select(pl => pl.PlatformName);
    return Json(model);
}
Comments