How to Include an Item in a Icollection

Asked

Viewed 308 times

2

I have a class Person who has a ICollection telephone class. On the Person maintenance screen I have a datatable with the Phones. There is a link to add a new phone, but I can’t use the @Html.DropDownLIstFor to ask for the type of phone (commercial, residential, mobile).

I’ll try to be succinct.

public partial class PessoaModel
{
        public Guid PessoaID { get; set; }
        public string Nome { get; set; }
        public virtual ICollection<TelefoneModel> Telefone { get; set; }
}
    public partial class TelefoneModel
    {
        public Guid TelefoneID { get; set; }
        public string DDD { get; set; }
        public string Numero { get; set; }
        public string TipoTelefone { get; set; }
        public Guid PessoaID { get; set; }
    }

And my view is this way:

@model GeoArea.Models.ViewModel.PessoaViewModel

<div class="panel panel-default" id="ITelefones">
    <div class="panel-heading">
        <h3 class="panel-title">Telefones</h3>
    </div>
    <div class="panel-body">
        <table id="tbTelefonePessoa" class="table table-striped table-hover">
            <thead>
                <tr>
                    <th>Tipo</th>
                    <th>Telefone</th>
                    <th>Opções</th>
                    <th></th>
                </tr>
            </thead>
            <tbody></tbody>
        </table>

        <div style="text-align:end">
            <a href="#" onclick="AcrescentarFone()">acrescentar  telefone</a>
        </div>
        <div id="acrescfone" class="hidden">
            @Html.ValidationSummary(true, "", new { @class = "text-danger" })
            <div class="form-group">
                <div class="col-md-6">
                    @Html.Label("Tipo", htmlAttributes: new { @class = "control-label" })
                    <div>
                        @Html.EditorFor(model => model.Telefone.FirstOrDefault().TipoTelefone.Nome, new { htmlAttributes = new { @class = "form-control" } })
                        @Html.ValidationMessageFor(model => model.Telefone, "", new { @class = "text-danger" })
                    </div>
                </div>
                <div class="col-md-6">
                    @Html.Label("Telefone", htmlAttributes: new { @class = "control-label" })
                    <div>
                        @Html.EditorFor(model => model.Telefone.FirstOrDefault().Numero, new { htmlAttributes = new { @class = "form-control" } })
                        @Html.ValidationMessageFor(model => model.Telefone, "", new { @class = "text-danger" })
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>


<script type="text/javascript">
    $(document).ready(function () {
        var ex = document.getElementById('tbTelefonePessoa');
        if ($.fn.DataTable.fnIsDataTable(ex)) {
            $(ex).dataTable().fnClearTable();
            $(ex).dataTable().fnDraw();
        }
        oTelefonePessoa = $('#tbTelefonePessoa').DataTable({
            "bAutoWidth": false,
            "dom": '<"hidden"f><"hidden"l><"hidden"i><"hidden"p>t',
            "bPaginate": false,
            "bProcessing": true,
            "bStateSave": false,
            "bLengthChange": false,
            "sSearch": false,
            "destroy": true,
            "bServerSide": false,
            "bSort": true,
            "iDisplayLength": 10,
            "order": [[0, "asc"]],
            "language": {
                "url": ROOT + "Content/resources/Portuguese-Brasil.json"
            },
            "columnDefs": [
                {
                    'targets': 1,
                    "mData": 0,
                     mRender: function (data, type, row) {
                         var fone = row["Numero"];
                         fone = '(' + row["DDD"] + ') ' + fone.substr(0,(fone.length - 4)) + '-' + fone.substr((fone.length - 4),4);
                        return fone;
                    }
                },
                {
                    'targets': 2,
                    mRender: function(){
                        return '<a class="glyphicon glyphicon-edit">alterar</a>' + '   ' +
                               '<a class="glyphicon glyphicon-remove">excluir</a>';
                    }
                }
            ],
            "columns": [
                { "data": "TipoTelefone.Nome" },
                { "data": "DDD" },
                { "data": "Numero" }
            ]
        });

        var data = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.Telefone));
        if (data.length > 0) {
            $("#tbTelefonePessoa").dataTable().fnAddData(data);
        }
    });

    function AcrescentarFone(){
        $("#acrescfone").removeClass("hidden");
    };
</script>

inserir a descrição da imagem aqui I don’t necessarily need to use the datatable but I found the easiest one. Have any suggestions?

  • Try to improve your question, perhaps by providing snippets of code that you have already touched.

  • Do you necessarily need to use jQuery Datatables? Or you can replace it with something else?

2 answers

4


You can use the Begincollectionitem to accomplish this. I answer this a few times here.

To use it you must install the package via Nuget with the following command:

Install-Package Begincollectionitem

After that, we’ll add a Action in your controller to add a new phone to Pessoa, thus:

public ActionResult GetNewTelefone()
    {
        var telefone = new Telefone
        {
            TelefoneId = Guid.NewGuid()
        };

        return PartialView("_Telefone", telefone);
    }

This way we are creating a new phone and returning the same in a PartialView, that you can do so:

@model WebApplication1.Models.Telefone


@using (Html.BeginCollectionItem("Telefones"))
{
    <div class="form-group">
        @Html.HiddenFor(model => model.TelefoneId)
        @Html.LabelFor(model => model.DDD, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-4">
            @Html.EditorFor(model => model.DDD, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.DDD, "", new { @class = "text-danger" })
        </div>
        @Html.LabelFor(model => model.Numero, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-4">
            @Html.EditorFor(model => model.Numero, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Numero, "", new { @class = "text-danger" })
        </div>
    </div>

}

Within the @using (Html.BeginCollectionItem("Telefones")) you put the name of sound ICollection, which in your case would be Telephone.

Once that’s done, we just need to make a requisition Ajax and return to PartialView to the desired location, in this way:

<script>
        $('#add-telefone').click(function () {
            $.ajax({
                url: '@Url.Action("GetNewTelefone","Pessoa")',
                type: 'POST',
                success: function (data) {
                    $('#new-telefone').append(data);
                }
            });
            return false;
        });
</script>

The Script is making a request by clicking the button with the id=add-telefone and returning to PartialView to the div that has the id=new-telefone.

Once done, just click save normally and the list will be sent to your controller.

And in your controller you save the phone normally, this way:

[HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit([Bind(Include = "PessoaId,Nome,Telefones")] Pessoa pessoa)
    {
        if (ModelState.IsValid)
        {

            if (pessoa.Telefones != null && pessoa.Telefones.Any())
            {
                foreach (var telefone in pessoa.Telefones)
                {
                    telefone.PessoaId = pessoa.PessoaId;
                    db.Telefone.Add(telefone);
                }
            }

            db.Entry(pessoa).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(pessoa);
    }

If you’re using [Bind(Include)], don’t forget to add the ICollection<Telefone> Telefone on it, else the value will null.

Any doubt, I made an example project with the use of this package. You can download to understand better, if you want. It is on my Github.

0

An Icollection type is just the sampling of a collection (readonly), being List, an implementation of Ilist, which comes from Icollection, along with list manipulation methods(e.g.: Add, Remove, Clear).

Use as follows:

public virtual List<TelefoneModel> Telefone { get; set; }

Browser other questions tagged

You are not signed in. Login or sign up in order to post.