2015-04-09 6 views
5

Ho un elenco di elementi che verranno associati a un utente. È una relazione uno-a-molti. Voglio che l'intera lista di elementi sia passata nella vista in modo che possano scegliere tra quelli che non sono ancora associati (e anche vedere quelli che sono già associati). Voglio creare checkbox da questi. Poi voglio rimandare quelli selezionati nel controller da associare. Come posso passare nell'elenco di tutti loro, compresi quelli che non sono ancora associati, e passarli in modo affidabile per essere associati?Passa l'elenco delle caselle di controllo in Visualizza e Estrai IEnumerable

Ecco cosa ho provato per primo, ma è chiaro che questo non funzionerà poiché sto basando gli input sugli elementi passati tramite la raccolta AllItems, che non ha alcuna connessione con gli Elementi sull'utente stesso.

<div id="item-list"> 
    @foreach (var item in Model.AllItems) 
    { 
     <div class="ui field"> 
      <div class="ui toggle checkbox"> 
       <input type="checkbox" id="[email protected]" name="Items" value="@item.Active" /> 
       <label for="[email protected]">@item.ItemName</label> 
      </div> 
     </div> 
    } 
</div> 

risposta

12

Non è possibile eseguire il binding a una raccolta utilizzando un ciclo foreach. Né dovresti generare manualmente il tuo html, che in questo caso non funzionerebbe perché le caselle di controllo deselezionate non postback. Utilizzare sempre gli helper html fortemente tipizzati in modo da ottenere il binding del modello a 2 vie corretto.

Non hai indicato quello che i modelli sono, ma supponendo che hanno un User e desidera selezionare Roles per quell'utente, quindi creare vista modelli per rappresentare ciò che si desidera visualizzare nella vista

public class RoleVM 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 
    public bool IsSelected { get; set; } 
} 
public class UserVM 
{ 
    public UserVM() 
    { 
    Roles = new List<RoleVM>(); 
    } 
    public int ID { get; set; } 
    public string Name { get; set; } 
    public List<RoleVM> Roles { get; set; } 
} 

In il metodo GET

public ActionResult Edit(int ID) 
{ 
    UserVM model = new UserVM(); 
    // Get you User based on the ID and map properties to the view model 
    // including populating the Roles and setting their IsSelect property 
    // based on existing roles 
    return View(model); 
} 

View

@model UserVM 
@using(Html.BeginForm()) 
{ 
    @Html.HiddenFor(m => m.ID) 
    @Html.DisplayFor(m => m.Name) 
    for(int i = 0; i < Model.Roles.Count; i++) 
    { 
    @Html.HiddenFor(m => m.Roles[i].ID) 
    @Html.CheckBoxFor(m => m.Roles[i].IsSelected) 
    @Html.LabelFor(m => m.Roles[i].IsSelected, Model.Roles[i].Name) 
    } 
    <input type"submit" /> 
} 

Poi nel metodo post, il tuo modello sarà legato e si può controllare quali ruoli sono stati selezionati

[HttpPost] 
public ActionResult Edit(UserVM model) 
{ 
    // Loop through model.Roles and check the IsSelected property 
} 
+0

Questo è in realtà qualcosa di simile a quello che ho fatto (con piccole differenze). Potrei fare alcune modifiche basandomi sui tuoi suggerimenti qui, però. Grazie! – muttley91

0

Non sembra che stiate eliminando le caselle dinamicamente in modo che questo problema sia molto più facile da risolvere. NOTA: la seguente soluzione non funzionerà come previsto se si consente ai client o agli script di rimuovere dinamicamente le caselle di controllo dalla pagina poiché gli indici non saranno più sequenziali.

Il binding del modello MVC non è infallibile, quindi a volte è necessario aiutarlo. Il raccoglitore modello sa che ha bisogno di legarsi a una proprietà chiamata Elementi perché il nome del campo di immissione è Articoli, ma non sa Gli elementi sono una lista. Pertanto, supponendo che nel controller sia presente un elenco di elementi per modellare il collegamento agli elementi denominati, è necessario aiutare MVC a riconoscere che si sta vincolando a un elenco. Per fare ciò specificare il nome della lista e un indice.

<div id="item-list"> 
    @for (var i = 0; i < Model.AllItems.Count; i++) 
    { 
     <div class="ui field"> 
      <div class="ui toggle checkbox"> 
       <input type="checkbox" id="[email protected][i].ItemID" name="Items[@i]" value="@Model.AllItems[i].Active" /> 
       <label for="[email protected][i].ItemID">@Model.AllItems[i].ItemName</label> 
      </div> 
     </div> 
    } 
</div> 

La linea di chiave qui è questo:

<input type="checkbox" id="[email protected][i].ItemID" name="Items[@i]" value="@Model.AllItems[i].Active" />

Avviso Posta [@i]? Questo sta dicendo al legatore del modello di cercare una proprietà denominata Articoli e associare questo valore all'indice in i per Articoli.

+0

Questo funziona, che passa negli indici voce, ma il valore effettivo di ogni articolo è nullo. C'è un modo per passare più informazioni sull'oggetto in? – muttley91

+0

Quindi assumerò che il tuo elenco di articoli non sia un elenco di booleani? Il modo in cui gestisci ciò è dando al raccoglitore del modello ancora più informazioni. Quindi, se gli oggetti nel tuo elenco di articoli hanno una proprietà chiamata "Attiva", il nome della tua casella di controllo dovrebbe essere Elementi [@i]. Attivo. Quindi per ogni campo aggiuntivo che vuoi popolare, ad esempio il nome, avresti un altro input con il nome Items [@i].Nome. – BoredBlazer

+0

Immagino di essere confuso - stai dicendo che ho bisogno di più input per una casella? Cosa succede se voglio solo passare l'ID dell'articolo di nuovo al controller? MODIFICA: anche, per poter spuntare la casella, probabilmente intendevi usare l'attributo 'checked'. – muttley91

Problemi correlati