Подтвердить что ты не робот

Предоставление начального значения наблюдаемому из разметки HTML

Я пытаюсь создать расширение HtmlHelper, которое выводит некоторый HTML-код в представление. В этом HTML я подключаю некоторые привязки KnockoutJS. Я новичок в KO, поэтому я все еще пытаюсь сделать кое-что. Во всяком случае, я пытаюсь создать поля ввода (в серверном коде), привязанные к наблюдаемым на моем клиентском коде, а затем установить начальные значения наблюдаемых через значение скрытых полей. К сожалению, это не работает для меня. Поэтому мне интересно, можно ли мне это сделать (даже если мне нужно сделать это совершенно иначе).

Вот что я в основном делаю:

В моей модели просмотра на стороне клиента у меня есть следующее:

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

И мой метод расширения выводит следующее:

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

Но когда страница отображает, когда я проверяю элементы, я замечаю, что в поле value полей ввода задана пустая строка, которая, по моему мнению, связана с тем, как объявляются наблюдаемые. Но есть ли способ отменить это поведение или что-то еще?

4b9b3361

Ответ 1

Один из альтернатив, который вы можете использовать, чтобы сохранить код более чистым, - это использовать настраиваемую привязку, которая обертывает привязку значения, инициализируя ее текущим значением элемента.

Вы даже можете создать для наблюдаемых объектов свою модель просмотра, если они не существуют.

Связывание может выглядеть примерно так:

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] });
    }
};

Вы бы использовали его как:

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

Обратите внимание, что имя свойства находится в кавычках, это позволяет связыванию создавать его, если оно не существует, а не ошибка из значения undefined.

Вот пример: http://jsfiddle.net/rniemeyer/BnDh6

Ответ 2

Немного поздно здесь. На самом деле я не был доволен RP-ответом, потому что он нарушает декларативную природу нокаута. В частности, если вы используете valueWithInit для определения своего свойства, вы не можете использовать его в более раннем связывании. Здесь есть вилка его jsfiddle, чтобы продемонстрировать.

Вы используете его таким же образом, но он все еще документ декларативный под капотом:

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

Продолжая эту идею, вы также можете использовать ее для разделения инициализации и привязки:

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

Это немного избыточно, но становится полезным, когда вы используете плагин вместо встроенных привязок:

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

Расширив еще немного, мне также понадобился способ инициализации флажков:

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

И вот обработчики:

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);
    }
};

Примечание valueWithInit просто использует initValue под капотом.

Посмотрите в действии на jsfiddle.

Ответ 3

Если пользовательская привязка слишком тяжелая, то простым решением является инициализация наблюдаемых данных из DOM.

Например, учитывая следующую HTML-форму:

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

Затем нокаут можно инициализировать следующим образом:

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

Ответ 4

Вы можете просто использовать настраиваемую привязку и присваивать значения существующим наблюдаемым:

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

Затем просто добавьте класс или идентификатор к входам и data-bind="yourBindingName" к содержащему их элементу HTML.