web-dev-qa-db-fra.com

Dans MVC/Razor, comment puis-je obtenir les valeurs de plusieurs cases à cocher et les transmettre toutes au contrôleur?

J'ai une vue avec une liste d'éléments d'un modèle. Je dois ajouter une case à cocher à chaque ligne, demander à l'utilisateur de cocher plusieurs cases et transmettre un identifiant de la ligne sélectionnée au contrôleur. Je sais comment transmettre une valeur unique via un lien d'action, mais je ne suis pas sûr de savoir comment transmettre plusieurs valeurs via un lien d'action ou comment "collecter" les lignes sélectionnées. Je vais montrer certaines de mes tentatives de code ci-dessous. Quelqu'un peut-il m'aider à comprendre pourquoi je ne peux pas obtenir les valeurs de toutes les cases à cocher transmises au contrôleur?

Voici ma page

Checkbox     App ID     Date     Name
   []          1        5/10     Bob
   []          2        5/10     Ted
   []          3        5/11     Alice

Ce que j'ai besoin de l'utilisateur, c'est de sélectionner les lignes 1 et 3 (par exemple) et de faire passer ces ID d'application au contrôleur.

J'ai commencé à énumérer diverses tentatives, mais j'ai simplement décidé de montrer ma tentative actuelle et de voir si quelqu'un pouvait signaler ce que je faisais mal. La principale différence que je vois entre les exemples en ligne et les miens est que le mien utilise une liste paginée et crée les lignes de la table dans une boucle foreach.

Le paramètre ints est vide lorsqu'il frappe le contrôleur. Comment puis-je obtenir les valeurs des cases à cocher? J'ai utilisé ce site pour l'idée de base: nommer toutes les cases à cocher identiques et passer une ICollection via le lien d'action: http://haacked.com/archive/2008/10/23/model-binding-to -a-list.aspx/

Vue:

@model PagedList.IPagedList<CarmelFinancialWeb.Models.ModelMerchantSummary>
<div class="block" style="width: 100%; float: left">
<p class="block-heading"> 
Merchant Application Report
</p>
<div class="table-holder">
    <table class="table" style="margin-bottom: 0px">
            <tbody>
                @foreach (var item in Model)
                {
                    <tr>
                        <td>
                            <input type="checkbox" name="ints" value=item.ApplicationID />
                        </td>
                    <td>
                        @Html.ActionLink(item.ApplicationID.ToString(), "ViewApplication", new { ID = item.ApplicationID, edit = 1 }, new AjaxOptions { HttpMethod = "GET" })
                    </td>
                    <td>
                        @Convert.ToDateTime(item.ApplicationDate).ToString("M/d/yy")
                    </td>
                    <td>
                        @item.ApplicantName
                    </td>
        </tbody>
    </table>
</div>
</div>
@Html.ActionLink("Print Application", "PrintApplication", "CreateContract", new { @class = "btn btn-primary" })

Manette:

    [AuthorizeAdmin]
    public ActionResult PrintApplication(ICollection<int> ints, string ID)
    {
        Contracts_Create contract = new Contracts_Create();
        ModelApplication currentApplication = new ModelApplication();
        currentApplication.contract = new ModelContract();
        return File(contract.CreatePDF_PrintedApplication_English(currentApplication.contract.location, currentApplication.contract), "application/pdf");
    }

Edit: Cela a été marqué comme un duplicata d'une autre question. La question était de savoir si des noms d’entrée non séquentiels pouvaient être utilisés. Mon problème est que j'utilise des entrées qui ne sont pas séquentielles, mais cela ne fonctionne toujours pas. Je comprends le concept, je ne peux tout simplement pas comprendre pourquoi mon code spécifique ne fonctionne pas. J'ai passé beaucoup de temps à cela et je ne trouve pas la réponse à mon code spécifique. Merci!

10
boilers222

Essayez de passer un ViewModel dans votre page et d’utiliser le classeur de modèles pour publier le même modèle de vue dans votre contrôleur.

Des modèles:

public class MerchantModel
{
    public int AppId { get; set; }
    public string Name { get; set; }
    public bool IsSelected { get; set; }
}

public class MerchantViewModel
{
    public List<MerchantModel> Merchants { get; set; }
}

Manette:

public class DefaultController : Controller
{
    // GET: Default
    public ActionResult Index()
    {
        var merchant1 = new MerchantModel
        {
            AppId = 1,
            Name = "Bob"
        };
        var merchant2 = new MerchantModel
        {
            AppId = 2,
            Name = "Ted"
        };
        var merchant3 = new MerchantModel
        {
            AppId = 3,
            Name = "Alice"
        };

        List<MerchantModel> list = new List<MerchantModel>();
        list.Add(merchant1);
        list.Add(merchant2);
        list.Add(merchant3);

        var model = new MerchantViewModel
        {
            Merchants = list
        };

        return View(model);
    }

    [HttpPost]
    public ActionResult Index(MerchantViewModel model)
    {
        return View(model);
    }
}

Vue:

 @model TestCheckBoxes.Models.MerchantViewModel

    @{
        Layout = null;
    }

    <!DOCTYPE html>

    <html>
    <head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    <div> 
        <form action="/default/index" method="post">
            <table>
                @for (int i = 0; i < Model.Merchants.Count; i++)
                {
                    <tr>
                        <td>
                            @Html.CheckBoxFor(x => x.Merchants[i].IsSelected)
                        </td>
                        <td>
                            @Html.HiddenFor(x => x.Merchants[i].AppId)
                            @Model.Merchants[i].AppId
                        </td>
                        <td>
                            @Html.HiddenFor(x => x.Merchants[i].Name)
                            @Model.Merchants[i].Name
                        </td>
                    </tr>
                }
            </table>

            <button type="submit">Submit</button>
        </form>



    </div>
</body>
</html>

De retour dans votre méthode [HttpPost] dans votre contrôleur, vous aurez une liste de MerchantModel avec la valeur bool true ou false. De cette façon, vous pouvez vérifier si c'est vrai et simplement récupérer l'AppId à partir de là.

8
Nick Young

N'utilisez pas foreach dans mvc, faites toujours une itération à l'aide de for et d'une variable d'indexation.

Vous aurez également besoin d'un booléen pour suivre l'état de la sélection.

Cet exemple de code fonctionne pour moi:

public class AModel
{
    public List<AnotherModel> Items { get; set; }
}

public class AnotherModel
{
    public int ApplicationId { get;set; }
    public DateTime ApplicationDate { get; set; }
    public string ApplicantName { get; set; }
    public bool Selected { get; set; }
}

Page.cshtml

@using (Html.BeginForm("PostIndex", "Home", FormMethod.Post))
{
    <table class="table" style="margin-bottom: 0px">
        <tbody>
        @for (var i = 0; i < Model.Items.Count(); i++)
        {
            <tr>
                <td>
                    <label>@Html.CheckBoxFor(model => model.Items[i].Selected) @Html.DisplayFor(model => model.Items[i].ApplicantName)</label>
                </td>
                <td>
                    @Html.ActionLink(Model.Items[i].ApplicationId.ToString(), "ViewApplication", new {ID = Model.Items[i].ApplicationId, edit = 1}, new AjaxOptions {HttpMethod = "GET"})
                </td>
                <td>
                    @Html.DisplayFor(model => model.Items[i].ApplicationDate)
                </td>
                <td>
                    @Html.DisplayFor(model => model.Items[i].ApplicationId)
                </td>
            </tr>
        }
        </tbody>
    </table>
    <input type="submit"/>
}
8
C Bauer

@CBauer et @NickYoung avaient essentiellement la réponse. Les clés étaient (1) en s'assurant que l'ID de ma case était coché avec un numéro séquentiel entre parenthèses avec le même suffixe, (2) en utilisant un bouton d'envoi au lieu d'un lien d'action et (3) en écrivant correctement le contrôleur pour accepter les ID des cases à cocher. Je pensais publier une partie de mon code pour vous donner une idée de ce que je devais travailler:

Vue (partielle):

@model PagedList.IPagedList<CarmelFinancialWeb.Models.ModelMerchantSummary>

...

@{var i = 0;}
@foreach (var item in Model)
{
  var tmp = "[" + i + "].ints";
  <tr>
      <td>
          <input name="ints" type="checkbox" id="@tmp" class="chkclass" value="@item.ApplicationID" />
      </td>

...

<input id="Submit" type="submit" class="btn btn-primary" value="Print Application(s)" />

...

Manette:

[AuthorizeAdmin]
[HttpPost]
public ActionResult MerchantApplicationSummary(string[] ints, FormCollection form, int? page)
{

...

Merci @CBauer et @NickYoung pour votre aide!

0
boilers222