How to create a View for this Template case?

Asked

Viewed 387 times

6

I’ve been trying to apply the solution to this question (How to pass checkbox list to Actionresult) in a problem I’m having but I’m not getting a positive result.

I’m getting an array with several on’s instead of receiving an array with the id’s, as I imagined it would 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, representing 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 me something like:

Exemplo de View

To list the Acoes I’m doing it this way:

@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 "game" made with the checkboxes is returning a list of on’s instead of a list of Id’s.

My method, which is not yet complete, I am testing yet:

[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:

checkeds

The parameter checkeds come with the list of on’s.

So what I ask is for your help to elaborate this View and make it exchange information correctly with my Action method.

2 answers

2


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

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

It’s also wrong to write the tag text within the tag input, just leave "checked".

I would write something like that (I randomly named it, 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();
            ...
    }    
  • Hello @Andrefigueiredo, thanks for the help. I indexed, only that I am receiving in the array all indexes with the value "0", instead of the Id of Action. You know what it could be?

  • If I keep leaving the parameter as string[] in my Action, the array then continues coming with the list of on’s, move to int[] returns the array with all 0. So apparently it’s just returned a "positive" (true) to the selected indexes.

  • Ah, you have to return then a complex type (a Viewmodel to) or a dictionary Key : Action Id, Value: status checked.

  • Eita.. Can you give me an example, dear? Please!

  • I updated the answer, you would have to modify the items. But overall it would be something in this scheme..

  • ASP.NET MVC cuts when the sequence is not complete.. like this: If you look at the sample screen image you will understand. I selected List, Add, jumped the Alter and added the Rule out and the Report to the Neighborhood. But my Dictionary comes only with the List and the Add. But thank you, I think I understand that and I’ll run some tests. Thank you!

  • 1

    yes. if the inputs have a sequence [0, 1, 3], example, the framework will cut between 1 and 3. You have to be careful when giving the POST elements to be in sequence (in the example, I tried using the X counter)

  • Cool, I can try to manipulate this with Javascript/jQuery. I’ll try!

Show 3 more comments

2

Well, I solved it that way that it became 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");
        }
    });
});

At last, 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);
}

That way I got a complete list and much easier to handle:

Exemplo do Estado da Dictionary

Browser other questions tagged

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