How to create a View for this Model case?

6

I've been trying to work around this issue (#) into a problem I'm having but I'm not getting a positive result.

I'm getting an array with on's variants instead of getting an array with id's , as I imagined it to be.

I have the following classes:

Controle :

public class Controle
{
    public Controle() {
        Actions = new List<Action>();
    }
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]    
    public int Id { get; set; }
    public string Name { get; set; }
    public string DisplayName { get; set; }

    public virtual List<Acao> Acoes { get; set; }
}

Acao :

public class Acao
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public int ControleId { get; set; }
    public string Name { get; set; }

    [ForeignKey("ControleId")]
    public Controle Controle { get; set; }
}

Grupo , which would represent the groups in which users are allocated:

public class Grupo
{
    public Grupo() {
        Acessos = new List<GrupoAcesso>();
    }
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Descricao { get; set; }

    [InverseProperty("Grupo")]
    public virtual List<GrupoAcesso> Acessos { get; set; }
}

And GrupoAcesso , which represents the Controles and Acoes that the Group has access to:

public class GrupoAcesso
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public int GrupoId { get; set; }
    public int ControleId { get; set; }
    public int AcaoId { get; set; }

    [ForeignKey("GrupoId")]
    public virtual Grupo Grupo { get; set; }
    [ForeignKey("ControleId")]
    public virtual Controle Controle { get; set; }
    [ForeignKey("AcaoId")]
    public virtual Acao Acao { get; set; }
}

Until then I'm trying to create a view that presents something like:

TolisttheAcoesI'mdoingitthisway:

@model Domain.Grupo .... @{ var checkeds = new string[] { }; if (ViewBag.Checkeds != null) { checkeds = ViewBag.Checkeds as string[]; } } ... <table class="table table-striped table-condensed table-bordered" style="margin:2px;"> @for (var X = 0; X < controle.Acoes.Count(); X++) { var acao= controle.Acoes[X]; <tr> <td> <label style="font-weight:bold; color:darkblue">@acao.Name</label> </td> <td class="text-center" style="width:50px; padding:0; vertical-align:middle;"> <input type="checkbox" name="checkeds" id="@acao.Id" if (checkeds.Contains(acao.Id.ToString())) { <text> checked </text> } /> </td> </tr> } </table> ...

But in my method I get the post , the result of this checkboxes game is returning a list of on's in instead of a Id's list.

My method, which is not yet complete, I'm still testing:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Gravar([Bind(Exclude = "Acessos, Usuarios")]Domain.Grupo obj, string[] checkeds)
{
    if (ModelState.IsValid)
    {
        try
        {
            // carrego o grupo caso ele já exista
            var rec = repository.Grupos.Include("Acessos").SingleOrDefault(x => x.Id == obj.Id || x.Descricao.ToLower() == obj.Descricao.ToLower());
            if (rec != null) {
                rec.Acessos.RemoveAll(x => x.ControleId == rec.Id);
            }
            else {
                repository.Grupos.Add(obj);
            }
            repository.SaveChanges();
            return RedirectToAction("Listar");
        }
        catch (Exception e)
        {
            ModelState.AddModelError("", "Ocorreu um erro enquanto processávamos sua requisição");
            System.Console.WriteLine(e.Message);
        }
    }

    ViewBag.Controllers = repository.Controles.Include("Acoes").ToList();
    ViewBag.Checkeds = checkeds;

    return View("Cadastro", obj);
}

The parameter checkeds :

The checkeds parameter comes with the on's list.

So what I ask is your help in working through this View and getting it to exchange information correctly with my Action method.

    
asked by anonymous 23.03.2014 / 16:22

2 answers

2

To post an array of elements to the Controller transparently, you should index the name property for each of the checkboxes.

You must pass each element to the Controller to have the ID and Checked status of each element.

It is also wrong to write the text tag inside the input tag, just leave it checked.

I would write something like this (I named it randomly, but it serves as an example):

View:

@{
    var checkedIDs = new int[] { };
    if (ViewBag.Checkeds != null) {
        checkedIDs = ViewBag.Checkeds as int[];
    }
}

...

var checkedIndice = "acoes[" + X + "]";
<input type="hidden" name="@(checkedIndice + ".Key")" id="@(checkedIndice + ".Key")" />
<input type="checkbox" name="@(checkedIndice + ".Value")" id="@(checkedIndice + ".Value")" 
       @(checkedIDs.Contains(acao.Id)? "checked": "") />

Controller:

    public ActionResult Gravar([Bind(Exclude = "Acessos, Usuarios")]Domain.Grupo obj, Dictionary<int, bool> acoes)
    {
        if (ModelState.IsValid)
        {
            try
            {
                // carrego o grupo caso ele já exista
                ...

                // instancia as tabela de ações marcadas do controle (antes das novas alterações)
                var repAcoes = repository.Acessos.Where(x => x.ControleId == obj.Id);

                // Remove as desmarcadas
                repAcoes.RemoveAll(x => !acoes.ContainsKey(x.AcaoId));

                // adiciona as marcadas que não estavam marcadas
                foreach(var acao in acoes.Where(x => x.Value)){
                    var novaAcao = new Acao(){
                        ControleId = obj.Id,
                        AcaoId = acao.Key
                    };
                    repAcoes.Add(novaAcao);
                }

                repository.SaveChanges();
            ...
    }    
    
24.03.2014 / 04:37
2

Well, I decided that it was much simpler to manipulate:

@{
    var checkeds = new int[] { };
    if (ViewBag.Checkeds != null)
    {
        checkeds = ViewBag.Checkeds as int[];
    }
}
...
<td class="text-center actions" style="width:50px; padding:0; vertical-align:middle;">
    <input type="hidden" name="actions[@X].Key" id="actions[@X].Key" value="@action.Id" />
    <input type="hidden" name="actions[@X].Value" id="actions[@X].Value" value="False" class="value" />
    <input type="checkbox" name="check[@X]" id="check[@X]"
            @(checkeds.Contains(action.Id) ? "checked" : "") />
</td>

with a jQuery to help confirm which one is selected:

$("#formGrupoCadastro").submit(function () {
    $(".actions").each(function () {
        var $checkbox = $(this).find("input[type=checkbox]");
        var $hidden = $(this).find("input[type=hidden].value");
        if ($checkbox.is(':checked')) {
            $hidden.attr("value", "True");
        }
    });
});

Finally, in my Action :

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Gravar([Bind(Exclude = "Acessos, Usuarios")]Domain.Grupo obj, Dictionary<int, bool> acoes)
{
    if (ModelState.IsValid)
    {
        ...
    }
    ViewBag.Controles = repository.Controles .Include("Acoes").ToList();
    ViewBag.Checkeds = acoes.Select(x => x.Key).ToArray();
    return View("Cadastro", obj);
}

In this way I have a complete and much easier list to handle:

    
24.03.2014 / 15:30