web-dev-qa-db-fra.com

L'événement de changement de case à cocher envoie l'ancienne valeur

J'ai un problème avec knock-out "vérifié" contraignant. Il semble que les événements "changer" de la case à cocher renvoient l'ancienne valeur avant sa mise à jour (donc, si cette case n'est pas cochée, elle retournera la valeur false). Je ne pense pas que je puisse souscrire à la valeur puisque je l'ai à l'intérieur de l'objet.

<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>

Donc, dans cet exemple, j'ai une case à cocher ShowOpened qui peut déclencher la méthode CategoryChange qui va changer une variable à l'intérieur de l'objet (dont j'ai besoin par la suite pour savoir quel objet est mis à jour). Mais lorsque la boîte à cocher est modifiée, elle envoie toujours l'ancienne valeur, la méthode de déclenchement, puis modifie la valeur. Est-ce qu'il y a un moyen de réparer ceci?

35
akhabaiev

Comme vous avez persisté à affirmer que l’absence de ko.observables n’est pas un problème, j’ai examiné la question de plus près. Il semble que vous ayez raison! L'événement change est déclenché avant la valeur réelle est définie. J'ai bien peur de ne pas en connaître la raison.

Mais il existe un moyen facile de résoudre ce problème: il suffit de changer l'événement change en événement click:

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

N'oubliez pas que vous devez explicitement mettre return true; à la fin du gestionnaire d'événements click. Sinon, la nouvelle valeur ne sera pas cochée.

Si vous ne souhaitez pas utiliser l'événement click, vous pouvez le faire dans l'autre sens. S'abonner aux modifications de ShowOpened:

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

Essayez d'utiliser subscribe au lieu de la liaison d'événement. Cela devrait fonctionner maintenant

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

Ou comme alternative (et à mon avis une meilleure solution) vous pouvez utiliser dependentObservable, maintenant appelé computed. Voici à quoi cela ressemblerait

<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);
6
Sasha Grinevich

J'ai également eu ce problème, mais je ne pouvais pas utiliser la solution subscribe, car j'étais déjà abonné au même champ avec une demande ajax pouvant réinitialiser la valeur. Le code resterait alors en boucle lorsque vous le modifieriez. J'ai donc ajouté la solution suivante (c'est moche mais ça marche).

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

Alors au lieu d'écouter le changement, j'écouterais l'événement afterChange.

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

Je sais que ce n'est pas la meilleure solution, mais dans mon cas, je n'avais pas d'autre choix. 

0
J. Visser