How to create master-detail form using a ViewModel

2

I have a viewmodel in my project. Inside it I have two entities which are a list of items.

I'm doing the data-editing logic for these entities that are within the viewmodel . I have 5 entities in all. The ones that are not a list, I get the data in the fields in the view , now those that are list I can not. I can load the object and fill it, but I can not pass that data to the view .

The codes I have are:

    public ActionResult Edit(int? id)
    {
        CliCliente cliente = db.CliCliente.Find(id);
        AnaAnamineseAlimentar anamnese = db.AnaAnamineseAlimentar.Find(id);
        RecRecordatorio recordatorio = db.RecRecordatorio.Find(id);
        List<RefRefeicao> refeicao = anamnese.RefRefeicao; //db.RefRefeicao.Find(id);
        List<QfaQuestionarioFrequenciaAlimentar> qfa = anamnese.QfaQuestionarioFrequenciaAlimentar;//= db.QfaQuestionarioFrequenciaAlimentar.Find(id);

        for (int i = 0; i < qfa.Count; i++)
        {
            qfa[i].AnaId = anamnese.AnaId;
            qfa[i].AnaAnamineseAlimentar = anamnese;
        }

        for (int i = 0; i < refeicao.Count; i++)
        {
            refeicao[i].AnaId = anamnese.AnaId;
            refeicao[i].AnaAnamineseAlimentar = anamnese;
        }

        AnamineseViewModel viewModel = new AnamineseViewModel() 
        {
            CliCliente = cliente,
            AnaAnamineseAlimentar = anamnese,
            RecRecordatorio = recordatorio,
            RefRefeicao = refeicao,
            QfaQuestionarioFrequenciaAlimentar = qfa
        };

        return View(viewModel);
    }

In view :

@model NutriSport.Models.AnamineseViewModel

<div class="form-horizontal">
    <br />

    @Html.ValidationSummary(true, "", new { @class = "text-danger" })

    <table class="table">

        <tr class="success">
            <th>
                Tipo
            </th>

            <th>
                Horário/Local
            </th>

            <th>
                Alimentos/Quantidades
            </th>
        </tr>

        @for (int i = 0; i <= Model.RefRefeicao.Count; i++)
        {
            <tr class="success">

                <td>
                    @Html.TextBox(string.Format("RefRefeicao[{0}].RefTipo", i), null, new { @class = "form-control" })
                </td>

                <td>
                    @Html.TextBox(string.Format("RefRefeicao[{0}].RefHorarioLocal", i), null, new { @class = "form-control" })
                </td>

                <td>
                    @Html.TextArea(string.Format("RefRefeicao[{0}].RefAlimentosQuantidades", i), null,  new { @class = "form-control" })
                </td>
            </tr> 
        }
    </table>
</div>
    
asked by anonymous 20.06.2016 / 04:44

1 answer

2

Actually you can pass the data to View yes. The problem is different: you're trying to build a master-detail form and it's probably not getting the way you need to be.

The assembly principle is correct. You need to increase the intelligence of your code so that the form makes sense.

If it's a form, you need to write it down as one, that is:

@model NutriSport.Models.AnamineseViewModel

@using (Html.BeginForm())
{
    <div class="form-horizontal">
        <br />

        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        ... 

The next detail is how you write the form. You did it the way it is right, but unnecessarily laborious. Also, to work out the binding of this form, you would need to tell the binder that the current record is about index i . That is:

    @for (int i = 0; i <= Model.RefRefeicao.Count; i++)
    {
        <tr class="success">
            <input type="hidden" name="RefRefeicao.index" id="RefRefeicao_index" value="@i.ToString()" /> @* Isto aqui *@
            <td>
                @Html.TextBox(string.Format("RefRefeicao[{0}].RefTipo", i), null, new { @class = "form-control" })
            </td>

            <td>
                @Html.TextBox(string.Format("RefRefeicao[{0}].RefHorarioLocal", i), null, new { @class = "form-control" })
            </td>

            <td>
                @Html.TextArea(string.Format("RefRefeicao[{0}].RefAlimentosQuantidades", i), null,  new { @class = "form-control" })
            </td>
        </tr> 
    }

Once this is done, Model Binder correctly identifies its element as an object of the RefRefeicao aggregate class.

But, as I've said a few times, there is a component that solves this for you . I've talked about it many, many times . With it, you can assemble your list into the form as follows:

    @foreach (var refeicao in Model.RefRefeicao)
    {
        @Html.Partial("_Refeicoes", refeicao)
    }

In this case, you need to create a Partial that will have the following content:

_Refeicoes.cshtml

    @model NutriSport.Models.RefRefeicao

    @using (Html.BeginCollectionItem("RefRefeicao")) @* O nome precisa ser o mesmo que você definiu a List<RefRefeicao> no ViewModel *@
    {
        <tr class="success">
            <td>
                @Html.TextBoxFor(model => model.RefTipo), null, new { @class = "form-control" })
            </td>

            <td>
                @Html.TextBoxFor(model => model.RefHorarioLocal, null, new { @class = "form-control" })
            </td>

            <td>
                @Html.TextAreaFor(model => model.RefAlimentosQuantidades, i), null,  new { @class = "form-control" })
            </td>
        </tr> 
    }

The component creates index for you. You do not have to do anything else.

If everything has been done right, by sending your <form> to the Controller that receives AnamineseViewModel [HttpPost] , you will see that RefRefeicao will be properly populated.     

20.06.2016 / 05:14