Html.DropDownListFor returns null - asp.net-mvc

There are similar questions and I have tried most of them. Instead of continuing to destroy the remaining code while conjuring demons from the similar past questions, I have decided to ask for help.
When I arrive at the AddMembership action I get a null value instead of the selected item. Below are the details.
View;
#using (Html.BeginForm("AddMembership", "WorkSpace", FormMethod.Post, new { data_ajax = "true", id = "frmAddMembership" }))
{
<div id="newMembershipDiv">
#Html.DropDownListFor(m => m.selectedID, new SelectList(Model.allInfo, "Value","Text",1), "Select!")
<input type="submit" value="Add" name="Command" />
</div>
}
Controller (I just want to see the selectedID or anything appear here.);
public ActionResult AddMembership(SelectListItem selectedID)
{
return View();
}
Model;
public class SomeModel
{
public SelectList allInfo { get; set; }
public SelectListItem selectedID { get; set; }
}
The Monstrosity which initializes the allInfo SelectList
model.allInfo = new SelectList(synHelper.getall().ToArray<Person>().Select(r => new SelectListItem {Text=r.Name, Value=r.prID.ToString() }));
synHelper.getAll() returns a List of the below class;
public class Person
{
public Guid prID { get; set; }
public string Name { get; set; }
}

The only thing that is posted to your action is a selectedID, which is a simple string. If you wander, in the request it looks as simple as:
selectedID=1234
Therefore it should be awaited for as a simple string. Adjust your action parameter:
public ActionResult AddMembership(string selectedID)

Related

Pass model to controller

Im tryin to ceate a very simple blog. In my view i got this:
#using (Html.BeginForm("AddBlogPost", "Home")) <--Probably missing something here
{
foreach (var item in Model.BlogPost)
{
#Html.LabelFor(x=>item.Title)
#Html.TextBoxFor(x=>item.Title)
#Html.LabelFor(x=>item.Text)
#Html.TextBoxFor(x=>item.Text)
}
<input type="submit" value="Create Post" />
}
With the submit-button, im hoping to pass the two values to this controller:
public ActionResult AddBlogPost(BlogPost model)
{
BlogPost post = new BlogPost()
{
Title = model.Title,
Text = model.Text,
};
RavenSession.Store(post);
RavenSession.SaveChanges();
return RedirectToAction("Index");
}
Creating a new blogpost and saving it to the DB.
The problem is that the method receives null. Guess im missing somehting silly?
EDIT:
Im not longer passing a list of blogposts...:
#using (Html.BeginForm("AddBlogPost", "Home"))
{
#Html.LabelFor(Model.Title)
#Html.TextBoxFor(Model.Title)
#Html.LabelFor(Model.Text)
#Html.TextBoxFor(Model.Text)
<input type="submit" value="Create Post" />
}
This does not seem to be the right way...
EDIT 2: These are my two class:
public class ContentPage
{
public ContentPage()
{
Template = new RouteTemplate();
ParentReference = "";
Url = "/";
}
public string ParentReference { get; set; }
public RouteTemplate Template { get; set; }
public string Url { get; set; }
public bool ShowInMenu { get; set; }
public string Title { get; set; }
public string Id { get; set; }
public BlogPost BlogPost { get; set; }
}
Blog-class:
public class BlogPost
{
public string Title { get; set; }
public string Text { get; set; }
}
To the view I pass the COntentPage, which contains an instance of the Blog-post...I cant seem to access the blogpost in the way you are describing? Sorry for not being vlear from the start.
Bind you View with the BlogPost class and don't use foreach loop. See the following code.
#using (Html.BeginForm("AddBlogPost", "Home"))
{
#Html.LabelFor(x=>Model.Title)
#Html.TextBoxFor(x=>Model.Title)
#Html.LabelFor(x=>Model.Text)
#Html.TextBoxFor(x=>Model.Text)
<input type="submit" value="Create Post" />
}

BeginForm in ChildAction uses wrong id

There is something simple I don't understand with ChildActions.
I've created a simple View for a model, that loads a child action with a form.
The child action has another model than its parent, with a different id property.
Html.HiddenFor(m => m.Id) still outputs the parents id, although #Model.id outputs the correct value!
Can't I reliably use the Helper methods in ChildActions, or is this a known bug?
HomeController
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new Models.HomeModel { id = 1, message = "bugmodel" };
return View(model);
}
[HttpGet]
[ChildActionOnly]
public ActionResult Child(int id)
{
var model = new Models.HomeChildModel { id = 100, parentId = id, childMessage = "My Child message" };
return PartialView(model);
}
[HttpPost]
[ActionName("Child")]
[ValidateAntiForgeryToken()]
public ActionResult ChildPost(Models.HomeChildModel model)
{
return RedirectToAction("Index");
}
}
Models
public class HomeModel
{
public int id { get; set; }
public string message { get; set; }
}
public class HomeChildModel
{
public int id { get; set; }
public int parentId { get; set; }
public string childMessage { get; set; }
}
Home view
#model ChildActionBug.Models.HomeModel
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#Html.DisplayFor(m=>m.id)
#Html.DisplayFor(m=>m.message)
#Html.Action("Child", new { id = Model.id })
**Child view**
#model ChildActionBug.Models.HomeChildModel
<h3>Child here</h3>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.HiddenFor(m=>m.id)
#Html.HiddenFor(m=>m.parentId)
#Html.EditorFor(m=>m.childMessage)
<div>Child Model ID: #Model.id</div>
<button type="submit">Save</button>
}
Based on the answer given in the SO question I posted in the comment, you're better off explicitly creating the hidden fields
ASP.Net MVC Html.HiddenFor with wrong value
That's normal and it is how HTML helpers work. They first use the
value of the POST request and after that the value in the model. This
means that even if you modify the value of the model in your
controller action if there is the same variable in the POST request
your modification will be ignored and the POSTed value will be used.
So instead, hand craft the hidden fields:
<input type="hidden" name="Id" value="#Model.Id" />
<input type="hidden" name="ParentId" value="#Model.ParentId" />
<input type="hidden" name="ChildMessage" value="#Model.ChildMessage" />

Model with DropDownListFor SelectList not binding on the HttpPost

When I have the following code and I submit the form my post action shows the Contact object as null. If I remove the DropDownListFor from the view the Contact object contains the expected information (FirstName). Why? How do I get the SelectList value to work?
My classes:
public class ContactManager
{
public Contact Contact { get; set; }
public SelectList SalutationList { get; set; }
}
public class Contact
{
public int Id{get;set;}
public string FirstName{get; set;}
public SalutationType SalutationType{get; set;}
}
public class SalutationType
{
public int Id { get; set; }
public string Name { get; set; }
}
My view:
#model ViewModels.ContactManager
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.Contact.Id)
#Html.DropDownListFor(model => model.Contact.SalutationType.Id, Model.SalutationList, "----", new { #class = "form-control" })
#Html.EditorFor(model => model.Contact.FirstName)
<input type="submit" value="Save" />
}
My Controller:
public ActionResult Edit(int? id)
{
Contact contact = db.Contacts.FirstOrDefault(x => x.Id == id);
ContactManager cm = new ContactManager();
cm.Contact = contact;
cm.SalutationList = new SelectList(db.SalutationTypes.Where(a => a.Active == true).ToList(), "Id", "Name");
return View(cm);
}
[HttpPost]
public ActionResult Edit(ContactManger cm)
{
//cm at this point is null
var test = cm.Contact.FirstName;
return View();
}
You will pass the DropdownList using ViewBag:
ViewBag.SalutationList = new SelectList(db.SalutationTypes.Where(a => a.Active == true).ToList(), "Id", "Name");
than u have to call this list inside your edit view:
#Html.DropDownList("SalutationList",String.Empty)
The problem is that the DefaultModelBinder won't be able to map nested models properly if you use a different parameter name. You must use the same parameter name as the model name.
public ActionResult Edit(ContactManager contactManager)
As a general practice, always use the name of the model as the parameter name to avoid mapping problems.
Further Suggestion:
You can just use Contact as the parameter model, no need to use ContactManager if you only need the contact model.
[HttpPost]
public ActionResult Edit(Contact contact)
{
var test = contact.FirstName;
return View();
}

How do I get a strongly typed DropDownList to bind to a control Action

I've just started a new MVC project and I'm having trouble getting the post result from a form.
This is my Model Class :
public class User
{
public int id { get; set; }
public string name { get; set; }
}
public class TestModel
{
public List<User> users { get; set; }
public User user { get; set; }
public SelectList listSelection { get; set; }
public TestModel()
{
users = new List<User>()
{
new User() {id = 0, name = "Steven"},
new User() {id = 1, name = "Ian"},
new User() {id = 2, name = "Rich"}
};
listSelection = new SelectList(users, "name", "name");
}
}
This is my view class
#model MvcTestApplicaiton.Models.TestModel
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm())
{
#Html.DropDownListFor(x => x.user, #Model.listSelection)
<p>
<input type="submit" value="Submit" />
</p>
}
#if (#Model.user != null)
{
<p>#Model.user.name</p>
}
And this is my controller :
public class TestModelController : Controller
{
public TestModel model;
//
// GET: /TestModel/
public ActionResult Index()
{
if(model ==null)
model = new TestModel();
return View(model);
}
[HttpPost]
public ActionResult Test(TestModel test)
{
model.user = test.user;
return RedirectToAction("index", "TestModel");
}
}
The drop down list appears just fine but I can't see to get the ActionResult Test function to run. I thought it would just bind itself with reflection but whatever is wrong, I can't see it.
You have two main errors in your code.
As Brett said you're posting to the Index method, but you don't have Index method that supports POST verb. The easiest way to fix is to change Html.BeginForm() with Html.BeginForm("Test", "TestModel")
You're using Html.DropDownListFor in a wrong way. You could pass only a value types there, because don't forget that the View will generate an HTML page. So instead of User in your Model you should have an UserID and in your View you should have #Html.DropDownListFor(x => x.UserID, #Model.listSelection). And finally in your Action you should query your data source to get the details for the user with this ID.
Hope this helps.
Looks like you're posting back to index. Either use a GET Test() action method, or specify the ACTION parameter in BeginForm().
For example,
#using (Html.BeginForm("Test", "TestModel"))
{
#Html.DropDownListFor(x => x.user, #Model.listSelection)
<p>
<input type="submit" value="Submit" />
</p>
}
Or use a view named Test (rename index.cshtml to test.cshtml):
public ActionResult Test()
{
if(model ==null)
model = new TestModel();
return View(model);
}

How to pass an entire ViewModel back to the controller

I have a ViewModel that contains two objects:
public class LookUpViewModel
{
public Searchable Searchable { get; set; }
public AddToSearchable AddToSearchable { get; set; }
}
The two contained models look something like this:
public class Searchable
{
[Key]
public int SearchableId { get; set; }
public virtual ICollection<AddToSearchable> AddedData { get; set; }
}
public class AddToSearchable
{
[Key]
public int AddToSearchableId { get; set;}
[Required]
public int SearchableId { get; set; }
[Required]
public String Data { get; set; }
[Required]
public virtual Searchable Searchable { get; set; }
}
I have a view that uses my LookUpViewModel and receives input to search for a SearchableId. If the Searchable object is found, a LookUpViewModel object is created and passed to the View. The view then displays editor fields for AddToSearchable.Data. Once submitted, I want the LookUpViewModel to be passed to an action method to handle all the back-end code. The only problem is, the LookUpViewModel passed to my action method contains a null reference to Searchable and a valid reference to AddToSearchable.. i.e. I'm missing half of my data.
Here's an example of what my view looks like:
#model HearingAidTrackingSystem.ViewModels.LookUpViewModel
#using (Html.BeginForm("LookUp", "Controller", "idStr", FormMethod.Post))
{
<input type="text" name="idStr" id="idStr"/>
<input type="submit" value="Search" />
}
#if (Model.Searchable != null && Model.AddToSearchable != null)
{
using (Html.BeginForm("AddMyStuff", "Controller"))
{
Html.HiddenFor(model => model.Searchable.SearchableId);
Html.HiddenFor(model => model.Searchable.AddedData);
Html.HiddenFor(model => model.AddToSearchable.AddToSearchableId);
Html.HiddenFor(model => model.AddToSearchable.SearchableId);
Html.HiddenFor(model => model.AddToSearchable.Searchable);
<div class="editor-field">
#Html.EditorFor(model => model.AddToSearchable.Data)
#Html.ValidationMessageFor(model => model.AddToSearchable.Data);
</div>
<input type="submit" value="Submit" />
}
}
and here are my action methods:
public ActionResult LookUp(LookUpViewModel vm)
{
return View(vm);
}
[HttpPost]
public ActionResult LookUp(string idStr)
{
int id = /*code to parse string to int goes here*/;
Searchable searchable = dal.GetById(id);
LookUpViewModel vm = new LookUpViewModel { Searchable = searchable,
AddToSearchable = new AddToSearchable() };
//When breakpoint is set, vm contains valid references
return View(vm);
}
[HttpPost]
public ActionResult AddMyStuff(LookUpViewModel vm)
{
//**Problem lies here**
//Do backend stuff
}
Sorry for the lengthy post. I tried my best to keep it simple. Any suggestions you may have.. fire away.
Two methods to fix it:
You can add to do HiddenFor() for all properties of Model.Searchable.
You can use serialization to transfer your Model.Searchable into text presentation and repair it from serialized form in controller.
Update: The problem is: You need to use #Html.HiddenFor(), not Html.HiddenFor();.

Resources