MVC: Binding dynamic select list back to ViewModel on Post - asp.net-mvc

I have a MVC 3 project, and is stuck on the binding of the view back to the model on Post.
Here is my Model:
public class DBViewModel
{
public ProductionDatabasesViewModel PDBViewModel { get; set; }
public IList<string> SelectedNames { get; set; }
public DBViewModel()
{
SelectedNames = new List<string>();
PDBViewModel = new ProductionDatabasesViewModel();
}
}
My view: (cut down version)
#model Web.Models.DBViewModel
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
#Html.ListBoxFor(x => x.SelectedNames, new SelectList(Model.SelectedNames))
<input id="button-submit" name="SubmitButton" type="submit" value="Submit" />
</fieldset>
}
Snippet of the Controller:
[HttpPost]
public ActionResult Database(DBViewModel model)
{
var users = model.SelectedNames; //<---- empty, the count is 0 always.
}
In the view there is the ability to select users from a autocomplete box and then jQuery script that will add the selected names to the list in the view above. This all works, so I can search for the users, and then click the add button to add the users to the list. But I run into problems when clicking the Submit button. The users that were added in the view (selectlist in the view), is not bound to the Model. So on post the model.SelectedNames is empty. I have also tried Request["SelectedNames"] and Request.Form["SelectedNames"] and they are all null.
I am very experienced in normal webforms, but still learning MVC, so any help would be much appreciated.
[UPDATE]
I will update the question further tomorrow my time, but it appears that the items that is in the list will be bound to the viewmodel if I select them. I will figure this out tomorrow. But thanks a lot so far for all the comments, help and suggestions.

Does this Does the Model Binder in ASP.NET MVC Beta Support List<T>? answer your question? The string list is a simpler version.

Have to say this cut off version of your code works as it should. SelectedNames list is successfully filled from listbox after submit. You can check it yourself. Though I have made several changes:
removed all references to ProductionDatabasesViewModel;
changed return type of POST version of Database method to void;
added GET version of Database method
:
public ActionResult Database()
{
return View(new DBViewModel { SelectedNames = { "a", "b", "c" } });
}
So I believe you have a bug somethere else, not in these parts.

Ok, I have found what the issue is. When you have a multi select element in your html that you want to bind the values in the box back to the model, you have to select the items first. Very annoying, but that's the way it seems to want it.
So if you have a select box like:
<select id="selected-ad-users-list" name="SelectedNames" multiple="multiple" size="5"
style="width: 100%">
</select>
And you add items to it, from anywhere really, in my case I had another list/or textbox where they typed a name in, and then I used jQuery to populate this select list. What I needed to do was to add a bit of jQuery script to spin through my list and select all items. So once the items are selected, it will bind them to the model.
Here is a good article on this: select all or some items in a select box
I really hope this helps someone.

Related

Using one dropdownlist for two different forms in ASP MVC

Using MVC4, I have a drop-down list that contains a value a user may select. Then I have two different actions that I would like to pass that value into. How do I accomplish this, if it is even possible?
View:
#using (Html.BeginForm("Action1", "Controller", FormMethod.Post, new FormCollection()))
{
#Html.DropDownList("Item", Model.GetListValues(Model.Items))
<input type="submit" value="Goto Action1">
}
#using (Html.BeginForm("Action2", "Controller", FormMethod.Post, new FormCollection()))
{
<input type="submit" value="Goto Action2">
}
Controller:
public Task<ActionResult> Action1(string item)
{
//logic
}
public Task<ActionResult> Action2(string item)
{
//logic
}
Right now, the code will allow me to pass in the value in the dropdown for the first form, but how do I include it in the second form? Might it involve the use of #Html.HiddenFor? I don't want to duplicate the drop-down list.
With jQuery, all things are possible.
As you mentioned, add a hidden field to your second form. Then, add a jQuery script to update that field whenever the dropdown changes. You'll need to update your item names so they aren't duplicates, but other than that, your existing code will work.
$("#ItemDropdown").change(function () {
$("#ItemHidden").val($("#ItemDropdown").val());
});

View not passing data to controller

I've been looking on SO and google for over a week now and still was unable to find the working answer. Hopefully someone can help me.
Im working on a project with asp.net (Entity Framework + Razor) and I'm trying' to add two models to the views. It is showing perfectly, using editorFor(). Now the problem is some part is not passing the information to the controller.
In this case every exercise got some answers. This is my exercise model:
Table("Exercise")]
public class ExerciseModel
{
[Key]
public int ExerciseId { get; set; }
[Required]
public string Question { get; set; }
[Required]
public List<AnswerModel> Answers { get; set; }
And this the answermodel:
[Table("Answer")]
public class AnswerModel
{
[Key]
public int AnswerId { get; set; }
[Required]
public string Answer { get; set; }
}
The view exists out of two parts, the exercise part (the working one) and the answer part. I want to add more answers into a list in exercisemodel. I've tried different ways. Editor templates, partial views etc.
This is the view:
You can create a new question and add answers on the go using Jquery. What i want to create is that i can post answers into that list in exercisemodel.
#using (Html.BeginForm("CreateQuestion", "Admin", FormMethod.Post))
{
#Html.ValidationSummary(true)
//will be changed
#Html.Partial("_PartialCreateExercise")
//this shows the answers form
<div style="display: none;" id="new">
<div class="editor-field">
#Html.EditorFor(m => m.Answers);
</div>
</div>
<p>
<input name="command" type="button" id="add" value="add new answers" />
</p>
<p>
<input name="command" type="submit" value="Create" />
</p>
}
This works, but when i submit the page the List in exercisemodel (of type AnswerModel) remains empty. And finally the editor template for answers:
#model Academy.Models.AnswerModel
#{
Layout = null;
}
<h2>Answer</h2>
<p>
#Html.LabelFor(model => model.Answer)
#Html.EditorFor(model => model.Answer)
</p>
The jQuery:
$(document).ready(function () {
$("#add").click(function () {
$('#add').after($("#new").html());
$('#new').css("Display", "block");
});
});
It doesn't do much and tried alot in there, so it's becoming messy. But when using the debug mode the List in ExerciseModel is empty and also the AnswerModel.
So again, the problem is that when posting the form, the List in ExerciseModel remains empty. I can't reach the List in exercisemodel for some reason through editor template. (controller not included because it doesn't do a lot right now and the List is always empty)
This has been keeping me busy for a week now, hopefully someone can help me?
I suspect that the culprit lies in your jQuery code, the one that's supposed to dynamically add new answers. You haven't shown it so it is hard to tell what might be wrong with it.
What you should be careful with is the naming convention of the input fields. Phil Haack illustrated in his blog post this convention.
Basically there are 2 approaches to dynamically adding a new element (when #btnadd is clicked):
Send an AJAX call to a controller action that will return a partial view containing en empty template. The naming convention should once again be respected. The difficulty here comes with the index. Since the naming convention allows you to use non-sequential indexes (read Phil Haack blog post once again) the easiest here would be to use Guids as indexes. Steven Sanderson illustrated this concept in his blog post and even showed a custom Html.BeginCollectionItem helper which does exactly that.
Do it purely on the client side. For example you could use a framework such as knockoutjs. Once again Steven Sanderson illustrated this concept in his blog post.
So So basically it's up to you to choose the approach you prefer. But no matter which approach you choose when the form is submitted if you haven't respected the nameing convention of your Answers input fields all you will get in your controller action is null.

Model with List - approaches to add new item to the list from a Razor view

I have a model with various properties but the one of interest is a List of another type of Model.
For example:
public class User
{
public string Name { get; set; }
public string Description { get; set; }
public IEnumerable<UserInterest> Interests { get; set; }
}
I then use an Editor Template within my view to render out a view for each item of the model items.
#Html.EditorFor(x => x.Interests)
The EditorFor template looks something like:
#model Interest
<div>
#Html.HiddenFor(x => x.Id)
#Html.TextBoxFor(x => x.InterestText)
#Html.CheckBoxFor(x => x.Delete)
....
</div>
Something very similar to the accepted answer here: Model Containing List of Models (MVC-3, Razor)
My question is - how would you from the client-side (jQuery) create a new item within the property without going back to the server. I currently have a rough way of doing it whereby I post the data back to my controller which returns the model back with a new blank item within the Interests property.
This seems to be overkill making a HTTP request and not very elegent. I was thinking of using jQuery .Clone() but not entirely sure on what I'd need to do in terms of naming the elements and clearing existing values.
So does anybody have any suggestions. I'm hoping to get more opinions and different approaches.
You can simply create the Textbox and checkbox on the fly and add that to the DOM. When saving it, Use jQuery ajax to post that data ( new record data) to an action method and save it there. Return a status back (Succcess /Falied) from your action method to your client side code ( your callback function of jQuery ajax/post) and check it there. If it is success, Show a success message to the user and append the new item to the existing list.
Sample jSFiddle : http://jsfiddle.net/carwB/2/
If you want to return some complex data ( ex : All new records with its id etc..) along with the status, you may return JSON from your action method.
EDIT : To keep your Model binding works with the newly added dynamic elements, you need to follow the naming convention of the elements.
The trick is to keep the id property value of the html element in this format.
CollectionName_ItemIndex__PropertyName
and name property value in this format
CollectionName[ItemIndex].PropertyName
I created a sample working program and explained it how it works Here based on your requirements.
In such situations I prefer to use client templating. You send data to server with ajax and then receive JsonResult. Look at JsRender this is javascript lib without jQuery dependency.
1.Create two partial view one is for list item and second one is creation
2.First partail view should be inside the div which has id 'divMdeolList'
3.and Creation view will have the code like that
#using (Ajax.BeginForm("SubmitData", new AjaxOptions { UpdateTargetId = "divMdeolList" }))
{
#Html.TextBoxFor(x => x.InterestText)
<p>
<input type="submit" value="Create" />
</p>
}
4. And then create a ActionResult type action on controller that will render the partialview
public ActionResult SubmitData(YourModel model)
{
//Do : save the record
return PartialView("FirstPartailView", model);
}
This will update the View without postback

How to create a single select list box that shows the selection using Razor

How do I create a simple, single select list box using the Razor view engine? I'm currently running into two problems. The first is that the list box "Select" code generated has 'multiple' automatically added. Question One is how to turn that off. No, I don't want to have to use a drop down list box.
Question Two is trickier. The generated "Select" in the output html does not show any items as being selected, despite the item in question have selected values. Here's my code:
Object model:
public class Description
{
public String code { get; set; }
public SelectList codelist;
}
Controller:
code = "drain";
codelist = new SelectList(sourcelist, "Key", "Value", "drain");
View:
#Html.ListBoxFor(model => model.code, Model.codelist)
Output HTML:
<select data-val="true" data-val-required="The Select the permit type to apply for field is required." id="code" multiple="multiple" name="code"><option value="drain">Interior Drain Repair</option>
... yadda yadda yadda
</select>
You can see my two problems here. First, "multiple" has been added to the select list, and the selected option "drain" is not selected.
Any suggestions? I'm at the point of just tossing Razor and hand coding this stuff.
To create a single select list box you can use DropDownListFor but set a size attribute... so do this:
#Html.DropDownListFor(model => model.code,
Model.codelist,
new Dictionary< string, object >() { { "size", "3"} })
User Html.DropDownList instead of Html.ListBox to create a single select box.
Well, I've sort of got an answer to question one - turns out it's the browser that changes the rendering from simple list to dropdown list if "multiple" is removed, so I'm going to have to be creative to solve that one.
Question Two remains - why doesn't Razor keep my selected value during rendering?

ASP.NET MVC Filtering results in a list/grid

For some reason I'm stuck on this. I need to filter results from a View based on a DropDownList in the same view. The basic idea is this: I have a list of providers that belong to various partners, but the provider list contains ALL the providers together (for all partners). I need to be able to display the providers by partner when someone wants to see just that partner (otherwise, the default listing will be ALL providers). My view currently is the "default" (showing all), but for some reason Im sitting here staring at the monitor (for the last 2 hours!) trying to figure out how to filter these results.
Any suggestions where to start/how to do it?!
EDIT: If you want to do this with jQuery and AJAX (which will provide a better user experience because only the subdivisions list will refresh), see this tutorial.
If I understand correctly, you basically want to do a WebForms-style postback.
Let's say you have a control with countries and country subdivisions (e.g. states, provinces, etc). When the country changes, you want the appropriate subdivisions to display.
So this would be view:
<% using (Html.BeginForm()) { %>
<%=Html.DropDownList("Address.CountryId", new SelectList(Country.GetAll(), "Id", "Name"), new { onchange = "this.form.submit();" })%>
<%=Html.DropDownList("Address.CountrySubdivisionId", new SelectList(CountrySubDivision.GetByCountryId(Model.CountryId), "Id", "Name"))%>
<input type="submit" name="btnSubmit" value="Submit"/>
<%} %>
This is the key to getting the dependent list to filter:
new { onchange = "this.form.submit();" }
And in the controller, you'd have something like this:
[AcceptVerbs(HttpVerbs.Post)]
public ViewResult Index(string btnSubmit)
{
if (btnSubmit == null)
{
// return the view displayed upon GET
}
else
{
// process the submitted data
}
}
In the above code, if the form submission was triggered by changing the value in a dropdown, btnSubmit will be null. Thus, the action you are POSTing to can tell whether or not the user meant to finalize her changes.
To add upon the earlier answers.
To create a drop down (in ASP .NET MVC 3) I did the following:
Add code to Index.cshtml
#using (Html.BeginForm())
{
#Html.DropDownList("EmployeeId", (SelectList)ViewData["EmployeeId"])
<input type="submit" name="btnSubmit" value="Submit"/>
}
Add code to YourModelNameController.cs in the default ActionResult for Index()
public ActionResult Index()
{
//create a selectlist
var employeeList = from el in db.Employee select el;
ViewData["EmployeeId"] = new SelectList(employeeList, "EmployeeId", "TmName");
return View(modelName);
}
There are many ways to skin this cat. Here's one.
Enclose your DropDownList in a form with METHOD=GET.
<form action="" method="get">
<select name="provider">
<option>1</option>
<!-- etc -->
</select>
</form>
Then, in you controller, filter based on the value of provider that was passed in. Remember to treat it as a Nullable parameter so that you can have some kind of behavior when it's empty.
Without posting some of your current code, it's tough to get much more specific than that.
Let's assume that you're probably passing a model to the view and that model is a list or IEnummerable of partners. What you want to do is restrict the list. In order to do that add a drop down list in the view and fill it with some possible partners. This can be done either by putting a list in ViewData or expanding the model passed back to the view. Both have advantages. Now when you change the drop down reload the page but append a parameter which is the filter. In the controller check for that parameter in the action, if it isn't present then return an unfiltered list, if it is then apply a filter and return the list. The view will just dumbly display whatever you give it.
As for the filtering you might want to try using LINQ.
You probably want a parameter to your controller action, maybe a (nullable?) id of the provider, to filter the results already when you get them from DB. Then just use the same view to list them, and request a new list if the dropdownlist changes.
Best solution I know is that one.
http://gridmvc.codeplex.com/SourceControl/latest

Resources