I am using ASP.NET MVC in VB. This is the "CreateStuffViewModel", which is a view model for my "Stuff" class:
Public Property Name() As String
Public Property Description() As String
Public Property ItemNames() As List(Of String)
In the View for creating a Stuff, the model being used is the above view model. I have a dropdown combobox containing the names of all of the user's Items, which is created in the controller in the Get. The user can select an item in the combobox, then hit an "Add" button, which adds that text to a list box. When the user hits the "Create" button, the text items in the list box are supposed to be in the ItemNames list.
This is the Get function:
' GET: Stuff/Create
Function Create() As ActionResult
Dim selectItem As New List(Of SelectListItem)
Dim curUserID = User.Identity.GetUserId()
Dim listOfItems = db.Items.Where(Function(x) x.MyUser.Id = curUserID)
For Each item In listOfItems
selectItem.Add(New SelectListItem() With {.Value = item.ID, .Text = item.Name})
Next
ViewData("selectItem") = selectItem
Dim newStuff As CreateStuffViewModel = New CreateStuffViewModel
newStuff.ItemNames = New List(Of String)
Return View(newStuff)
End Function
Then this is the view:
@ModelType CreateStuffViewModel
@Code
ViewData("Title") = "Create"
'This is the list of items that was created in the controller
Dim selectItem As New List(Of SelectListItem)
selectItem = ViewData("selectItem")
Dim selItems As New List(Of SelectListItem)
End Code
<h2>Create</h2>
@Using (Html.BeginForm())
@Html.AntiForgeryToken()
@<div class="form-horizontal">
<br />
<br />
<h4>Create a new Stuff</h4>
<hr />
@Html.ValidationSummary(True, "", New With { .class = "text-danger" })
<div class="form-group">
@Html.LabelFor(Function(model) model.Name, htmlAttributes:= New With { .class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(Function(model) model.Name, New With { .htmlAttributes = New With { .class = "form-control" } })
@Html.ValidationMessageFor(Function(model) model.Name, "", New With { .class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(Function(model) model.Description, htmlAttributes:= New With { .class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(Function(model) model.Description, New With { .htmlAttributes = New With { .class = "form-control" } })
@Html.ValidationMessageFor(Function(model) model.Description, "", New With { .class = "text-danger" })
</div>
</div>
@*This is the dropdown list containing the strings of item names*@
<div class="form-group">
<div class="control-label col-md-2" style="font-weight: bold">Select an existing Item</div>
<div class="col-md-10" id="ItemsList">
@Html.DropDownList("AvailItems", selectItem)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="button" value="Add Item" class="btn btn-default" id="AddItem"/>
</div>
</div>
@*This is the list box to which the Add button adds the item text*@
<div class="form-group">
<div class="control-label col-md-2" style="font-weight: bold">Items in Stuff</div>
<div class="col-md-10">
@Html.ListBoxFor(Function(model) model.ItemNames, New SelectList(selItems), htmlAttributes:=New With {.name = "ItemNames"})
<div class="btn-group-vertical">
<div class="btn-link">Move Up</div>
<div class="btn-link">Move Down</div>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="button" value="Remove Selected Item" class="btn btn-default" id="RemoveItem"/>
</div>
</div>
<br />
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
End Using
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@Section Scripts
@Scripts.Render("~/bundles/jqueryval")
@*Script for adding selected item from drop down to the list*@
<script>
$('#AddItem').click(function () {
var selection = $('#ItemsList :selected').text();
selection.trim();
var x = document.getElementsByName("ItemNames");
var i;
for (i = 0; i < x.length; i++) {
if (x[i].type == "select-multiple") { //listbox
x[i].options.add(new Option(selection, selection));
}
}
});
</script>
@*Script for removing selected item from list*@
<script>
$('#RemoveItem').click(function () {
var x = document.getElementsByName("ItemNames");
var listBox;
var i;
for (i = 0; i < x.length; i++) {
if (x[i].type == "select-multiple") { //listbox
listBox = x[i];
}
}
if (listBox.selectedIndex >= 0) {
var sel = listBox.options[listBox.selectedIndex];
listBox.options.remove(sel);
}
});
</script>
End Section
And this is the Post function:
' POST: Stuff/Create
'To protect from overposting attacks, please enable the specific properties you want to bind to, for
'more details see http://go.microsoft.com/fwlink/?LinkId=317598.
<HttpPost()>
<ValidateAntiForgeryToken()>
Async Function Create(ByVal model As CreateStuffViewModel) As Task(Of ActionResult)
If ModelState.IsValid Then
Dim newStuff = New Stuff() With {
.Name = model.Name,
.Description = model.Description
}
Dim curUserID = User.Identity.GetUserId()
Dim thisUser As AppUser = db.Users.Where(Function(x) x.Id = curUserID).FirstOrDefault()
newStuff.MyUser = thisUser
'model.ItemNames is Nothing:
Dim thisList As List(Of String) = model.ItemNames
If thisList IsNot Nothing Then
Dim thisItem As Item
For Each item In thisList
thisItem = (From thing In db.Items Select thing Where thing.MyUser.Id = curUserID AndAlso thing.Name = item)
newStuff.Items.Add(thisItem)
Next
End If
db.Stuffs.Add(newStuff)
Await db.SaveChangesAsync()
Return RedirectToAction("Index")
End If
Return View(model)
End Function
So the view works fine - the Add button adds the text to the list box as expected. But when I hit the "Create" button, in the controller, the ItemNames list is NOTHING, and I do not know why.
Any help is greatly appreciated!