0

New to MVC.NET (and C# generally...and developing generally) and trying to my head around ViewModels. I've got a pretty basic requirement. I have Actor, UseCase and Project entities. To create a new UseCase I want a view with a DropDownListFor the Actors that are in the same Project as the UseCase. The project id is in the URL. I've been following this How to bind a selectlist with viewmodel? but I'm getting stuck with an error:

DataBinding: 'System.Web.Mvc.SelectListItem' does not contain a property with the name 'ActorId'.

Also, I don't really know exactly how to do the mapping in my POST method - I'm happy to do this manually for now without AutoMapper.

ViewModel:

 public class UserGoalsStepViewModel
{
    public enum GoalLevel
    {
        Summary, UserGoal, SubGoal,
    }

        public int ProjectId { get; set; }
        public int ActorId { get; set; }
        public SelectList ActorList { get; set; }
        public string Title { get; set; }
        public GoalLevel Level { get; set; }

        public UserGoalsStepViewModel ()
        {

        }


}

UPDATED: Controller: Has been updated to reflect changes discussed in comments below.

What's happening: 1. Model is correctly populated when the view is created in the GET (values for ProjectId, Level and ActorList are right, actorId is '0' and Title is null. All as expected. 2. On the POST though, Title gets set to "5" (which is the actually the Id of the selected actor, ActorId = 0 still, Level gets the correct value and ProjectId loses its value. So, obviously I need to do something with the SelectList definition but I'm not sure why the ProjectId is getting lost?

// GET: UseCases/Create
    public ActionResult Create(int id)

    {

        ViewBag.projectId = id;

        //Populate the ViewModel
        UserGoalsStepViewModel model = new UserGoalsStepViewModel()
        {
            ProjectId = id,
            ActorList = new SelectList(db.Actors.Where(a => a.projectID == id), "id", "Title"),

        };

        return View(model);
    }

    // POST: UseCases/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]
    public ActionResult Create([Bind(Include = "ProjectId,ActorId,Title,Level")] UserGoalsStepViewModel model, int id)
    {

        ViewData["Actors"] = new SelectList(db.Actors.Where(a => a.projectID == id), "id", "Title");


        if (ModelState.IsValid)
        {

            //Create a use case object to map to, which can then be saved in the DB

            UseCase uc = new UseCase();
            uc.ProjectID = model.ProjectId;
            uc.ActorID = model.ActorId;
            uc.Level = (Level)model.Level;
            db.SaveChanges();
            return RedirectToAction("Index", new { id = model.ProjectId });
        }

        return View(model);
    }

View:

@Html.DropDownListFor(model => model.Title, new SelectList(Model.ActorList, "ActorId", "Title"), new { @class = "form-control" })

2 Answers 2

2

Try:

@Html.DropDownListFor(model => model.Title, Model.ActorList, new { @class = "form-control" })

instead of:

@Html.DropDownListFor(model => model.Title, new SelectList(Model.ActorList, "ActorId", "Title"), new { @class = "form-control" }

The problem is that you were trying to create a Selectlist in the DropDownListFor, but Model.ActorList already is a SelectList.

There are potentially other problems in the code, but that should get you past that particular error.

UPDATE

The Controller method that you POST to should look something like this:

public ActionResult Create(UserGoalsStepViewModel model)
{
    // what are we updating? assume it's a project
    var p = from db.Projects.Where(x => x.Id == model.id;

    p.SomeProperty = model.SomeProperty;
    db.SaveChanges();
}

NB- I've removed some of the additional checking for the sake of brevity - obv you'll want to add in the binding restrictions, modelstate checks, null checks etc.

UPDATE 2

When you POST the data, Title=5 because the Title control is your selectlist, and 5 is the selected value. ActorId = 0 because you probably don't have a form control that holds this value, same goes for ProjectId? Can't tell for sure without seeing the View code.

Sign up to request clarification or add additional context in comments.

6 Comments

Great, that's got the view loading a populating the DDL now :-)
Any advice on how the POST should look? I'm just after advice to get me through this the first time. Cheers.
Looks ok, although you don't need the int id parameter - you're already passing it in the model
Thanks Mark I'm just implementing this now, will feedback shortly
Hi Mark, I've updated original message with what I now have in my Create GET & POST - it's not working, I've given details of the errors. Thanks in advance
|
0

Here's what I do on the post.... Add a Post method to VM.

public class UserGoalsStepViewModel{  

  // in the ctor initiailze properites...

  public string SelectedValue {get;set;}
  public IEnumerable<SelectListItem> DDL {get;set;}

public void Post(){
    DoSomethingWith(SelectedValue)

}

This requires proper binding using strong type binding in View...

@model UserGoalStepViewModel
@Html.DropDownListFor(x=>model.SelectedValue, model.DDL)

Controller (action method for post)

[HttpPost]
public ActionResult(UserGoalsStepViewMdoel vm){
      if(ModelState.IsValid){
             vm.Post();
             ModelState.Clear(); // if you want to show changed properties in view.

       }
       return View(vm);
}

One last thing, make sure everything you want to be posted back to controller is inside the BeginForm... MVC has this habit of just giving you what you post back to the strongly type controller action method, if you don't get everyting inside of the BeginForm it will look like "lost data"...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.