7

I'm implementing check box list in MVC, although I succeed to get the desired result, I have a doubt in my approach:

public class AdditionalServicesModel
{
    public IList<SelectListItem> AdditionalServices { get; set; }
}

=========================================================================

public class HomeController : Controller
{
    //
    // GET: /Home/

    public ActionResult Index()
    {
        AdditionalServicesModel objAdditionalServicesModel = new AdditionalServicesModel();

        List<SelectListItem> services = new List<SelectListItem>();
        services.Add(new SelectListItem { Text = "service-1", Value = "1", Selected=false });
        services.Add(new SelectListItem { Text = "service-2", Value = "2", Selected=false });
        services.Add(new SelectListItem { Text = "service-3", Value = "3", Selected=false });
        objAdditionalServicesModel.AdditionalServices = services;

        return View(objAdditionalServicesModel);
    }

    [HttpPost]
    public ActionResult Index(AdditionalServicesModel result)
    {
        return RedirectToAction("Thanks", "Home");
    }

    public ActionResult Thanks()
    {
        return View();
    }
}

=========================================================================

@model checkboxes.Models.AdditionalServicesModel
@{
    ViewBag.Title = "Index";
    Layout = null;
}


@using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
    for (int i = 0; i < Model.AdditionalServices.Count; i++)
    {        
        <ul>
            <li>
                @Html.CheckBoxFor(m=>Model.AdditionalServices[i].Selected, new { id = "Chk-" + i})
                @Html.Label(Model.AdditionalServices[i].Text, new { @for = "Chk-" + i })
                @Html.HiddenFor(m => Model.AdditionalServices[i].Text)
                @Html.HiddenFor(m=> Model.AdditionalServices[i].Value)
            </li>
        </ul>
    }
    <input type="submit" value="POST to Controller" />
}

1) For one checkbox I should create 2 additional hidden fields. Is there a better approach? I feel like it just wrong to make all this long way just to send checkboxes values + names, It would be much easier to collect its values with javascript and send it via Json, but then I will not have an unobtrusive validation...

2) I send all check boxes while I need to send only selected boxes. Is there a way to do it with forms post?

3
  • You can still use validation, you just need to call validate on the form object before you try to send the selected options back to the server. Commented Aug 5, 2013 at 5:39
  • Did You mean unobtrusive validation that works both on client and server? Do you have an example for me? Commented Aug 5, 2013 at 5:47
  • you won't be able to use the same validation if you only post partial data back, unless you create a second model that has only the properties you want to return. It'll get a bit hairy doing it that way, though, because you'll have to keep the models in sync. Using a single model and posting all data back can be validated in both places using DataAnnotations with your model, which is part 2 in that link. The DataAnnotations are used in unobtrusive javascript, and there's a Modelstate.IsValid() function you call where the data gets posted. Commented Aug 5, 2013 at 5:57

1 Answer 1

4

Create a custom 'services check box item' class (reusable), and make a list or enumerable of them as a property in your AdditionalServicesModel. Also, its probably a better idea to create a constructor of the model so you don't have to assign the model properties inside the controller.

public class ServicesItem
{
     public bool Selected { get; set; }
     public string Value { get; set; }
     public string Text { get; set; }
}

public class AdditionalServicesModel
{
    public AdditionalServicesModel(IList<ServicesItem> items){
         this.AdditionalServices = items;
    }

    public IList<ServicesItem> AdditionalServices { get; set; }
}

Create a custom editor template for Additional Services, to easily reference in your view (you don't have to add a hidden for the text, as only the value and selected properties will be default binded back to the model:

  @Html.CheckBoxFor(m => Selected)
  @Html.LabelFor(m => Text)
  @Html.HiddenFor(m => Value)

Then pop the editor template into your view (let MVC.net do its magic - have a look at the markup to see what it does):

@Html.EditorFor(m => m.AdditionalServices)

Then inspect the automatically bound values in your controller:

    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            List<SelectListItem> services = new List<SelectListItem>();
            services.Add(new SelectListItem { Text = "service-1", Value = "1", Selected=false });
            services.Add(new SelectListItem { Text = "service-2", Value = "2", Selected=false });
            services.Add(new SelectListItem { Text = "service-3", Value = "3", Selected=false });

            return View(new AdditionalServicesModel(services));
        }

    [HttpPost]
    public ActionResult Index(AdditionalServicesModel result)
    {
         var selectedServicesList = result.AdditionalServices.Where(s => s.Selected);
         return RedirectToAction("Thanks", "Home");
    }
}
Sign up to request clarification or add additional context in comments.

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.