I'm not sure what I am doing wrong here, not even sure if I am on the right track. I have a view model and I create a drop down list from it. Here is my view model:
public class ApplicationViewModel
{
public Application Application { get; private set; }
public SelectList AccountTypes { get; private set; }
public ApplicationViewModel(Application application, IEnumerable<AccountType> accountTypes)
{
Application = application;
AccountTypes = new SelectList(accountTypes, "AccountTypeID", "AccountTypeName", application.AccountTypeID);
}
}
Here is my Create (get) action:
public ActionResult Create()
{
var viewModel = new ApplicationViewModel(new Application(), db.AccountTypes);
return View(viewModel);
}
And my view code:
<%: Html.DropDownListFor(???, Model.AccountTypes, "-- Select --") %>
<%: Html.ValidationMessageFor(???) %>
In the code above, I'm not exactly sure what must come in ??? The initial value is "-- Select --". If the user clicks on the submit button and the dropdown's value is still "-- Select --" then it must display a message.
I am also using EF4. Please can someone advise as to what to do. Code samples would be appreciated.
Thanks.
If your View is strongly typed ie:
Inherits="System.Web.Mvc.ViewUserControl<Model.NameSpace.ApplicationViewModel>"
Then the ??? in your view code should be a lambda expression referring to the items in your ViewModel. (I assume your ViewModel's Application object has a property that is going to be assigned a value based on the drop down list?)
I've assumed your application object has an AccountType property, For example:
??? should be something like:
<%= Html.DropDownListFor(x => x.Application.AccountType, Model.AccountTypes) %>
The value from the drop down list will populate the AccountType property on your Application model and will be populated with the AccountTypes from your ViewModel.
Hope this helps.
-- EDIT --
On your Application model, use the namespace:
using System.ComponentModel.DataAnnotations;
Above your AccountTypes property, add
[Required(ErrorMessage="Account Type Required")]
I think this should work.
Related
I have two tables, Location and Job
When I want to create a new job, I can select the location from a drop down list which is populated from the location table.
My create view:
public ActionResult Create(CreateJobViewModel model)
{
model.Locations = repository.GetAllLocations()
.Select(x => new SelectListItem { Text = x.State, Value = x.LocationId.ToString() })
.ToList();
return View(model);
}
and my view model:
public class CreateJobViewModel
{
public Job Job { get; set; }
public IList<SelectListItem> Locations { get; set; }
public int SelectLocationId { get; set; }
}
This all works fine, but how do i get the selected value from the drop down box and then save that value in the foreign key field of the Job table?
My post action looks like this:
[HttpPost]
[Authorize(Roles = "Employer")]
[ValidateAntiForgeryToken]
public ActionResult Create(Job job)
{
repository.AddJob(job);
return RedirectToAction("Create");
}
The post action uses Job entity and the get action uses CreateJobViewModel, during my previous projects, I only either do create or I display, I never come into a situation like this.
I am thinking something of passing the model between views???
and in my create view, I don't know which model i should use, the view model "CreateJobViewModel" or "Job" entity?
#model foo.CreateJobViewModel
or
#model foo.Job
How can I link the two models???
Here is some code of mine, similar to your problem, you can modify it by your requirements. Hope it helps.
Controller:
public ActionResult Create()
{
string selected = (from cat in dc.Category
join sub in dc.SubCategory on cat.Id equals sub.SubCategoryId
select cat.Name).First();
ViewBag.Category = new SelectList(dc.Category, "Id", "Name", selected);
var model = new SubCategory();
return View(model);
}
View:
<div> Category:</div>
<div>
#Html.DropDownListFor(model => model.CategoryId, (IEnumerable<SelectListItem>)ViewBag.Category,
new { #class = "form-control" })
</div>
You should use view model in the create and then use custom mapping logic to make Job entity and send to your business or data layer.
You can use Auto mapper for mapping between the entities.
You are thinking about this wrong. Why do you have a Job view model and a Job business object?
Your view should only know about the view model, your controller should (how you have this setup) knows about both the view model and business model, and the repository only knows about the business model.
Have the Post action return a Job View Model. Then convert the View Model to a model in the controller and pass to the repository.
There are several ways you could do this, doing this by hand in the controller, doing this in the constructor of the business object, or utilizing an automapper.
My preference is to create a new constructor for the business object that accepts a view model and copy the properties over that I need (and I do it from model to view model as well).
I have a ViewModel like this:
public class MyViewModel
{
public string SelectedItem { get; set; }
public List<MyClass> Items { get; set; }
}
I fill these items on screen with a #Html.DropDownListFor(m => m.SelectedItem, new SelectList(...)).
Ok, but when I call any action which receives this ViewModel, I got this collection empty.
Is there a way to get back the DropDownList values when I call any action?
That's a normal behavior and it's how HTML works. Only the selected value of a <select> element is sent to the server, not the entire collection. In your POST action if you want to retrieve the collection all you have to do is exactly the same you did in your GET action to retrieve it in the first place. That's usually a database call. And if you are afraid that you might be hitting your database quite often, just cache the collection.
In a tag form you can only send the value selected in the tag select, in this case the value of SelectedItem.
If you need also send the list of values of Items, you have to create something like this:
#{
var ind = 0;
foreach(var item in Model.Items)
{
<input type="hidden" name="Items[#ind].Id" value="#item.Id"/>
ind++;
}
}
But id you can send the data by Ajax, in this case is mode simple, because you can create the data to send. See this plugin toDictionary
One way is to have the List<SelectListItem> as part of the view model and populate it via a method called from the controller and pass it to the view, e.g.
View model:
public List<SelectListItem> SelectList { get; set; }
And in the view:
#Html.DropDownListFor(model => model.SelectedItem, Model.SelectList)
I'm fairly new to ASP.NET MVC and am trying to work out the best way to do this. It's probably simple but I just want to do things correctly so I thought I'd ask.
Lets say I have a model that is this:
Task - Id, Description, AssignedStaffMember
StaffMember - Id, FirstName, LastName
and in my view I want to create a new task. I make a strongly typed Razor view, and can use EditorFor to create textboxes for Description but what about AssignedStaffMember?
I want a drop down list of all current staff and have the option of selecting one, then this gets submitted to an action method which is
NewTask(string description, StaffMember assignedStaffMember)
either that or I could have an int for staffId instead of the StaffMember object and look it up in the action method.
What is the best way to do this? I need to go to the database to get the list off staff, so here's what I thought:
Make a partial view for the listing of staff drop down, which will be used a few times and use #Html.Action("ListStaff", "Staff") to call it. The action method then has
public ActionResult ListStaff()
{
IEnumerable<StaffMember> model = _serviceLayer.GetAllStaff();
return PartialView(model);
}
However I'm not sure on how this will work with model binding, my understanding is that it has to have the correct name for the form to submit it, I'd need to pass the name to the partial view to put on the element I guess?
Instead of having it call a controller to get the staff, make a ViewModel that contains my Task and a IEnumerable possibleStaff collection. possibly send this information to a partial view.
a Html Helper ?
EditorFor could somehow be used?
which one (or is there more) would be best? and how would I do the model binding?
Here is one way to do this. Create a TaskDetailsViewModel
public class TaskDetailsViewModel
{
public TaskDetailsViewModel()
{
this.Task = new Task();
this.StaffMembers = new List<StaffMember>();
}
public Task Task { get; set; }
public IEnumerable<StaffMember> StaffMembers { get; set; }
}
In Controller
public ActionResult Edit(int id)
{
var task = taskRepository.GetTaskByID(id);
var taskDetailsViewModel = new TaskDetailsViewModel();
// Populate taskDetailsViewModel from task and staff
return View(taskDetailsViewModel);
}
[HttpPost]
public ActionResult Edit(TaskDetailsViewModel taskDetailsViewModel)
{
if (ModelState.IsValid)
{
taskRepository.Save(taskDetailsViewModel.Task);
}
else
{
// Show Error
}
return View(taskDetailsViewModel);
}
In View (bound strongly to TaskDetailsViewModel)
#Html.DropDownListFor(model => model.Task.AssignedStaffMember, new SelectList(Model.StaffMembers, "ID", "FirstName", Model.Task.AssignedStaffMember))
#Html.ValidationMessageFor(model => model.Task.AssignedStaffMember)
I am trying to work with an HTML.DropDownList in MVC and am not getting the expected return values. Here is my implementation for the selectList to bind to the drop down -
IEnumerable<status> stat = _provider.GetAllStatuses();
Statuses = new SelectList(stat.ToList(), "id", "name", i.status.id);
And here is my view -
<%= Html.DropDownList("Status",Model.Statuses) %>
I am getting an error when trying to run updatemodel in my controller. I then tried to individually set each object. It turns out that I am not getting a single int from the formvalue as I would expect to. Instead, I am getting a value like "5,10,2,3". I think this is coming from how I set up my selectlist, but I'm not exactly sure. Can anyone see an error in the way I am setting up this dd?
Thanks for any help, and let me know if I can clarify anything.
What does the signature of the post method look like? It (or the model) should have a Status property that's defined as an int. I suspect that you've got more code than you're showing us that is listing all the potential statuses on the page (hidden fields?) and that's what you are seeing posted back as an array of ints.
It should look something like:
public ActionResult PostAction( int status, .... )
{
... status will contain the selected value from the dropdown ...
}
This is how I am doing it:
var stat = _provider.GetAllStatuses();
myViewDataObject.Statuses = new SelectList(stat, "id", "name", i.status.id);
stat is an IEnumerable. Statuses is of type SelectList. You don't need ToList() if you are returning an IEnumerable or IQueryable from your provider.
My view inherits from
System.Web.Mvc.Viewpage<MyProject.Models.MyViewDataClass>
which looks like this:
class MyViewDataClass
{
public int StatusID { get; set; }
public SelectList Statuses { get; set; }
}
In the controller, I am accepting a FormsCollection object, and using the model binder to update it:
public ActionResult Edit(FormCollection collection)
{
var myViewDataObject = new MyViewDataClass();
UpdateModel(myViewDataObject);
}
More info at http://nerddinnerbook.s3.amazonaws.com/Part6.htm
Am using strongly typed view to show a complex object in a data entry/edit form. for eg: Model.UserInformation.Name, Model.LivingPlace.FacilitiesSelectList, Model.Education.DegreesList... etc. These information are shown in multiselect listbox, grids.. etc. User can change the information in the edit screen. Is there any way to post the Model object with user changes to controller on sumbit button click. Please suggest.
Regards,
SHAN
The same object instance that has been passed to the view: No. ASP.NET MVC uses a default Model binder to instantiate new action parameters from request values. So for example if you had the following action method:
public ActionMethod DoWork(User model)
{
return View();
}
public class Address
{
public string Street { get; set; }
}
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Address[] Addresses { get; set; }
}
the binder will look in the request and try to bind model values. You could to the following in your View:
<%= Html.TextBox("FirstName") %>
<%= Html.TextBox("LastName") %>
<%= Html.TextBox("Addresses[0].Street") %>
<%= Html.TextBox("Addresses[1].Street") %>
This will automatically populate the values of your model in the controller action.
To avoid mass assignment of properties that shouldn't be bound from request values it is always a good idea to use the BindAttribute and set Exclude or Include properties.
Use <input type="text" name="UserInformation.Name"><input> to bind to subobjects.