MVC 3 + KnockoutJS: Agregar el atributo de unión a datos cuando se usa Editor para un campo booleano

StackOverflow https://stackoverflow.com/questions/7302434

  •  22-10-2019
  •  | 
  •  

Pregunta

Usando @Html.EditorFor(model =>model.IsClient), donde Isclient es un booleano, hace una lista desplegable con Not Set, Yes and No como las opciones.

Todo bien y bien.

Ahora quiero usar knockoutjs con la lista desplegable resultante, que me gusta, entonces, ¿cómo agrego el atributo de unión a datos usando @html.editorfor, que necesito para que los knockoutjs funcionen con este menú desplegable?

Yo he tratado:

@Html.EditorFor(model => model.IsClient, new Dictionary<string, object> { { "data-bind", "value: Account.IsClient" } })

Sin embargo, esto utiliza el parámetro de ViewData del objeto, y no renderiza el atributo de unión a datos. Lo cual es probablemente bastante natural, ya que este parámetro probablemente no tiene nada que ver con los atributos HTML para la etiqueta renderizada.

Sin embargo, no puedo encontrar ninguna documentación razonable, y ninguna de las otras sobrecargas parece probable candidatos para lo que quiero.

Tia cualquier sugerencia.

¿Fue útil?

Solución

Brad Wilson escribido Acerca de las plantillas de visualización y editor en ASP.NET MVC 2. para que pueda modificar la plantilla predeterminada para boolean y agregar los atributos que necesita (~/Views/Shared/EditorTemplates/MyTemplate.cshtml):

@{
    bool? value = null;
    if (ViewData.Model != null) 
    {
        value = Convert.ToBoolean(ViewData.Model, System.Globalization.CultureInfo.InvariantCulture);
    }

    var triStateValues = new List<SelectListItem> 
    {
        new SelectListItem 
        { 
            Text = "Not Set",
            Value = String.Empty,
            Selected = !value.HasValue 
        },
        new SelectListItem 
        { 
            Text = "True",
            Value = "true",
            Selected = value.HasValue && value.Value 
        },
        new SelectListItem 
        { 
            Text = "False",
            Value = "false",
            Selected = value.HasValue && !value.Value 
        },
    };
}

@if (ViewData.ModelMetadata.IsNullableValueType) 
{
    <!-- TODO: here you can use any attributes you like -->
    @Html.DropDownList(
        "", 
        triStateValues, 
        new { 
            @class = "list-box tri-state", 
            data_bind="value: " + ViewData.TemplateInfo.GetFullHtmlFieldName("") // you could also use ViewData.ModelMetadata.PropertyName if you want to get only the property name and not the entire navigation hierarchy name
        }
    )
} 
else 
{
    @Html.CheckBox("", value ?? false, new { @class = "check-box" })
}

y finalmente:

@Html.EditorFor(model => model.IsClient, "MyTemplate")

o decorar la propiedad isClient en su modelo de vista con el UIHint atributo:

[UIHint("MyTemplate")]
public bool? IsClient { get; set; }

y entonces:

 @Html.EditorFor(x => x.IsClient)

elegirá automáticamente la plantilla de editor personalizado.

Otros consejos

Anexo para usuarios de knockoutjs:

La respuesta de @Darin Dimitrov es excelente, pero un poco rígida para usar con knockoutjs, donde las vistas complejas pueden conducir a ViewModels que no se asignan por completo al parámetro @Model.

Así que he hecho uso del parámetro adicional ViewData. Para acceder al parámetro adicionalViewData desde su edición personalizada, consulte la siguiente pregunta:

Acceda a adicionalViewData desde el código de edición personalizado personalizado

Digresion: el adicional ViewData Param es confuso, ya que no hace nada con el editor predeterminado. Solo entra en sí mismo con una plantilla de editor personalizado.

De todos modos, mis enmiendas al código de Darin son las siguientes:

@if (ViewData.ModelMetadata.IsNullableValueType) 
{
    var x = ViewData["koObservablePrefix"];
    if ((x != "") && (x != null)) { x = x + "."; }
    @Html.DropDownList(
        "", 
        triStateValues, 
        new { 
            @class = "list-box tri-state", 
            data_bind="value: " + x + ViewData.TemplateInfo.GetFullHtmlFieldName("") // or you could also use ViewData.ModelMetadata.PropertyName if you want to get only the property name and not the entire navigation hierarchy name
        }
    )
} 
else 
{
    @Html.CheckBox("", value ?? false, new { @class = "check-box" })
}

Tenga en cuenta las líneas:

var x = ViewData["koObservablePrefix"];
if ((x != "") && (x != null)) { x = x + "."; }

KoobServablePrefix está allí para poder agregar un prefijo arbitrario a mi ViewModel Ko.observable. Podrías hacer otras cosas si así lo eliges.

Yo uso la variable x de la siguiente manera:

data_bind="value: " + x + ViewData.TemplateInfo.GetFullHtmlFieldName("")

De esa manera, si no paso en el "KoobServablePrefix" adicional ViewData, todo todavía funciona.

Entonces, ahora puedo escribir:

@Html.EditorFor(model => model.IsClient, "koBoolEditorFor", new { koObservablePrefix = "Account" })

que renderizará como:

<select class="list-box tri-state" data-bind="value: Account.IsBank" id="IsBank" name="IsBank">

Nota la "Valor: Account.isBank" Valor de atributo de unión a datos.

Esto es útil si, por ejemplo, su modelo de visión es muy escrito es de cuenta de tipo, pero en su cuenta de cuentas para su página, tiene una estructura más compleja, por lo que debe empaquetar sus observables en un objeto de cuenta. P.EJ:

function account(accountId, personId, accountName, isClient, isProvider, isBank) {

    this.AccountId   = ko.observable(accountId);
    this.PersonId    = ko.observable(personId);
    this.AccountName = ko.observable(accountName);
    this.IsClient    = ko.observable(isClient);
    this.IsProvider  = ko.observable(isProvider);
    this.IsBank      = ko.observable(isBank);
}

function accountViewModel() { 

    var self = this;

    this.selectedCostCentre = ko.observable('');            
    this.Account = new account(@Model.AccountId, @Model.PersonId, '@Model.AccountName', '@Model.IsClient','@Model.IsProvider', '@Model.IsBank');
              // etc. etc
}

Si no tiene este tipo de estructura, entonces, el código recogerá la estructura. Es solo una cuestión de adaptar su ViewModel JS a esta convención flexible.

Espero que esto no sea demasiado confuso ...

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top