2013-09-03 8 views
10

Quando utilizzo i modelli di visualizzazione annidati e aggiungo elementi di input tramite l'helper HTML, il motore Razor aggiunge un prefisso ai nomi dei campi.Come impedire a Razor di aggiungere prefissi agli input quando si utilizzano modelli di visualizzazione annidati?

Capisco che questo è fatto per garantire l'unicità del nome di input a livello di pagina (e per ricostruire l'intero modello sul postback).

Tuttavia, ho molte piccole forme che eseguono azioni ad-hoc e non ho bisogno né dell'unicità del nome né della capacità di ricostruire l'intero modello.

Ho solo bisogno di quel valore di singola proprietà, e avendo Razor alterare i nomi degli elementi di input interrompe il raccoglitore del modello quando invio uno dei moduli, poiché tutti i nomi saranno diversi.

Questo esempio contiene un modello nidificato semplificato

public class Student 
{ 
    public Guid Id { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public List<Course> Courses { get; set; } 
} 

public class Course 
{ 
    public Guid Id { get; set; } 
    public string Name { get; set; } 
    public List<Grade> Grades { get; set; } 
} 

public class Grade 
{ 
    public Guid Id { get; set; } 
    public DateTime Date { get; set; } 
    public decimal Value { get; set; } 
} 

ed ha una Index vista con tre modelli di visualizzazione annidati

IndexView 
    StudentDisplayTemplate 
     CourseDisplayTemplate 
      GradeDisplayTemplate 

Nella maschera di visualizzazione grado aggiungo un pulsante per rimuovere il grado

@model Playground.Sandbox.Models.Home.Index.Grade 

<li> 
    @this.Model.Date: @this.Model.Value 

    @using (Html.BeginForm("Remove", "Home", FormMethod.Post)) 
    { 
     <input name="GradeId" type="hidden" value="@this.Model.Id" /> 

     <input type="submit" value="Remove" /> 
    } 
</li> 

e sull'altro lato della richiesta il mio azione di controllo riceve l'ID grado

public ActionResult Remove(Guid id) 
{ 
    // Do various things. 
    return this.RedirectToAction("Index"); 
} 

Se provo a farlo utilizzando il modello di supporto

@Html.HiddenFor(x => x.Id) 

ottengo l'elemento HTML

<input data-val="true" 
     data-val-required="The Id field is required." 
     id="Courses_0__Grades_1__Id" 
     name="Courses[0].Grades[1].Id" 
     type="hidden" 
     value="76f7e7ed-a479-42cb-add5-e58c0090770c" /> 

in cui il nome del campo ottiene un prefisso basato sull'albero del modello di visualizzazione dell'intero genitore.

Utilizzando l'aiutante "manuale"

@Html.Hidden("GradeId", this.Model.Id) 

dà l'elemento HTML

<input id="Courses_0__Grades_0__GradeId" 
     name="Courses[0].Grades[0].GradeId" 
     type="hidden" 
     value="bbb3c11d-d2d0-464a-b33b-ff7ac9815601" /> 

dove il prefisso è ancora presente, anche se con il mio nome alla fine.

aggiungere manualmente l'input nascosto

<input name="GradeId" type="hidden" value="@this.Model.Id" /> 

dà l'elemento HTML

<input name="GradeId" 
     type="hidden" 
     value="a1a35e81-29cd-41b5-b619-bab79b767613" /> 

che è quello che voglio.

È possibile ottenere ciò che desidero oppure i problemi di visualizzazione dei modelli di visualizzazione sono errati?

+0

http://stackoverflow.com/questions/14157376/why-does-html-helper-add-prefix-to-attributes-for-child-item-of-view-model –

+0

@MohamadBataineh come ho detto, lo faccio sai perché lo sta facendo Quello che sto chiedendo è se c'è un modo per prevenirlo quando si usano gli helper HTML (non penso di poter usare l'attributo Bind nell'azione di ricezione, poiché gli helper stanno inserendo indici di array nei nomi). – Albireo

risposta

9

si desidera impostare ViewData.TemplateInfo.HtmlFieldPrefix nel Grade modello:

@model Playground.Sandbox.Models.Home.Index.Grade 

@{ 
    ViewData.TemplateInfo.HtmlFieldPrefix = ""; 
} 

Questo dà l'output desiderato di:

<input id="GradeId" name="GradeId" type="hidden" /> 
+0

Risolve il problema con i nomi, ma ora il markup non è valido. Sembra che stia usando un 'List' di' Grade's e lo renda come una lista di elementi del form. Impostando 'ViewData.TemplateInfo.HtmlFieldPrefix' a' "" "il campo ID degli input del form non sarà più univoco. Qualche idea per soluzione alternativa? Oltre a specificare l'ID personalizzato per ogni input, ovviamente. –

0

Dalla tua domanda, non è chiaro se si sta cercando di essere in grado per inviare sia l'intero modulo, o solo le singole azioni. Se si vuole essere in grado di fare entrambe le cose, penso che sarà necessario utilizzare una soluzione basata su JS per inviare manualmente le richieste di sottomaschera.

Tuttavia, se si desidera solo di presentare i sottomoduli, frammentario, leggere insieme ..

Se la sintassi Courses_0__Grades_1__Id per le collezioni sta causando problemi, questo è relativamente facile da risolvere, nella mia esperienza.

È possibile ottenere un comportamento diverso su come i nomi/ID vengono generati negli oggetti figlio nelle raccolte utilizzando foreach anziché un tradizionale for.

Mi spiego:


1) Questo romperà il modello vincolante per tutta la forma di presentazione. Tutti gli input per elementi figlio non avranno alcun contesto del loro percorso genitore.

@foreach(var child in Model.Children) 
{ 
    @Html.EditorFor(x=> child) 
} 


2) Questi saranno rispettare contesto genitore e consentire modello vincolante per tutta la forma di presentazione. Tutti gli input per gli elementi figlio avranno il contesto del percorso principale.

@for(var i = 0; i < Model.Children.Count(); i++) 
{ 
    @Html.EditorFor(x=> Model.Children[i]) 
} 
// or.. 
var i = 0; 
@foreach(var child in Model.Children) 
{ 
    @Html.EditorFor(x=> Model.Children[i]) 
    i++; 
} 

Tuttavia

Si dovrà ancora avere problemi con gli oggetti non in collezioni, appeso fuori il modello principale, come Model.SomeOtherType.AnotherType avrà ingressi nel nidificato EditorFor con nomi come SomeOtherType.Property1 e SomeOtherType.Property2

Per questi, è possibile inserire l'oggetto in una variabile temporanea nel rasoio:

@var tempObj = Model.SomeOtherType; 
<div class='somemarkup'> 
    @Html.EditorFor(x=> tempObj); 
</div>