Knockout JS의 라디오 버튼에 참 / 거짓 바인딩


84

내 뷰 모델에는 true 또는 false 값이있는 IsMale 값이 있습니다.

내 UI에서 다음 라디오 버튼에 바인딩하고 싶습니다.

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

내가 생각하는 문제는 checked"true"/ "false"문자열을 기대한다는 것입니다 . 제 질문은이 UI와 모델을 사용하여이 양방향 바인딩을 어떻게 얻을 수 있습니까?


10
Knockout 버전> = 3.0 경우 허용 된 답변에서 제안한 것보다 더 간단한 soution에 대한 Natan의 답변 을 참조하십시오 .
Markus Pscheidt

답변:


81

한 가지 옵션은 쓰기 가능한 계산 된 Observable 을 사용하는 것 입니다.

이 경우, 좋은 옵션은 쓰기 가능 계산 된 관찰 가능 항목을 관찰 가능 항목의 "하위 관찰 가능 항목"으로 만드는 것 IsMale입니다. 보기 모델은 다음과 같습니다.

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

다음과 같이 UI에서 바인딩합니다.

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

샘플 : http://jsfiddle.net/rniemeyer/Pjdse/


훌륭한 솔루션 인 것 같습니다. 매핑 플러그인을 사용하여 VM을 새로 고칩니다. IsMale에서 ForEditing이 사라질 것이라는 것을 알고 있습니까?
CJ

26
다음은 계산 된 관찰 가능 생성을 사용자 지정 바인딩으로 푸시하는 대안입니다. 이렇게하면 매핑 플러그인에서 처리하는 것에 대해 걱정할 필요가 없습니다. jsfiddle.net/rniemeyer/utsvJ
RP Niemeyer

2
모든 객체에 대한 관찰을 바인딩을 사용하는 대신 작성하는 일
그렉 에니스를

1
@RPNiemeyer는 확실히 갈 길입니다.
Andrew

1
@RPNiemeyer 감사합니다! 댓글에있는 바이올린이 저에게 효과적이었습니다.
SFlagg

128

나는 이것이 오래된 스레드라는 것을 알고 있지만 동일한 문제가 있었고이 질문이 공식적으로 답변 된 후 녹아웃에 추가 된 훨씬 더 나은 솔루션을 발견했기 때문에 동일한 문제를 가진 사람들에게 남겨 두겠습니다.

현재 Extender, 사용자 정의 바인딩 핸들러 또는 계산이 필요하지 않습니다. "checkedValue"옵션을 제공하면 html 'value'속성 대신이 옵션을 사용하며 모든 javascript 값을 전달할 수 있습니다.

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

또는:

<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
소스를 보면 여기 에서 확인 된 값을 사용하기로 결정한 것 같습니다 . 입력이 라디오이거나 값이 배열 인 확인란 인 경우 'useCheckedValue'는 true로 설정됩니다 . 또한 Knockout 3.0을 사용하고 있습니다. 도움이되는지 확인하십시오.
Natan

1
예, 고마워요. 3.0.0으로 업그레이드했고 이제 거기에 있습니다. 서버 코드는 그 기대 때문에 아직 ;-) 문자열 내 부울 값을 래핑 할 필요가
ZiglioUK

좋은 정보. 두 가지 추가 사항 : (1) v3.0 이전 Knockout에서는 value바인딩 을 사용한 다음 checked바인딩 (순서대로)을 사용할 수 있었지만 3.0에서는 checkedValue바인딩 대신 바인딩 을 사용해야했습니다 value. (2) 사전 버전 3.0은 필요에 대한 까다로운했다 value앞에 바인딩 checked난 당신이 세우면 일이 모든 시나리오에서 버전 3.0에서 더 잘 작동 할 수 있다는 느낌 그래서, 제대로 작동하려면 바인딩을 checkedValue전과 바인딩 checked바인딩과 같습니다, 그들은 문서에 표시됩니다 .
Jason Frank

@ZiglioNZ 이것이 실패 할 수있는 한 가지 방법은 checkedsetter (또는 아마도 그것에 의존하는 무언가)가 오류를 발생시키는 것입니다 – 그런 다음 올바른 체크 박스를 체크하지 않는 것입니다
Simon_Weaver 2014-08-04

저는 3.4 버전을 사용하고 있는데 여전히 value = "true"와 위의 값을 넣어야 작동하게됩니다.
wirble

11

이것은 나를 위해 작동합니다.

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>

내가 보는 유일한 문제는 viewmodel을 직렬화하여 서버에 전달할 때 관찰 가능한 정수 (부울 대신)를 얻게된다는 것입니다. vm.IsMale(!!vm.+IsMale());서버로 보내기 위해 json을 직렬화하기 전에 호출해야 합니다 (서버 측에서 제대로 처리 할 수없는 경우)
Artem

나는 당신이 옳다고 생각하지만 Javascript 지식이 부족합니다. !! +가 어떻게 작동하는지 설명해 주시겠습니까? 나는 그 구문에 익숙하지 않다.
CJ

1
@CJ 이것은 문자열 또는 숫자를 부울로 변환합니다-이 jsfiddle.net/nickolsky/6ydLZ 첵 , 문자열이 이미 부울이면 부울로 유지합니다
Artem

매우 감사합니다. 나는 이것도 훌륭한 해결책이라고 생각합니다.
CJ

1
그래도 양방향으로 작동하지는 않습니다. 라디오 버튼은로드 될 때 확인되지 않습니다.
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);
        }
    }
};

어리석은 코 계산 관찰 가능 항목을 만드는 대신이 바인더를 사용하십시오.

예:

<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

당신이 알아낼 일단 라디오 버튼의 초기 경기 만 문자열과 일치하고 싶어 하고 문자열로 값을 설정하고자, 단순히 문자열에 초기 값을 변환하는 문제이다.나는 Int 값으로 이것을 싸워야했다.

Observable을 설정 한 후 값을 문자열로 변환하면 KO가 거기에서 마법을 수행합니다. 개별 라인으로 매핑하는 경우 해당 라인에서 변환을 수행하십시오.

예제 코드에서는 Json을 사용하여 단일 명령으로 전체 모델을 매핑합니다. 그런 다음 Razor가 변환을 위해 따옴표 사이에 값을 삽입하도록합니다.

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>

개발 중에 웹 페이지 하단에있는 "화면에 모두 덤프"를 사용합니다.

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

다음은 데이터 값입니다. 이전

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

그리고 이후

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

내 프로젝트에서는 같은 좌절감이없는 확인란을 사용할 수 있기 때문에 Bools를 변환 할 필요가 없었습니다.


0

1과 0 대신 단순히 참과 거짓이 아닌 이유는 무엇입니까?

 <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 객체를 보내는 경우 차이가 있습니다.
Doctor

0

익스텐더를 사용하여 더 많은 관찰 가능 항목에 쉽게 재사용 할 수 있습니다.

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

그런 다음 다음과 같이 사용하십시오.

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

제공되는 매개 변수 boolForEditing값이 널일 수 있는지 여부 표시하기 위해 입니다.

http://jsfiddle.net/G8qs9/1/ 참조


0

3.0 이전 버전의 녹아웃에 대해 많은 연구를 수행 한 후에는 두 가지 최선의 옵션이 있습니다.

다음과 같은 녹아웃 익스텐더 만들기

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

모델에서 익스텐더를 사용하려면 다음과 같이해야합니다.

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>

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.