Knockout bağlama ile seçili olay değiştir, bunun gerçek bir değişiklik olup olmadığını nasıl bilebilirim?


87

Bir izin kullanıcı arayüzü oluşturuyorum, her iznin yanında bir seçim listesi olan bir izinler listesi var. İzinler, seçilen bir listeye bağlı gözlemlenebilir nesneler dizisi ile temsil edilir:

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

Şimdi sorun şudur: değişiklik olayı, kullanıcı arayüzü ilk kez doldurulduğunda ortaya çıkar. Ajax işlevimi çağırıyorum, izinler listesini alıyorum ve ardından izin öğelerinin her biri için olay ortaya çıkıyor. Bu gerçekten istediğim davranış değil. Sadece bir kullanıcı seçim listesindeki izin için gerçekten yeni bir değer seçtiğinde yükseltilmesini istiyorum, bunu nasıl yapabilirim?

Yanıtlar:


109

Aslında olayın kullanıcı veya program tarafından tetiklenip tetiklenmediğini bulmak istiyorsunuz ve bu olayın başlatma sırasında tetikleyeceği açıktır.

Eklemenin nakavt yaklaşımı subscriptionher durumda yardımcı olmayacaktır, çünkü modelin çoğunda böyle uygulanacaktır.

  1. modeli tanımlanmamış verilerle başlatın, sadece yapı (actual KO initilization)
  2. modeli başlangıç ​​verileriyle güncelleyin (logical init like load JSON , get data etc)
  3. Kullanıcı etkileşimi ve güncellemeler

Yakalamak istediğimiz asıl adım 3'teki değişikliklerdir, ancak ikinci adımda subscriptionçağrı alacaktır, Yani daha iyi bir yol, olay değişikliğine aşağıdakiler gibi

 <select data-bind="value: level, event:{ change: $parent.permissionChanged}">

ve olay permissionChangedişlevinde tespit edildi

this.permissionChanged = function (obj, event) {

  if (event.originalEvent) { //user changed

  } else { // program changed

  }

}

5
Bunun doğru cevap olarak işaretlenmesi gerektiğini düşünüyorum. Soruda açıklandığı gibi tam senaryoya sahiptim ve selectöğenin Anahtarı olarak geçen dizeleri test ettim . Bununla birlikte, seçimin başlangıç ​​değeri seçeneklerden biriyle eşleşse bile, yine de changeolayı tetikledi . ifİşleyicide bu basit bloğu uyguladığımda , her şey beklendiği gibi çalıştı. Önce bu yöntemi deneyin. Teşekkürler @Sarath!
Pflugs

Kullanıcı değişti ve program değişti arasında ayrım yapma kavramını seviyorum. Bu, günlük durumlarda, özellikle gözlemlenebilirlerin herhangi bir kullanıcı etkileşimi olmadan değeri değiştirmesinin en muhtemel olduğu nakavt durumlarında yararlıdır.
rodiwa

@ Pflugs ile anlaşın, benim için işe yarayan olay türleri arasında ayrım yapın ve bu kabul edilen cevap olmalıdır.
Emma Middlebrook

1
def kabul edilen bir cevap ... etkinlik türü özelliği premissionChanged tetiklenmesi ayırt etmek için kullanılabilir olmalıdır
caniaskyouaquestion

1
Ayrıca, bir kullanıcının başka bir tetikleyici yerine bir seçimi değiştirip değiştirmediğini tespit etmek için bu yöntemi kullandı. Benim durumumda, seçenekler değerlerinin "seçenekler" bağlaması yoluyla güncellenmesi "değiştirme" olayını tetikledi.
nath

32

Bu sadece bir tahmin, ama bunun levelbir sayı olduğu için olduğunu düşünüyorum . Bu durumda, valuebağlama , dize değeriyle changegüncellenmesi için bir olayı tetikleyecektir level. Bu nedenle, levelbaşlamak için bir dize olduğundan emin olarak bunu düzeltebilirsiniz .

Ek olarak, bunu yapmanın daha "Nakavt" yolu olay işleyicileri kullanmak değil, gözlemlenebilirleri ve abonelikleri kullanmaktır. Make levelgözlemlenebilir ve ardından her çalışmasına alacak olan buna bir abonelik eklemek leveldeğişiklikleri.


Sayfanın yüklenmesinden sonra formumun 'değiştir' olayını tetiklemesinin nedenini araştırdıktan 2 saat sonra, beni kurtardığını tahmin ediyorsunuz.
Samih A

Cevabınız bana bir fikir verdi ... URL'den gelen türü kasıtlı olarak değiştirdim, böylece abone olma işlevim sayfa yüklemesini tetikleyecekti (sadece açılır listem bir değişikliği tetiklediğinde değil, bir url değişkenini işlemesini istedim). Bunu yapmanın daha az karmaşık bir yolu var mı?
Jiffy

4

İşte bu garip davranışa yardımcı olabilecek bir çözüm. Değişim olayını manuel olarak tetiklemek için bir düğme yerleştirmekten daha iyi bir çözüm bulamadım.

DÜZENLEME: Belki bunun gibi özel bir bağlama yardımcı olabilir:

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
            }

        });

    }
  };

Ve seçili veri bağlama özniteliğinizde şunu ekleyin:

changeSelectValue: yourSelectValue

oh ... bir kaydetme düğmesi gibi mi demek istiyorsun? .. benim için iyi değil .. gerçekten bunun işe yaramasına ihtiyacım var :)
guy schaller

Cevabı daha iyi bir çözümle düzenleyin (umarım).
Ingro

Hey Ingro, bu (yanlış) bir cevap olarak işaretlendi. İlk cümlenizi yeniden yazdım, böylece işaretçiler yanlışlıkla bir soruyu cevap olarak gönderdiğini düşünmesinler. Bu yardımcı olur umarım! :)
jmort253

@ jmort253: üzgünüm, bu benim hatamdı. "Bende de aynı sorun var" diye yanıt vermemek daha iyidir, çünkü bu başka bir şey soruyormuşsunuz gibi görünür. Bunun yerine, bir cevaba doğrudan bir çözüm sunun ve nasıl çalıştığını açıklayın.
Qantas 94 Heavy

1
Evet üzgünüm, benim hatam. Bu, stackoverflow'da yayınladığım ilk cevaplardan biriydi ve tüm kuralları bilmiyordum. Düzenleme için teşekkürler!
Ingro

3

Ben (dayanan bağlayıcı Bu özel kullanmak bu , onun cevabını bkz RP Niemeyer keman bu kesin sayısal değer düzgün (Michael Best çözümü önerdiği gibi) sayıya dize dönüştürülür yapar sorusuna):

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

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

2

İlkel bir değer yerine gözlemlenebilir bir değer kullanırsanız, seçme, ilk bağlamada değişiklik olayları oluşturmaz. Doğrudan gözlemlenebilir olana abone olmak yerine değişiklik olayına bağlanmaya devam edebilirsiniz.


1

Basit bir bayrak kullanarak hızlı ve kirli:

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

Bu işe yaramazsa, setTimeout () içindeki son satırı kaydırmayı deneyin - olaylar eşzamansızdır, bu nedenle, applyBindings () zaten döndürüldüğünde belki de sonuncusu beklemede olabilir.


merhaba cevap için teşekkürler, bu benim için işe yaramayacak çünkü dom hazır olduğunda ko.applyBindings'i çağırıyorum, ancak izinlerim a modelime daha sonraki bir aşamada dolduruluyor ... bu yüzden bayrak doğru olurdu ama sorun yine de olacaktır.
guy schaller

0

Benzer bir sorun yaşadım ve değişkenin türünü kontrol etmek için olay işleyicisini değiştirdim. Tür, sayfa ilk yüklendiğinde değil, yalnızca kullanıcı bir değer seçtikten sonra ayarlanır.

self.permissionChanged = function (l) {
    if (typeof l != 'undefined') {
        ...
    }
}

Bu benim için çalışıyor gibi görünüyor.


0

bunu kullan:

this.permissionChanged = function (obj, event) {

    if (event.type != "load") {

    } 
}

0

Bunu dene:

self.GetHierarchyNodeList = function (data, index, event)
{
    debugger;
    if (event.type != "change") {
        return;
    }        
} 

event.type == "change"
event.type == "load" 

2. parametre indeks değildi, benim için olaydı.
sairfan

@sairfan, işleve birkaç parametre ekler ve hata ayıklayıcıyı kullanarak hangi parametreden olay aldığınızı bulun
Chanaka Sampath

-1

Altını Gizlemeyi kullanarak çalışıyorsanız, gözlenebilir işlevsellik devre dışı bırakmanın temel işlevini kullanın. Yöntemi
kullanın ko.computed()ve bu işlev içinde ajax çağrısını yapın ve tetikleyin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.