Problems generating a Partialview with Begincollectionitem

Asked

Viewed 346 times

2

With the intention of creating an action for Adc/Delete data dynamically to a table with relation 1 to Many, the . net returns the exception "Undefined object reference for an object instance." when I call the Partialview I try to visualize the view, follow the Models, viewModels, Controller, View and Partialview...

Models

public class Candidato
{
    [Key]
    public int id { get; set; }
    public string nome { get; set; }
    public string cpf { get; set; }
    public string sexo { get; set; }
}

public class CandidatoEP
{
    [Key]
    public int id { get; set; }
    public int id_candidato { get; set; }
    public string empresa { get; set; }
    public string cargo { get; set; }
    public DateTime inicio { get; set; }
    public DateTime fim { get; set; }
    public string obsEp { get; set; }

    [ForeignKey("id_candidato")]
    public virtual Candidato candidato { get; set; }
}

Viewmodel

public class NovoCandidato
{
    [Required(ErrorMessage = "Obrigatório informar o Nome")]
    [Display(Name = "Nome")]
    public string nome { get; set; }

    [Required(ErrorMessage = "Obrigatório informar o CPF")]
    [Display(Name = "CPF")]
    public string cpf { get; set; }

    [Required(ErrorMessage = "Obrigatório informar o Sexo")]
    [Display(Name = "Sexo")]
    public string sexo { get; set; }

    public virtual ICollection<CandidatoEP> CandidatoEPs { get; set; }
}

Controller

public ActionResult Novo()
{
    var novoCandidato = new CandidatoNovo();
    return View(novoCandidato);
}

View (part where I insert the Partialview)

<div class="form-group col-lg-12" style="margin-bottom:30px;">
    <label>Experiência <small>(opcional)</small></label>
    <div class="dc-form-inside">

        @foreach (var Experiencia in Model.CandidatoEPs)
        {
            Html.RenderPartial("_AddCandidatoExp", Experiencia);
        }

        <a href="#" class="control-add-box">+ Adicionar Experiência</a>

    </div>
</div>

Partialview

@model Site.ViewModels.CandidatoNovo

@using (Html.BeginCollectionItem("CandidatoEPs"))
{
    <div class="dc-box-clonar form experiencia">
        <a href="#" class="fechar-form botao"><i class="glyphicon glyphicon-remove"></i></a>
        <div class="form-group col-lg-12">

            @Html.EditorFor(m => m.empresa, new { htmlAttributes = new { @class = "form-control", @placeholder = "Empresa onde trabalhou" } })
        </div>
        <div class="form-group col-lg-12">

            @Html.EditorFor(m => m.id_departamento, new { htmlAttributes = new { @class = "form-control", @placeholder = "Departamento" } })
        </div>
        <div class="form-group col-lg-12">

            @Html.EditorFor(m => m.cargo, new { htmlAttributes = new { @class = "form-control", @placeholder = "Função exercida" } })
        </div>
        <div class="form-group col-lg-6">

            @Html.EditorFor(m => m.inicio, new { htmlAttributes = new { @class = "form-control", @placeholder = "Início (MM/AAAA)" } })
        </div>
        <div class="form-group col-lg-6">

            @Html.EditorFor(m => m.fim, new { htmlAttributes = new { @class = "form-control", @placeholder = "Fim (MM/AAAA)" } })
        </div>
        <div class="form-group col-lg-12" style="margin-bottom:30px;">

            @Html.TextAreaFor(m => m.obsEp, new { @class = "dc-textarea form-control", @placeholder = "Descreva as atividades exercidas na função...", @rows = "3" })
            @Html.ValidationMessageFor(model => model.obsEp, "", new { @class = "text-danger" })
        </div>
    </div>
}

Ai, I use a function in js to add multiple experience box.

Javascript

$('.dc-box-clonar').hide();
$('.control-add-box').on('click', function (e) {
    e.preventDefault();
    var newElem = $(this).parent().find('.dc-box-clonar:first').clone();
    newElem.find('input').val('');
    newElem.prependTo($(this).parent()).show();
    var height = $(this).prev('.dc-box-clonar').outerHeight(true);

    $("html, body").stop().animate({ scrollTop: $(this).offset().top - 520 }, 600);
});

1 answer

5


Quickly solving the problem, it would be something like this:

<div class="form-group col-lg-12" style="margin-bottom:30px;">
    <label>Experiência <small>(opcional)</small></label>
    <div class="dc-form-inside">

        @if (Model != null && Model.CandidatoEPs != null) 
        {
            foreach (var Experiencia in Model.CandidatoEPs)
            {
                Html.RenderPartial("_AddCandidatoExp", Experiencia);
            }
        }

        <a href="#" class="control-add-box">+ Adicionar Experiência</a>
    </div>
</div>

To add the experience, use something like this:

        <script type="text/javascript">
            $("#adicionar-nova-experiencia").click(function () {
                $.get('/Experiencia/NovaLinha', function (template) {
                    $("#area-experiencias").append(template); /* Você pode ainda colocar .then($(...)); */
                });
            });
        </script>

And in the Controller (using Guid):

    public ActionResult NovaLinha()
    {
        return PartialView("_LinhaExperiencia", new Experiencia { ExperienciaId = Guid.NewGuid() });
    }

Using int:

    public ActionResult NovaLinha()
    {
        return PartialView("_LinhaExperiencia", new Experiencia());
    }

With int the key is not defined in Controller because the key definition is in charge of the database, the moment you save the record.

The Controller receives the following:

[HttpPost]
public ActionResult Novo(CandidatoNovo candidatoNovo)
{
    if (ModelState.IsValid) 
    { 
        /* Aqui candidatoNovo.CandidatoEPs está preenchido */ 
    }
}
  • And Gypsy, because by putting @if in the view the problem has been solved?

  • Because references can be null. I don’t know how you’re filling in, so I check the variables before trying to print anything.

  • Here the Experience Id is declosed as int, then when you put Guid returns an error... What’s the best way out of this?

  • I updated the answer.

  • And what would the Post action look like in the controller? it would receive the template or a list?

  • It receives the entire Model.

  • But here, I do not know why it is not recording what is being stored in Icollection, the data that are going to the bank are only those that are declared outside the Icollecion... You could update the answer with a short example?

  • @Matheussilva See now.

  • Hmmm, then I believe there is some error in my Viewmodel, because when I put it like this and give the command to add it to the original model (db.Candidato.Add(candidatNovo)), points out an error, something like "The best overloaded method match for..."

  • I think it’s the case of one more question.

Show 5 more comments

Browser other questions tagged

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