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

Событие изменения флажка нокаута отправляет старое значение

У меня возникла проблема с проверкой привязки нокаутом. Кажется, что событие "change" на флажке возвращает старое значение, прежде чем оно будет обновлено (поэтому, если оно не было отмечено, оно вернет false). Я не думаю, что могу подписаться на значение, так как у меня есть его внутри объекта.

<tbody data-bind="foreach: Categories">
                <tr>
                    <td><input type="checkbox" data-bind="checked: ShowOpened, event: { change: $root.CategoryChange }" /></td>
                </tr>
            </tbody>
<script type="text/javascript">
var Category = function (Id, Name, Order, ShowOpened) {
    this.Id = Id;
    this.Name = Name;
    this.Order = Order;
    this.ShowOpened = ShowOpened;
    this.IsUpdated = ko.observable(false);

    this.OldOrder = Order;
    this.OldShowOpened = ShowOpened;
};
var ViewModel = {
    Categories: ko.observableArray([]),
    CategoryChange: function(pCategory) {
        if(pCategory.Order != pCategory.OldOrder || pCategory.ShowOpened != pCategory.OldShowOpened)
            pCategory.IsUpdated(true);
        else
            pCategory.IsUpdated(false);
    }
};
ko.applyBindings(ViewModel);
</script>

Итак, в этом примере у меня установлен флажок ShowOpened, который может вызывать метод CategoryChange, который изменит переменную внутри объекта (что мне нужно позже, чтобы узнать, какой объект обновлен). Но когда chechbox изменен, он всегда отправляет старое значение, метод запуска, а затем меняет значение. Есть ли способ исправить это?

4b9b3361

Ответ 1

Поскольку вы настаивали на том, что отсутствие ko.observables не проблема, я посмотрел на нее ближе. Кажется, вы правы! Событие change запускается до, когда установлено фактическое значение. Боюсь, я не знаю причину этого.

Но есть простой способ исправить это: просто измените событие change на событие click:

<input type="checkbox" data-bind="checked: ShowOpened, click: $root.CategoryChange" />

Помните, что вы должны явно помещать return true; в конец обработчика события click. В противном случае новое значение не будет установлено на флажок.

Если вы не хотите использовать событие click, вы можете сделать это другим способом. Подпишитесь на изменения ShowOpened:

this.ShowOpened = ko.observable(ShowOpened);
this.ShowOpened.subscribe(function(newValue) {
    /* Do something when ShowOpened changes.
       newValue variable holds the new value, obviously. :) */
});

Ответ 2

Попробуйте использовать subscribe вместо привязки к событию. Это должно работать сейчас

<table>
    <tbody data-bind="foreach: Categories">
        <tr>
            <td><input type="checkbox" data-bind="checked: ShowOpened" /></td>
        </tr>
    </tbody>
<table>

var Category = function (Id, Name, Order, ShowOpened) {
    this.Id = Id;
    this.Name = Name;
    this.Order = Order;
    this.ShowOpened = ko.observable(ShowOpened);
    this.IsUpdated = false;

    this.OldOrder = Order;
    this.OldShowOpened = ShowOpened;

    this.ShowOpened.subscribe(function (newShowOpened) {
        if(this.Order != this.OldOrder || this.ShowOpened() != this.OldShowOpened)
            this.IsUpdated = true;
        else
            this.IsUpdated = false;
    }, this);
};
var ViewModel = {
    Categories: ko.observableArray([])
};
ko.applyBindings(ViewModel);

Или как альтернатива (и, на мой взгляд, лучшее решение), вы можете использовать dependentObservable, теперь называемый computed. Вот как это будет выглядеть

<table>
    <tbody data-bind="foreach: Categories">
        <tr>
            <td>
                <input type="checkbox" data-bind="checked: ShowOpened" />
                <span data-bind="text: IsUpdated"></span>
            </td>
        </tr>
    </tbody>
</table>
var Category = function (Id, Name, Order, ShowOpened) {
    this.Id = Id;
    this.Name = Name;
    this.Order = Order;
    this.ShowOpened = ko.observable(ShowOpened);
    this.OldOrder = Order;
    this.OldShowOpened = ShowOpened;
    this.IsUpdated = ko.computed(function () {
        return this.Order != this.OldOrder || this.ShowOpened() != this.OldShowOpened;
    }, this);
};
var ViewModel = {
    Categories: ko.observableArray([])
};
ko.applyBindings(ViewModel);

Ответ 3

У меня также была эта проблема, но я не мог использовать решение подписки, потому что я уже подписался на одно и то же поле с запросом ajax, который мог бы reset значение. Тогда код будет оставаться в цикле, когда вы его измените. Поэтому я добавил следующее обходное решение (его уродливое, но оно работает).

$("input[type='radio'], input[type='checkbox']", element).on("change", function (e, data) {
    setTimeout(function () {
        $(this).trigger("afterChange", data);
    }.bind(this), 10);
}); 

Тогда вместо прослушивания изменения я прослушал событие afterChange.

<div data-bind="foreach: answerList">
    <input type="checkbox" data-bind="event: { afterChange: $root.sendSelectedAnswer($data) }"/>
</div>

Я знаю, что это не лучшее решение, но в моем случае у меня не было другого выбора.