2

I want to display a string type as checkbox on MVC view, but returns it as string type on HTTP post. The problem is that it returns false on HTTP Post. Below is my code:

View:

  @model List<Car>

        foreach(var car in Model){
       bool isFourWheel = false;
        if(bool.TryParse(car.IsFourWheel, out isFourWheel){
        @Html.CheckBox("IsFourWheel", isFourWheel); //need to be rendered as checkbox, but returns string type on HTTP POST
    }
     }

Model:

public class Car
    {
        public string IsFourWheel { get; set; } //bad naming, but it can contain any type, include boolean
    }

Controller:

 public ActionResult Index()
        {


            var cars = new List<Car>(){ new Car(){IsFourWheel = "true"},new Car(){IsFourWheel = "false"} };
            return View(cars);
        }

        [HttpPost]
        public ActionResult Index(List<Car> cars)  **Problem IsFourWheel is false when true is selected **
        {           
            return View(cars);
        }

Any ideal would be very much appreciated.

3 Answers 3

6

You can try specifying a template name in your helper:

@Html.EditorFor(car => car.IsFourWheel, "CheckBox")

And defining the template to render the data the way you want, in either ~/Views/{YourControllerName}/EditorTemplates/CheckBox.cshtml or ~/Views/Shared/EditorTemplates/CheckBox.cshtml.

You can find a whole series of post by Brad Wilson on MVC templates here:

Brad Wilson: ASP.NET MVC 2 Templates, Part 1: Introduction

It is for MVC 2, but most concepts still apply to MVC 3 as well (save for the Razor syntax).

Update:

Actually you probably don't need a custom template for this. Try using @Html.CheckBoxFor(car => car.IsFourWheel) instead.

Update 2:

Drop the following template in ~/Views/Shared/EditorTemplates:

IsFourWheel.cshtml

@functions {
    private bool IsChecked() {
        if (ViewData.Model == null) return false;
        return Convert.ToBoolean(ViewData.Model, System.Globalization.CultureInfo.InvariantCulture);
    }
}

@Html.CheckBox("", IsChecked(), new { @class = "check-box" })

Then from your view, call it like so:

@Html.EditorFor(model => model.IsFourWheel, "IsFourWheel")

I tested it and binding works in both GET and POST scenarios.

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

8 Comments

Thanks. Could you please elaborate on How to implement it on the CheckBox.cshtml.
For an example, you could take a look at the default template for boolean fields (what CheckBoxFor renders) in the MVC source code, for example Boolean.ascx, but as I said, unless you're doing something very specific with your IsFourWheels property, you probably don't need a template and can just use @Html.CheckBoxFor(car => car.IsFourWheel) instead.
Daniel Liuzzi, @Html.CheckBoxFor requires bool type.
@Pingpong Yes, my bad. I updated the answer with the template, which work as expected for boolean values stored as strings.
Thanks. I will use it and see if it works with my implementation.
|
1

You could alter your viewmodel like this:

public class Car
    {
        public string IsFourWheel { get; set; }
        public bool IsFourWheelBool { get { return bool.Parse(IsFourWheel); } }
    }

Your view would look like this:

@Html.EditFor(x => x.IsFourWheelBool);

3 Comments

that requires change of domain model, which is not the ideal one.
It's usually considered bad design to use your domain models in your views. (stackoverflow.com/questions/4865806/…) It's better to create viewmodels to facilitate your view. With a tool like automapper (automapper.org) it's easy to create viewmodels from domain models. But also creating viewmodels by hand is quite do-able.
Thanks. I knew that. My question is only a simplified example.
1

I think it will be easier, if you add an Id to your model. Just like this
Model:

public class Car
{
    public int CarID { get; set; }
    public string IsFourWheel { get; set; }        
}


View:

@model IEnumerable<Car>
foreach (var car in Model)
{
    if(car.IsFourWheel == "true"){
        <input type="checkbox" name="carID" value="@car.CarID" checked="checked" />
    }
    else
    {
        <input type="checkbox" name="carID" value="@car.CarID" />
    }
}

Controller:

[HttpPost]
public ActionResult Index(List<int> carID)
{
    //handle selected cars here
    return View();
}

2 Comments

Thank you for your advice. I updated my question. I have a collection of cars, which is needed on post. Your current solution can work for single car only.
When there are a collection of car, the input tag needs a id/name that allows the model binder to assign the value.

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.