2012-07-02 16 views
32

Ho riscontrato un problema con il binding "controllato" a eliminazione diretta. Sembra che l'evento "change" alla casella di controllo restituisca il vecchio valore, prima che venga aggiornato (quindi se è deselezionato restituirà false). Non penso di poterti iscrivere al valore poiché lo ho dentro l'oggetto.Evento di modifica della casella di controllo Knockout invia il vecchio valore

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

Quindi, in questo esempio ho ShowOpened casella di controllo che può innescare metodo CategoryChange che cambierà una variabile all'interno di oggetto (che ho bisogno in seguito per sapere quale oggetto vengono aggiornati). Ma quando viene cambiato il chechbox invia sempre il vecchio valore, il metodo di innesco, e quindi modifica il valore. C'è un modo per risolvere questo problema?

+1

C'è qualcosa che non va nel tuo codice. Né 'ShowOpened' né' IsUpdated' sono ko.observables (e probabilmente questo è il motivo per cui ottieni sempre il vecchio valore). Come può funzionare anche questo codice? 'CategoryChange' dovrebbe generare un'eccezione. – freakish

+1

@freakish sei wright, ho commesso un errore durante la creazione di questo post in origine. Ma l'errore che hai segnalato non è ancora il problema. – akhabaiev

+0

Oi, manca ancora questo: 'this.ShowOpened = ko.observable (ShowOpened);' e questo: 'pCategory.ShowOpened()'. Devo dire che hai commesso molti errori durante la stesura di questo post ... – freakish

risposta

57

Dal momento che si persistenti affermando che la mancanza di ko.observables non è un problema, ho guardato più da vicino. Sembra che tu abbia ragione! L'evento change viene generato prima del il valore effettivo è impostato. Temo di non sapere il motivo per questo.

Ma c'è un modo semplice per risolvere questo problema: basta cambiare change evento per click evento:

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

Ricordate, che bisogna mettere esplicitamente return true; alla fine del click gestore di eventi. Altrimenti il ​​nuovo valore non sarà impostato su checkbox.

Se non si desidera utilizzare l'evento click, è possibile farlo in un altro modo. Iscriviti ai cambiamenti di ShowOpened:

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

Ottimo, clicca l'evento funziona. L'ho provato a chiedere l'elemosina, ho semplicemente dimenticato di restituire true e la casella di controllo non è mai stata selezionata/deselezionata. Grazie. – akhabaiev

+0

Ho avuto esattamente lo stesso problema con IE non riconoscendo l'evento 'change'. Grr. – Brandon

+5

Funziona perfettamente! Grazie. Il "ritorno vero" è fondamentale per questo per funzionare correttamente! – mikemike396

6

Provare a utilizzare subscribe anziché associazione eventi. Questo dovrebbe funzionare ora

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

O in alternativa (e, a mio parere una soluzione migliore) è possibile utilizzare dependentObservable, ora chiamato computed. Ecco come sarebbe simile a

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

Ho anche avuto questo problema, ma non ho potuto usare la soluzione iscriviti perché ero già iscritto allo stesso campo con una richiesta Ajax che potrebbe reimpostare il valore. Il codice rimarrebbe quindi in un ciclo quando lo hai cambiato. Così ho aggiunto il seguente workaround (è brutto ma funziona).

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

Quindi, invece, ascoltando il cambiamento, vorrei ascoltare l'evento afterChange.

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

So che non è la soluzione migliore, ma nel mio caso non avevo altra scelta.

Problemi correlati