Sparksong Sparksong - 18 days ago 5
ASP.NET (C#) Question

Add Actors to a list for DVD Library

So I have a DVD object which contains a list of actors. I have an add view (everything else adds fine) but I'm stuck on trying to get the actors to add to the list on the DVD. I attempted to integrate JavaScript into it to create new text boxes for each actor, but it isn't actually saving more than the first one. Any advice / suggestions?

Here is the code in the view for the actor list:

<div id="actorsContainer">
<div class="form-group">
@Html.LabelFor(model => model.dvd.ActorList, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.TextBoxFor(model => model.dvd.ActorList, new { htmlAttributes = new { @class = "form-control", id = "actors", name = "actors[]" } })
<input type="button" class="btn-sm btn-default col-md-2" id="addActor" value="+" />
@Html.ValidationMessageFor(model => model.dvd.ActorList, "", new { @class = "text-danger" })
</div>
</div>
</div>


And here is what I used currently for the JavaScript:

<script>
document.getElementById("addActor").onclick = function () {
var div = document.getElementById("actorsContainer");
var input = document.createElement("input");
input.type = "text";
input.name = "actors[]";
div.appendChild(document.createElement("br"));
div.appendChild(input);
}
</script>


Update:

Here is the code I have for the controller as well. Maybe this have something to do with it? Also only one addActor button exists, but hoping to add a textbox each time it is clicked to add multiple actors.

[HttpGet]
public ActionResult AddDVD()
{
DVDListVM vm = new DVDListVM();

return View(vm);
}

[HttpPost]
public ActionResult AddDVD(DVDListVM model)
{
if (ModelState.IsValid)
{
DVD newDVD = new DVD();

newDVD.Title = model.dvd.Title;
newDVD.ReleaseYear = model.dvd.ReleaseYear;
newDVD.DirectorName = model.dvd.DirectorName;
newDVD.Studio = model.dvd.Studio;
newDVD.MPAARating = model.dvd.MPAARating;

newDVD.ActorList = model.dvd.ActorList;

newDVD.UserNotes = model.dvd.UserNotes;
newDVD.UserRating = model.dvd.UserRating;

_dvdManager.AddDVD(newDVD);

return RedirectToAction("Collection");
}
else
{
return View(model);
}
}

Answer

If ActorList is a collection, you need to create an input for every record in the collection like this.

@for (int i = 0; i < model.dvd.ActorList.Count; i++) { @Html.TextBoxFor(model => model.dvd.ActorList[i], new { htmlAttributes = new { @class = "form-control"} }) }

I do not assign id and name attributes since razor generates values for this attributes automatically.

If you want to create inputs dynamically, you need to check out html rendered by razor and how it handles indexes for collections. I use asp.net mvc core and that's how email input which is part of a collection looks in html.

<input name="EmailAddresses[1].EmailAddress" class="form-control emailInputAddress" id="EmailAddresses_1__EmailAddress" type="email" value="">

To create inputs dynamically I get element index, increment it, and then create a copy of element with new index.

var newEmailInput = $(".emailInput:last").clone(true)[0].outerHTML;
    //get index generated by razor and increment it
    var newEmailInputIndex = newEmailInput.match(/(\[([^\]]+)\])/i)[0].match(/\d+/i)[0];
    newEmailInputIndex++;
    newEmailInput = newEmailInput.replace(/(\[([^\]]+)\])/ig, "[" + newEmailInputIndex + "]")
                            .replace(/(_([^_]+)__)/ig, "_" + newEmailInputIndex + "__");

    $(this.lastEmailInput).after(newEmailInput);