Problems with .net mvc 4 razor Html.checkboxfor

sagesky36 picture sagesky36 · Sep 30, 2012 · Viewed 8.9k times · Source

I'm having two issues with the above subject line on its use.

I have two strongly typed models that I need to use in one View. The reason why I need two different models is because the data being read is coming from two different databases, so I needed to have an edmx (Entity Framework) data model for each one.

I simply want to bring in a dynamic list of "templates" & "guarantors". The number of items coming back can obviously change.

Issue 1: I want to set each checkbox to "checked" and set its name for the display. With this, I don't know if the syntax is correct or not the way I have it set up, even though the second one is not giving me a design time compile error.

Issue 2: The other issue I'm having is that I need to use a different model for each set of check boxes. But, when I set the model in the second set of check boxes, the first model is ignored (which makes sense because it's the last one).

How can I use each of the models successfully in the same View in order to set the check boxes up correctly?

Here is the code:

<tr>
                            <td colspan="5">
                                <b>@Html.Label("lbl_Templates", "Templates:")</b>
                            </td>
                        </tr>
                        <tr>
                            @model IEnumerable<PDFConverterModel.PDFTemplate>
                            @foreach (var item in Model)
                            {
                                <td>
                                    @Html.CheckBoxFor(model => true, item.TemplateName)
                                </td>
                            }
                        </tr>
                        <tr>
                            <td colspan="5">
                                <b>@Html.Label("lbl_Guarantor", "Guarantor(s):")</b>
                            </td>
                        </tr>
                        <tr>
                                @model IEnumerable<PDFConverterModel.tGuarantor>
                                @foreach (var item in Model)
                                {
                                    <td>
                                        @Html.CheckBoxFor(model => true, item.GuarantorFirstName + " " + item.GuarantorLastName)
                                    </td>
                                }
                        </tr>

btw, is the use of the Label set up correctly syntactically where the first parm is the ID of the Label and the second parm is the Value that is shown?

Part of the Solution: I'm almost there... I'm having an issue with getting the indexing of the properties that I want shown via the CheckBoxFor Html Helper on the View (which i haven't used before until now)...

If you could help me with this last part, I would so appreciate it...

You can see that I created the below ViewModel (the one I am working with is the ViewModelTemplate_Guarantors class).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PDFConverterModel;

namespace PDFConverterModel.ViewModels
{
    public class ViewModelTemplate
    {
        public int SelectedTemplateId { get; set; }
        public IEnumerable<PDFTemplate> Templates { get; set; }
    }

    public class ViewModelGuarantors
    {
        public int SelectedGuarantorId { get; set; }
        public IEnumerable<tGuarantor> Guarantors { get; set; }
    }

    public class ViewModelDepartment
    {
        public int SelectedDepartmentId { get; set; }
        public IEnumerable<Department> Departments { get; set; }
    }

    public class ViewModelTemplate_Guarantors
    {
        public int SelectedTemplateId { get; set; }
        public IEnumerable<PDFTemplate> Templates { get; set; }

        public int SelectedGuarantorId { get; set; }
        public IEnumerable<tGuarantor> Guarantors { get; set; }
    }
}

Below is the Business code method I created in a separate DLL within the client project that populates the Model.

public ViewModelTemplate_Guarantors SelectViewModelTemplate_Guarantors(int LoanId, string LoanTypeId, int DepartmentId)
        {
            try
            {
                var model = new ViewModelTemplate_Guarantors();

                using (PDFService03Entities DbContext1 = new PDFService03Entities())
                {

                    DbContext1.Database.Connection.Open();

                    IEnumerable<PDFTemplate> temps = DbContext1.PDFTemplates.Where(p => p.LoanTypeId == Convert.ToInt32(LoanTypeId) && p.DepartmentId == DepartmentId).FromCache(CachePolicy.WithSlidingExpiration(TimeSpan.FromSeconds(30)));

                    model.Templates = temps.Select(x => new PDFTemplate
                    {
                        TemplateId = x.TemplateId.ToString(),
                        TemplateName = x.TemplateName
                    });
                }

                using (VisionEntities DbContext2 = new VisionEntities())
                {
                    DbContext2.Database.Connection.Open();

                    IEnumerable<tGuarantor> guars = DbContext2.tGuarantors.Where(p => p.ApplicationNum == LoanId).FromCache(CachePolicy.WithSlidingExpiration(TimeSpan.FromSeconds(30)));

                    model.Guarantors = guars.Select(x => new tGuarantor
                    {
                        ApplicationNum = x.ApplicationNum,
                        GuarantorFirstName = x.GuarantorFirstName,
                        GuarantorLastName = x.GuarantorLastName
                    });
                }

                return model;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

Below, is part of the Contoller Action method that calls the above code:

ViewModelTemplate_Guarantors tg = db.SelectViewModelTemplate_Guarantors(Convert.ToInt32(loanID), loanType, Convert.ToInt32(selectedVal));

Below is where I'm having my problem in the View...

Since I'm passing back an IEnumerable object, if I was able to send attachments here, I have 4 screen shots that show how I'm using my View.

Suffice it to say, that the screenshots clearly show that the Templates & Guarantors show up. They both are of type IEnumerable ViewModelTemplate_Guarantors.Templates and .Guarantors respectively.

I simply want to put in the index of the item that is coming back, but am getting a design time compile error of:

"Cannot apply indexing with [ ] to an expression of type 'System.Collections.Generic.IEnumerable" and tGuarantor respectively.

Call it 101 programming, unless I'm burned out on working on this, but I should be able to apply an index variable for the above collection to get the respective item back, unless I've completely forgot something....

What am I doing wrong below???

Here is my View:

@model IEnumerable<PDFConverterModel.ViewModels.ViewModelTemplate_Guarantors>
@{
    ViewBag.Title = "BHG :: PDF Generator";
    int ctr = 0;
}
<h2>@ViewBag.Message</h2>

<form id="form1" runat="server">
    <div>
        <table>
            <tr>
                <td>
                    <table style="width: 1000px">
                        <tr>
                            <td colspan="5">
                                <img alt="BHG Logo" src="~/Images/logo.gif" />
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <label for="txtLoanID">Loan ID :</label>
                            @(Html.Kendo().IntegerTextBox()
                                        .Name("txtLoanID")
                                        .Placeholder("Enter LoanID")
                                )

                            <td colspan="3">
                                <input type="submit" id="btnRefresh" value='Refresh' />
                            </td>
                        </tr>
                        <tr>
                            <td><@Html.Label("lblLoanType1", "Loan Type : ")</td>
                            <td><@Html.Label("lblLoanType2", "SBA")</td>
                            <td></td>
                            <td>
                                <label for="ddlDept">Department:</label>
                                @(Html.Kendo().DropDownList()
                                      .Name("ddlDept")
                                      .DataTextField("DepartmentName")
                                      .DataValueField("DepartmentID")
                                      .Events(e => e.Change("Refresh"))
                                      .DataSource(source =>
                                      {
                                          source.Read(read =>
                                          {
                                              read.Action("GetDepartments", "Home");
                                          });
                                      })
                                )
                            </td>
                        </tr>
                        <tr>
                            <td colspan="5">
                                <b>@Html.Label("lbl_Templates", "Templates:")</b>
                            </td>
                        </tr>
                        <tr>
                            @ctr = 0;
                            @foreach (var item in Model)
                            {
                                <td>
                                    @Html.CheckBoxFor(model => item.Templates[ctr].TemplateName)
                                    @ctr = ctr + 1;
                                    @Html.LabelFor(model => item.Templates[ctr].TemplateName)
                                </td>
                            }
                        </tr>
                        <tr>
                            <td colspan="5">
                                <b>@Html.Label("lbl_Guarantor", "Guarantor(s):")</b>
                            </td>
                        </tr>
                        <tr>
                            @ctr = 0;
                            @foreach (var item in Model)
                            {
                                <td>
                                    @Html.CheckBoxFor(model => item.Guarantors[ctr].GuarantorFirstName + " " + item.GuarantorLastName)
                                    @ctr = ctr + 1;
                                    @Html.LabelFor(model => item.Guarantors[ctr].GuarantorFirstName + " " + item.GuarantorLastName)
                                </td>
                            }
                        </tr>
                        <tr>
                            <td colspan="2"></td>
                            <td>
                                @*@using (Html.BeginForm("GeneratePDF", "Home", new { @loanID = loanID }, FormMethod.Post))
                                { 
                                    <input type="submit" id="btnGeneratePDF" value='Generate PDF' />
                                }*@
                            </td>
                            <td colspan="2"></td>
                        </tr>
                        <tr>
                            <td colspan="5">
                                <b>@ViewBag.Error</b>
                            </td>
                        </tr>
                    </table>
                </td>
            </tr>
        </table>
    </div>
</form>

<script type="text/javascript">

    $(document).ready(function () {
        $("#ddlDept").prepend("<option value='All' selected='selected'></option>");
    });

    var txtLoanID;

    $("#btnRefresh").click(function () {
        Refresh();
    });

    function Refresh() {

        var txtLoanID = $("#txtLoanID").val();

        if (txtLoanID != "") {
            $.post('/Home/Refresh', { loanID: $('#txtLoanID').val(), loanType: $('#lblLoanType2').val, selectedVal: $("#ddlDept option:selected").text() }, function (data) {
                data.success;
                if (data.success == true) {
                    if (data.templist == true) {
                        //show the templates
                        $("#lbl_Templates").visible = true;
                        $("#btnGeneratePDF").visible = true;
                    }
                    if (data.guarlist == true) {
                        //show the guarantors
                        $("#lbl_Guarantor").visible = true;
                        $("#btnGeneratePDF").visible = true;
                    }
                    if ((data.templist == true) && (data.guarlist == true)) {
                        $("#btnGeneratePDF").visible = true;
                    }
                    else {
                        $("#btnGeneratePDF").visible = false;
                    }
                }
                else {
                    $("#btnGeneratePDF").visible = false;
                    //hide the templates
                    $("#lbl_Templates").visible = false;
                    $("#btnGeneratePDF").visible = false;
                    //hide the guarantors
                    $("#lbl_Guarantor").visible = false;
                    $("#btnGeneratePDF").visible = false;
                }
            });
        }
        else {
            alert("Please enter a Loan ID.");
        }
    }

    $("#form1").validate({
        event: "submit",
        rules: {
            txtLoanID: {
                required: true
            }
        },
        messages: {
            txtLoanID: {
                required: ' Please enter a Loan ID. '
            }
        }
    });

</script>

Answer

Jeremy Bell picture Jeremy Bell · Sep 30, 2012

You can use Html.Checkbox instead of Html.CheckBoxFor if you really needed to accomplish task of creating a control for a value that does not exist in your model.

That allows you to specify the name, the value, and the IsChecked property programmatically.

Or, do as the other answer suggests and create a GarantorFullName property on your model.