Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to bind a selectlist with viewmodel?

I can't get a select list to bind to my ViewModel.

I have a ViewModel which contains a Question entity and a string

   public class QuestionViewModel
{
    public Question Question { get; set; }
    public string RefUrl { get; set; }

    public QuestionViewModel()
    {
    }

    public QuestionViewModel(Question question, string RefUrl)
    {
        this.Question = question;
        this.RefUrl = RefUrl;
    }

    public QuestionViewModel(Question question)
    {
        this.Question = question;
        this.RefUrl = "";
    }
}

this is the controller:

public ActionResult Edit(int id)
    {
        Question question = db.Question.Single(q => q.question_id == id);
        QuestionViewModel qvm = new QuestionViewModel(question);
        ViewBag.category_id = new SelectList(db.Category, "category_id", "category_name", qvm.Question.category_id);
        ViewBag.type_code = new SelectList(db.Question_Type, "type_code", "type_description", qvm.Question.type_code);
        return View(qvm);
    }

and the code in my view looks like this:

<div class="editor-label">
        @Html.LabelFor(model => model.Question.type_code, "Question_Type")
    </div>
    <div class="editor-field">
        @Html.DropDownListFor(model => Model.Question.Question_Type, (SelectList)ViewBag.type_code)
        @Html.ValidationMessageFor(model => model.Question.type_code)
    </div>

The View does set the Question entity's Question_Type to the selected value, but when i submit the form, the ValidationMessageFor triggers??

like image 715
Nanek Avatar asked Jul 08 '11 11:07

Nanek


1 Answers

What you have is not a view model. It's a hybrid class that you have called view model and in which you have wrapped your domain entity (Question). That's bad, don't do it.

Here's what I would recommend you. Start by designing a real view model which will reflect the requirements of your view (from your current description it's a dropdownlist containing some question types and allowing the user to select some question type from this ddl):

public class QuestionViewModel
{
    [DisplayName("Question_Type")]
    public string SelectedQuestionType { get; set; }

    public IEnumerable<SelectListItem> QuestionTypes { get; set; }

    // didn't see where you are using this on your view
    public string RefUrl { get; set; }
}

then have your controller map between your domain model and your view model. Of course a further improvement would be to use AutoMapper to avoid this mapping all over your controller actions:

public ActionResult Edit(int id)
{
    var question = db.Question.Single(q => q.question_id == id);
    var qvm = new QuestionViewModel
    {
        // preselect a value
        SelectedQuestionType = question.type_code,
        QuestionTypes = db.Question_Type.Select(x => new SelectListItem
        {
            Value = x.type_code,
            Text = x.type_description
        })
    };
    return View(qvm);
}

and then:

<div class="editor-label">
    @Html.LabelFor(x => x.SelectedQuestionType)
</div>
<div class="editor-field">
    @Html.DropDownListFor(
        x => SelectedQuestionType, 
        new SelectList(Model.QuestionTypes, "Value", "Text")
    )
    @Html.ValidationMessageFor(x => x.SelectedQuestionType)
</div>

And one final remark: make sure you have gotten rid of any ViewBag/ViewData ugliness and put anything your view needs into the view model. You have shown some categories over there in your controller action which weren't materialized in the view snippet you have shown. If you ever needed them simply put them in your view model, the same way we did with the question types.

like image 59
Darin Dimitrov Avatar answered Oct 14 '22 01:10

Darin Dimitrov