w3schools tag tab style color attribute javascript data-binding knockout.js observable

javascript - tag - Dando valor inicial a observable desde el marcado HTML



title html w3schools (4)

HtmlHelper crear una extensión HtmlHelper que HtmlHelper algo de HTML a la vista. En este HTML estoy cableando un enlace KnockoutJS. Soy nuevo en KO, así que todavía estoy luchando para hacer algunas cosas. De todos modos, lo que estoy tratando de hacer es generar campos de entrada (en el código del lado del servidor) vinculados a observables en mi código del lado del cliente, luego establecer los valores iniciales de los observables a través del valor de los campos ocultos. Desafortunadamente, eso no está funcionando para mí. Entonces me pregunto si hay alguna forma de que pueda hacer esto (incluso si tengo que hacerlo completamente diferente).

Esto es lo que básicamente estoy haciendo:

En mi modelo de vista lateral del cliente, tengo lo siguiente:

self.dataSource = ko.observable(); self.pageSize = ko.observable();

Y mi método de extensión da como resultado lo siguiente:

<input type="hidden" value="/Employee/Get" data-bind="value: dataSource" /> <input type="hidden" value="30" data-bind="value: pageSize" />

Pero cuando se procesa la página, cuando inspecciono los elementos, noto que el value de los campos de entrada se está configurando como una cadena vacía, lo que creo se debe a la forma en que se declaran los observables. Pero, ¿hay alguna manera de anular este comportamiento o algo así?


Si un enlace personalizado es demasiado pesado, entonces una solución simple es inicializar los observables del DOM.

Por ejemplo, dado el siguiente formulario HTML:

<form name="person"> <input type="text" name="firstName" value="Joe" data-bind="value: firstName"/> </form>

Entonces Knockout podría inicializarse de la siguiente manera:

ko.applyBindings({ firstName: ko.observable(document.forms[''person''][''firstName''].value) });


Simplemente puede usar un enlace personalizado y asignar los valores a los observables existentes:

ko.bindingHandlers.yourBindingName = { init: function (element, valueAccessor, allBindings, viewModel, bindingContext) { viewModel.dataSource($(".dataSource").val()); viewModel.pageSize($(".pageSize").val()); } };

Luego, solo agregue una clase, o un Id a las entradas y data-bind="yourBindingName" al elemento HTML que los contiene.


Un poco tarde aquí. En realidad, no estaba satisfecho con la respuesta de RP porque rompe la naturaleza declarativa de Knockout. Específicamente, si usa valueWithInit para definir su propiedad, no puede usarla en un enlace anterior. Aquí hay un tenedor de su jsfiddle para demostrar .

Lo usa de la misma manera, sin embargo, sigue siendo declarativo en todo el documento bajo el capó:

<input data-bind="valueWithInit: firstName" value="Joe" />

Ampliando la idea, también puede usar esto para separar la inicialización y el enlace:

<input data-bind="initValue: lastName, value: lastName" value="Smith" />

Esto es un poco redundante, pero se vuelve útil cuando utilizas un complemento en lugar de los enlaces incorporados:

<input data-bind="initValue: lastName, myPlugin: lastName" value="Smith" />

Ampliando un poco más, también necesitaba una forma de inicializar casillas de verificación:

<input type="checkbox" data-bind="checkedWithInit: isEmployed" checked />

Y aquí están los manipuladores:

ko.bindingHandlers.initValue = { init: function(element, valueAccessor) { var value = valueAccessor(); if (!ko.isWriteableObservable(value)) { throw new Error(''Knockout "initValue" binding expects an observable.''); } value(element.value); } }; ko.bindingHandlers.initChecked = { init: function(element, valueAccessor) { var value = valueAccessor(); if (!ko.isWriteableObservable(value)) { throw new Error(''Knockout "initChecked" binding expects an observable.''); } value(element.checked); } }; ko.bindingHandlers.valueWithInit = { init: function(element, valueAccessor, allBindings, data, context) { ko.applyBindingsToNode(element, { initValue: valueAccessor() }, context); ko.applyBindingsToNode(element, { value: valueAccessor() }, context); } }; ko.bindingHandlers.checkedWithInit = { init: function(element, valueAccessor, allBindings, data, context) { ko.applyBindingsToNode(element, { initChecked: valueAccessor() }, context); ko.applyBindingsToNode(element, { checked: valueAccessor() }, context); } };

Observe que valueWithInit simplemente usa initValue debajo del capó.

Véalo en acción en jsfiddle .


Una alternativa que puede usar para mantener su código un poco más limpio es usar un enlace personalizado que ajuste el enlace de valor inicializándolo con el valor actual del elemento.

Incluso puede hacer que cree observables en su modelo de vista, si no existen.

El enlace podría ser algo así como:

ko.bindingHandlers.valueWithInit = { init: function(element, valueAccessor, allBindingsAccessor, data) { var property = valueAccessor(), value = element.value; //create the observable, if it doesn''t exist if (!ko.isWriteableObservable(data[property])) { data[property] = ko.observable(); } data[property](value); ko.applyBindingsToNode(element, { value: data[property] }); } };

Lo usarías como:

<input value="someValue" data-bind="valueWithInit: ''firstName''" />

Tenga en cuenta que el nombre de la propiedad está entre comillas, esto permite que el enlace lo cree, si no existe en lugar de un valor indefinido.

Aquí hay una muestra: http://jsfiddle.net/rniemeyer/BnDh6