Knockout JS'de radyo düğmelerine doğru / yanlış bağlama


84

Görüş modelimde, true veya false değerine sahip bir IsMale değerim var.

Kullanıcı arayüzümde onu aşağıdaki radyo düğmelerine bağlamak istiyorum:

<label>Male
   <input type="radio" name="IsMale" value="true" data-bind="checked:IsMale"/>
</label> 
<label>Female
   <input type="radio" name="IsMale" value="false" data-bind="checked:IsMale"/>
</label>

Sanırım sorun, checked"doğru" / "yanlış" dizesini beklemektir. Öyleyse sorum şu, bu kullanıcı arayüzü ve modelle bu 2 yönlü bağlamayı nasıl elde edebilirim?


10
Nakavt sürümleri için> = 3.0 bakınız Natan cevabını kabul cevap önerdiği daha basit SOUTION için.
Markus Pscheidt

Yanıtlar:


81

Bir seçenek, yazılabilir, hesaplanmış bir gözlemlenebilir kullanmaktır .

Bu durumda, güzel bir seçenek, yazılabilir hesaplanmış gözlemlenebilir olanı, sizin IsMalegözlemlenebilirinizin bir "alt-gözlemlenebilir" haline getirmektir . Görünüm modeliniz şöyle görünür:

var ViewModel = function() {
   this.IsMale = ko.observable(true);

   this.IsMale.ForEditing = ko.computed({
        read: function() {
            return this.IsMale().toString();  
        },
        write: function(newValue) {
             this.IsMale(newValue === "true");
        },
        owner: this        
    });          
};

Bunu kullanıcı arayüzünüzde şu şekilde bağlarsınız:

<label>Male
   <input type="radio" name="IsMale" value="true" data-bind="checked:IsMale.ForEditing"/>
</label> 
<label>Female
   <input type="radio" name="IsMale" value="false" data-bind="checked:IsMale.ForEditing"/>
</label>

Örnek: http://jsfiddle.net/rniemeyer/Pjdse/


Harika bir çözüm gibi görünüyor. Sanal makinemi yenilemek için eşleme eklentisini kullanıyorum. IsMale'de ForEditing'in silineceğini biliyor musunuz?
CJ

26
Burada, hesaplanan gözlemlenebilir yaratımı özel bir bağlama içine iten bir alternatif var, bu da onu haritalama eklentisinde onunla uğraşmaktan endişelenmenize gerek kalmayacak hale getirecek: jsfiddle.net/rniemeyer/utsvJ
RP Niemeyer

2
Her nesnede bir gözlemlenebilir oluşturmak yerine bir bağlama kullanmaya +1
Greg Ennis

1
@RPNiemeyer kesinlikle gitmenin yolu.
Andrew

1
@RPNiemeyer teşekkürler! yorumlardaki o keman benim için işe yaradı.
SFlagg

128

Bunun eski bir konu olduğunu biliyorum, ama aynı sorunu yaşıyordum ve muhtemelen bu soru resmi olarak yanıtlandıktan sonra nakavt için eklenen çok daha iyi bir çözüm buldum, bu yüzden onu aynı sorunu olan insanlar için bırakacağım.

Şu anda genişleticilere, özel ciltleme işleyicilerine veya hesaplananlara ihtiyaç yoktur. Yalnızca bir "checkValue" seçeneği sağlayın, html "değer" özelliği yerine bunu kullanır ve bununla herhangi bir javascript değerini iletebilirsiniz.

<input type="radio" name="a" data-bind="checked:IsChecked, checkedValue: true"/>
<input type="radio" name="a" data-bind="checked:IsChecked, checkedValue: false"/>

Veya:

<input type="radio" name="b" data-bind="checked:Quantity, checkedValue: 1"/>
<input type="radio" name="b" data-bind="checked:Quantity, checkedValue: 2"/>
<input type="radio" name="b" data-bind="checked:Quantity, checkedValue: 3"/>

2
Kaynağa bakıldığında, burada kontrol edilen değeri kullanma kararı veriyor gibi görünüyor . 'UseCheckedValue', giriş bir radyo veya değeri dizi olarak içeren bir onay kutusuysa true olarak ayarlanır . Ayrıca, Knockout 3.0 kullanıyorum. Bunun yardımcı olup olmadığına bak.
Natan

1
evet, teşekkürler, 3.0.0'a yükselttim ve şimdi orada. Yine de boole değerlerimi bir
String'e sarmam gerekiyor

İyi bilgi. İki ek nokta: (1) Ön v3.0 Knockout ile önce valuebağlamayı ve ardından checkedbağlamayı (bu sırayla) kullanabildiğimi buldum, ancak 3.0 ile checkedValuebağlama yerine bağlama kullanmak zorunda kaldım value. (2) ön v3.0 gerektiren konusunda seçici oldu valueönce bağlanma checkedSana koyarsanız şeyler aynı zamanda tüm senaryolarda v3.0 daha iyi işe yarayabilecek bir duygu var bu yüzden doğru işlevine bağlanma checkedValueönce bağlanmasını checkedbağlama gibi onlar göstermek docs .
Jason Frank

@ZiglioNZ bunun başarısız olmasının bir yolu, checkedayarlayıcınız (veya belki ona bağlı bir şey) bir hata verirse - o zaman doğru onay kutusu işaretlenmez
Simon_Weaver

3.4 sürümünü kullanıyorum ve işe yaraması için hala value = "true" ve yukarısını koymam gerektiğini buluyorum.
wirble

11

Bu benim için çalışıyor:

http://jsfiddle.net/zrBuL/291/

<label>Male
   <input type="radio" name="IsMale" value="1" data-bind="checked:IsMale"/>
</label> 
<label>Female
   <input type="radio" name="IsMale" value="0" data-bind="checked:IsMale"/>
</label>

Gördüğüm tek sorun, viewmodel'i sunucuya geçirmek için serileştirirken, gözlemlenebilir tam sayılar (boole yerine) elde edeceğinizdir. vm.IsMale(!!vm.+IsMale());Sunucuya göndermek için json'u seri hale getirmeden önce aramanız gerekecek (sunucu tarafı bunu düzgün bir şekilde işleyemezse)
Artem

Sanırım haklısın, ancak Javascript bilgim yetersiz. Lütfen bana !! + 'ın nasıl çalıştığını açıklar mısınız? Bu sözdizimine aşina değilim.
CJ

1
@CJ bu, dizeyi veya sayıyı boole'ye dönüştürür - bu jsfiddle.net/nickolsky/6ydLZ'yi kontrol edin , eğer dize zaten bool ise, bool olarak tutacaktır
Artem

Çok teşekkürler. Bunun da harika bir çözüm olduğunu düşünüyorum.
CJ

1
Her iki şekilde de çalışmıyor. Radyo düğmeleri yüklendiğinde kontrol edilmez.
Mikael Östberg

1
ko.bindingHandlers['radiobuttonyesno'] = {
    'init': function (element, valueAccessor, allBindingsAccessor) {
        var stateHandler = function (property, allBindingsAccessor, key, value, checkIfDifferent) {
            if (!property || !ko.isObservable(property)) {
                var propWriters = allBindingsAccessor()['_ko_property_writers'];
                if (propWriters && propWriters[key])
                    propWriters[key](value);
            } else if (ko.isWriteableObservable(property) && (!checkIfDifferent || property.peek() !== value)) {
                property(value);
            }
        };

        var updateHandler = function () {
            var valueToWrite;

            if ((element.type == "radio") && (element.checked)) {
                valueToWrite = element.value;
            } else {
                return; // "radiobuttonyesno" binding only responds to selected radio buttons
            }

            valueToWrite = (valueToWrite === "True") ? true : false;

            var modelValue = valueAccessor(), unwrappedValue = ko.utils.unwrapObservable(modelValue); //can be true of false

            stateHandler(modelValue, allBindingsAccessor, 'checked', valueToWrite, true);
        };
        ko.utils.registerEventHandler(element, "click", updateHandler);

        // IE 6 won't allow radio buttons to be selected unless they have a name
        if ((element.type == "radio") && !element.name)
            ko.bindingHandlers['uniqueName']['init'](element, function () { return true });
    },
    'update': function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());

        value = value ? "True" : "False";

        if (element.type == "radio") {
            element.checked = (element.value == value);
        }
    }
};

Aptal ko hesaplanmış gözlemlenebilirler oluşturmak yerine bu bağlayıcıyı kullanın.

Misal:

<label>Male
        <input type="radio" name="IsMale" value="True" data-bind="radiobuttonyesno:IsMale"/>
     </label> 
     <label>Female
        <input type="radio" name="IsMale" value="False" data-bind="radiobuttonyesno:IsMale"/>
     </label>

1

Radyo düğmesi için ilk eşleşmenin yalnızca bir dizeyle eşleşmek istediğini ve değeri bir dizeye ayarlamak istediğini anladıktan sonra , bu basitçe başlangıç ​​değerinizi dizeye dönüştürmekle ilgilidir. Bununla Int değerleri ile savaşmak zorunda kaldım.

Gözlenebilirlerinizi kurduktan sonra, değeri dizgeye çevirin ve KO sihrini oradan yapacaktır. Tek tek çizgilerle eşleme yapıyorsanız, dönüşümü bu satırlarda yapın.

Örnek kodda, tüm Modeli tek bir komutta eşlemek için Json kullanıyorum. Ardından, Razor'ın değeri dönüşüm için tırnak işaretleri arasına eklemesine izin verin.

script type="text/javascript">
    KoSetup.ViewModel = ko.mapping.fromJS(@Html.Raw(Json.Encode(Model)));
    KoSetup.ViewModel.ManifestEntered("@Model.ManifestEntered");       //Bool
    KoSetup.ViewModel.OrderStatusID("@Model.OrderStatusID");           //Int
</script>

Geliştirme sırasında web sayfamın altında "Hepsini ekrana dök" kullanıyorum.

<h4>Debug</h4>
<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>

İşte veri değerleri, Önce

"OrderStatusID": 6,
"ManifestEntered": true,

ve sonra

"OrderStatusID": "6",
"ManifestEntered": "True",

Projemde Bools'u dönüştürmem gerekmedi, çünkü aynı hayal kırıklığına sahip olmayan bir onay kutusu kullanabiliyorum.


0

Neden 1 ve 0 yerine sadece doğru ve yanlış değil?

 <label>Male
    <input type="radio" name="IsMale" value="true" data-bind="checked:IsMale"/>
 </label> 
 <label>Female
    <input type="radio" name="IsMale" value="false" data-bind="checked:IsMale"/>
 </label>

2
json nesneleri gönderiyorsanız fark yaratır.
Doktor

0

Ayrıca bir genişletici de kullanabilirsiniz, böylece onları daha fazla gözlemlenebilir için yeniden kullanmak kolaydır:

ko.extenders.boolForEditing = function (target, allowNull) {
    var result = ko.computed({
        read: function () {
            var current = target();
            var newValue = null;
            if (current === undefined || current === null || current === '') {
                if (!allowNull) {
                    newValue = 'false';
                }
            } else {
                newValue = current ? 'true' : 'false';
            }
            return newValue;
        },
        write: function (newValue) {
            var current = target();
            var valueToWrite = null;
            if (newValue === undefined || newValue === null || newValue === '') {
                if (!allowNull) {
                    valueToWrite = false;
                }
            } else {
                valueToWrite = newValue === 'true';
            }
            // only write if it changed
            if (valueToWrite !== current) {
                target(valueToWrite);
            } else {
                if (newValue !== current) {
                    target.notifySubscribers(valueToWrite);
                }
            }
        }
    }).extend({
        notify: 'always'
    });

    result(target());

    return result;
};

O zaman şu şekilde kullanın:

this.IsMale.forEditing = this.IsMale.extend({boolForEditing: true});

boolForEditingDeğerin boş olup olmadığını belirtmek için sağlanan parametre .

Bkz http://jsfiddle.net/G8qs9/1/


0

3.0'dan önceki eski nakavt sürümü için çok araştırma yaptıktan sonra, muhtemelen en iyi iki seçenek vardır.

Şunun gibi bir nakavt genişletici oluşturun

ko.extenders["booleanValue"] = function (target) {
    target.formattedValue = ko.computed({
        read: function () {
            if (target() === true) return "True";
            else if (target() === false) return "False";
        },
        write: function (newValue) {
            if (newValue) {
                if (newValue === "False") target(false);
                else if (newValue === "True") target(true);
            }
        }
    });

    target.formattedValue(target());
    return target;
};

Modelinizde genişleticiyi kullanmak için aşağıdaki gibi bir şey yapmalısınız:

function Order() {
  this.wantsFries= ko.observable(false).extend({ booleanValue: null });
}

<span>Do you want fries with that?</span>
<label>
  <input type="radio" name="question" value="True"
             data-bind="value: wantsFries.formattedValue" /> Yes
</label>
<label>
  <input type="radio" name="question" value="False"
             data-bind="value: wantsFries.formattedValue" /> No
</label>

kaynak: http://www.timlabonne.com/2013/02/building-a-knockout-js-extender-for-boolean-values/

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.