Buduję interfejs użytkownika dotyczący uprawnień, mam listę uprawnień z listą wyboru obok każdego uprawnienia. Uprawnienia są reprezentowane przez obserwowalną tablicę obiektów, które są powiązane z listą wyboru:
<div data-bind="foreach: permissions">
<div class="permission_row">
<span data-bind="text: name"></span>
<select data-bind="value: level, event:{ change: $parent.permissionChanged}">
<option value="0"></option>
<option value="1">R</option>
<option value="2">RW</option>
</select>
</div>
</div>
Teraz problem jest następujący: zdarzenie zmiany jest zgłaszane, gdy interfejs użytkownika jest wypełniany po raz pierwszy. Wywołuję moją funkcję Ajax, pobieram listę uprawnień, a następnie zdarzenie jest zgłaszane dla każdego elementu uprawnień. To naprawdę nie jest zachowanie, którego chcę. Chcę, aby było podnoszone tylko wtedy, gdy użytkownik naprawdę wybierze nową wartość uprawnienia na liście wyboru , jak mogę to zrobić?
źródło
select
elementu. Jednak nawet gdy początkowa wartość zaznaczenia pasowała do jednej z opcji, nadal wyzwalałachange
zdarzenie. Kiedy zaimplementowałem ten prostyif
blok w module obsługi, wszystko działało zgodnie z oczekiwaniami. Najpierw wypróbuj tę metodę. Dzięki, @Sarath!To tylko przypuszczenie, ale myślę, że dzieje się tak, ponieważ
level
jest liczbą. W takim przypadkuvalue
powiązanie wyzwolichange
zdarzenie do aktualizacjilevel
o wartość ciągu. Dlatego możesz to naprawić, upewniając się, żelevel
jest to ciąg znaków, od którego należy zacząć.Dodatkowo, bardziej "Knockout" sposobem na to jest nie używanie programów obsługi zdarzeń, ale użycie obserwabli i subskrypcji. Utwórz
level
obserwowalny, a następnie dodaj do niego subskrypcję, która będzie uruchamiana po każdejlevel
zmianie.źródło
Oto rozwiązanie, które może pomóc w tym dziwnym zachowaniu. Nie mogłem znaleźć lepszego rozwiązania niż umieszczenie przycisku, aby ręcznie wywołać zdarzenie zmiany.
EDYCJA: Może takie niestandardowe wiązanie mogłoby pomóc:
ko.bindingHandlers.changeSelectValue = { init: function(element,valueAccessor){ $(element).change(function(){ var value = $(element).val(); if($(element).is(":focus")){ //Do whatever you want with the new value } }); } };
W wybranym atrybucie powiązania danych dodaj:
źródło
Używam tego niestandardowego powiązania (na podstawie tego skrzypiec RP Niemeyera, zobacz jego odpowiedź na to pytanie), które zapewnia, że wartość liczbowa jest poprawnie konwertowana ze ciągu na liczbę (zgodnie z rozwiązaniem Michaela Besta):
JavaScript:
ko.bindingHandlers.valueAsNumber = { init: function (element, valueAccessor, allBindingsAccessor) { var observable = valueAccessor(), interceptor = ko.computed({ read: function () { var val = ko.utils.unwrapObservable(observable); return (observable() ? observable().toString() : observable()); }, write: function (newValue) { observable(newValue ? parseInt(newValue, 10) : newValue); }, owner: this }); ko.applyBindingsToNode(element, { value: interceptor }); } };
Przykładowy kod HTML:
<select data-bind="valueAsNumber: level, event:{ change: $parent.permissionChanged }"> <option value="0"></option> <option value="1">R</option> <option value="2">RW</option> </select>
źródło
Jeśli użyjesz obserwowalnej zamiast wartości pierwotnej, wybór nie zgłosi zdarzeń zmiany przy początkowym powiązaniu. Możesz kontynuować tworzenie powiązania ze zdarzeniem zmiany, zamiast subskrybować bezpośrednio to, co można zaobserwować.
źródło
Szybko i brudno, z wykorzystaniem prostej flagi:
var bindingsApplied = false; var ViewModel = function() { // ... this.permissionChanged = function() { // ignore, if flag not set if (!flag) return; // ... }; }; ko.applyBindings(new ViewModel()); bindingsApplied = true; // done with the initial population, set flag to true
Jeśli to nie zadziała, spróbuj zawinąć ostatnią linię w setTimeout () - zdarzenia są asynchroniczne, więc być może ostatni z nich jest nadal w toku, gdy applyBindings () jest już zwrócony.
źródło
Miałem podobny problem i właśnie zmodyfikowałem procedurę obsługi zdarzeń, aby sprawdzić typ zmiennej. Typ jest ustawiany dopiero po wybraniu wartości przez użytkownika, a nie przy pierwszym załadowaniu strony.
self.permissionChanged = function (l) { if (typeof l != 'undefined') { ... } }
To wydaje się działać dla mnie.
źródło
Użyj tego:
this.permissionChanged = function (obj, event) { if (event.type != "load") { } }
źródło
Spróbuj tego:
self.GetHierarchyNodeList = function (data, index, event) { debugger; if (event.type != "change") { return; } } event.type == "change" event.type == "load"
źródło
Jeśli pracujesz z knockoutem, użyj kluczowej funkcjonalności, jaką jest nokaut obserwowalnej funkcjonalności.
Użyj
ko.computed()
metody i wykonaj i uruchom wywołanie ajax w ramach tej funkcji.źródło