Search code examples
c#asp.net-mvcasp.net-corerazor-pageshtml-helper

Using ViewBag with @Html.CheckBoxFor rather than "plain" <input type= "checkbox">


Having already used @Html.CheckBoxFor within a View, I plan to use with the former Tag Helper in conjunction to ViewBag within the same View to circumvent few errors (e.g. variable definition):

MODEL

   public class test
    {
      public int ItemID { get; set; }
      public string ItemName { get; set; }
      public bool IsAvailable { get; set; }
    }

CONTROLLER

List<test> ItemList = new List<test>();
         ItemList.Add(new test {ItemID=1, ItemName="apple", IsAvailable = false});
         ItemList.Add(new test {ItemID=2, ItemName="mango", IsAvailable = false});
         ItemList.Add(new test {ItemID=3, ItemName="stuck", IsAvailable = false});
         ItemList.Add(new test {ItemID=4, ItemName="blocked", IsAvailable = false});
         ItemList.Add(new test {ItemID=5, ItemName="help:(", IsAvailable = false});
         ViewBag.ItemList = ItemList;

VIEW

<table>
      @foreach (var item in ViewBag.ItemList)
           {
            <tr><td>
           <input type= "checkbox" id = "Check_@item.ItemID" checked="@item.IsAvailable" 
           onclick="CheckOnlyOneCheckBox(this);"/>
           <label for="Check_@item.ItemID">@item.ItemName</label>
           </tr>
           }
 </table>

2 main issues have been encountered:

(a) Value of the selected box could not retrieved from a submit button using

   foreach (var item in ViewBag.ItemList)
         {
           if (item.IsCheck)
              {
                var zz = item.ItemName;
               }                     
          }     

(b) format of the displayed ItemName using <input type= "checkbox"> look slightly different (e.g. bold font) than the ones obtained from a previous checkbox list using @Html.CheckBoxFor.

Thus any assistance in using @Html.CheckBoxFor with ViewBag would highly be appreciated.

EDIT

@Md Farid Uddin Kiron

The main issue lies on the fact that a checkbox list has already been defined (in the same same View) via:

List<test> chk = new List<test>();
          chk.Add(new test() {ReferalTypeId=1, ReferalTypeName = "box1",
IsReferalCheck=false});
          chk.Add(new test() {ReferalTypeId=2, ReferalTypeName = 
"box2", IsReferalCheck=false});
          chk.Add(new test() {ReferalTypeId=3, ReferalTypeName = 
"Other", IsReferalCheck=false});

 CtrList chklist = new CtrList(); // Ctrl being a public class defined 
                                 // in MODEL
 chklist.reflist = chk;  
 return View(chklist);

Empirically I've ended up to a situation, where I could not define within public IActionResult Index() another checkbox list returning something else than chklist since the variable (e.g. list) won't be defined while looping it from View.

As a result I had to use, as a way around: ViewBag, enabling me to pass variable from Model to View without any problem. Without binding it, this effective way around has been raising another issue and the solution of last resort I am investigating consists of:

(a) looping through the checkbox;

(b) identifying the selected value via ViewBag;

(c) then finding a way to pass the selected variable from View to Controller. However, I had to concede that this latter approach looks sub-optimal.

Best


Solution

  • I have researched a lot on your scenario. The way you planned it cannot execute well because we cannot set htmlAttributes on CheckBoxFor so in this way we cannot retrive value from the from CheckBoxFor as you might know to get value from submitted item we need to set htmlAttributes on it like id class or name

    So considering your scenario the easiest solution I have founded for you like below:

    Your Predefined Model:

    public class CheckBoxTestModel
        {
            public int ItemID { get; set; }
            public string ItemName { get; set; }
            public bool IsAvailable { get; set; }
        }
    

    View Model To Lead Check On View:

     public class CheckBoxFromViewBagModel
        {
            public List<CheckBoxTestModel> CheckBoxes { get; set; }
            
        }
    

    Controller On Load:

     public IActionResult CheckboxforFromViewBag()
            {
                var checkBoxList = new List<CheckBoxTestModel>()
                {
                    new CheckBoxTestModel() { ItemID=1,ItemName="apple", IsAvailable = false },
                    new CheckBoxTestModel() { ItemID=2,ItemName="mango", IsAvailable = false },
                    new CheckBoxTestModel() { ItemID=3,ItemName="stuck", IsAvailable = false },
                    new CheckBoxTestModel() { ItemID=4,ItemName="blocked", IsAvailable = false },
                    new CheckBoxTestModel() { ItemID=5,ItemName="help:(", IsAvailable = false },
    
    
                };
    
                var model = new CheckBoxFromViewBagModel();
                model.CheckBoxes = checkBoxList;
                return View(model);
            }
    

    View When Load CheckBox:

    @model CheckBoxFromViewBagModel
    @{
        ViewData["Title"] = "CheckboxforFromViewBag";
    }
    <h4>Load CheckBox From ViewModel & Submit value to Controller wtih Selected Value</h4>
    
    <hr />
    <style>
        table {
            font-family: arial, sans-serif;
            border-collapse: collapse;
            width: 100%;
        }
    
        td, th {
            border: 1px solid #dddddd;
            text-align: left;
            padding: 8px;
        }
    </style>
    @using (Html.BeginForm("SubmitValueFromCheckBoxList", "UserLog"))
    {
        <table class="table-bordered">
            <tr>
                <th>Item Name</th>
                <th>Is Checked</th>
    
            </tr>
    
            @for (int i = 0; i < Model.CheckBoxes.Count; i++)
            {
                <tr>
    
                    <td> @Model.CheckBoxes[i].ItemName</td>
                    <td> @Html.CheckBoxFor(r => Model.CheckBoxes[i].IsAvailable)</td>
                    @Html.HiddenFor(h => @Model.CheckBoxes[i].ItemID)
                    @Html.HiddenFor(h => @Model.CheckBoxes[i].ItemName)
    
                </tr>
    
            }
        </table>
        <br />
        <input id="Button" type="submit" value="Submit To Controller" class="btn btn-primary" />
    }
    

    Controller When Submit The Value:

            [HttpPost]
            public IActionResult SubmitValueFromCheckBoxList(CheckBoxFromViewBagModel checkBoxViewModel)
            {
                var checkBoxValueFromView = checkBoxViewModel;
                return Ok(checkBoxValueFromView);
            }
    

    Output:

    enter image description here

    Note: As per your scenario I think this would the eligant way to handle this. Other than either of the work around bring us another chanllenge. In my solution you can ignore the CSS part. Here the important and tricky part is @Html.HiddenFor(h => @Model.CheckBoxes[i].ItemID) @Html.HiddenFor(h => @Model.CheckBoxes[i].ItemName) sets htmlAttributes for us.

    I hope it would help you well.