-1

JSON DATA

    [
    {
        "ErrorCode": 0,
        "ErrorMessage": null,
        "Heading": "Assessment",
        "SectionsSet": [
            {
                "ErrorCode": 0,
                "ErrorMessage": null,
                "Heading": "Assessment",
                "SectionsSet": [],
                "QuestionsSet": [
                    {
                        "ErrorCode": 0,
                        "ErrorMessage": null,
                        "Available": true,
                        "DisplayValue": "Q1",
                        "QuestionText": "What is the status of an advance care planning assessment?",
                        "TopLevel": true,
                        "Type": 1,
                        "AnswersSet": [
                            {
                                "ErrorCode": 0,
                                "ErrorMessage": null,
                                "Available": true,
                                "InputType": "text",
                                "Value": null,
                                "Text": "Advance care planning information has already been provided:",
                                "MutuallyExclusive": false,
                                "Selected": false,
                                "QuestionRefSet": [],
                                "GuidelineLinkSet": [],
                                "ChildQuestions": null,
                                "QuestionRefSetStrings": "",
                                "RadioOnly": true,
                                "HtmlText": "Advance care planning information has already been provided:",
                                "AnnotationSet": [],
                                "CitationSet": [],
                                "FootnoteSet": [],
                                "Id": "406",
                                "SortOrder": 1,
                                "Uid": "s/Assessment1-s78832-q1954-a406"
                            },
                            {
                                "ErrorCode": 0,
                                "ErrorMessage": null,
                                "Available": true,
                                "InputType": "text",
                                "Value": null,
                                "Text": "Advance care planning assessment is scheduled for a later date:",
                                "MutuallyExclusive": false,
                                "Selected": false,
                                "QuestionRefSet": [],
                                "GuidelineLinkSet": [],
                                "ChildQuestions": null,
                                "QuestionRefSetStrings": "",
                                "RadioOnly": true,
                                "HtmlText": "Advance care planning assessment is scheduled for a later date:",
                                "AnnotationSet": [],
                                "CitationSet": [],
                                "FootnoteSet": [],
                                "Id": "407",
                                "SortOrder": 2,
                                "Uid": "s/Assessment1-s78832-q1954-a407"
                            },
                            {
                                "ErrorCode": 0,
                                "ErrorMessage": null,
                                "Available": true,
                                "InputType": "text",
                                "Value": null,
                                "Text": "Not appropriate to conduct advance care planning assessment with person reachable today:",
                                "MutuallyExclusive": false,
                                "Selected": false,
                                "QuestionRefSet": [],
                                "GuidelineLinkSet": [],
                                "ChildQuestions": null,
                                "QuestionRefSetStrings": "",
                                "RadioOnly": true,
                                "HtmlText": "Not appropriate to conduct advance care planning assessment with person reachable today:",
                                "AnnotationSet": [],
                                "CitationSet": [],
                                "FootnoteSet": [],
                                "Id": "408",
                                "SortOrder": 3,
                                "Uid": "s/Assessment1-s78832-q1954-a408"
                            },
                            {
                                "ErrorCode": 0,
                                "ErrorMessage": null,
                                "Available": true,
                                "InputType": "text",
                                "Value": null,
                                "Text": "Other:",
                                "MutuallyExclusive": false,
                                "Selected": false,
                                "QuestionRefSet": [],
                                "GuidelineLinkSet": [],
                                "ChildQuestions": null,
                                "QuestionRefSetStrings": "",
                                "RadioOnly": true,
                                "HtmlText": "Other:",
                                "AnnotationSet": [],
                                "CitationSet": [],
                                "FootnoteSet": [],
                                "Id": "1917",
                                "SortOrder": 4,
                                "Uid": "s/Assessment1-s78832-q1954-a1917"
                            },
                            {
                                "ErrorCode": 0,
                                "ErrorMessage": null,
                                "Available": true,
                                "InputType": null,
                                "Value": null,
                                "Text": "Don't know/Not sure",
                                "MutuallyExclusive": false,
                                "Selected": false,
                                "QuestionRefSet": [],
                                "GuidelineLinkSet": [],
                                "ChildQuestions": null,
                                "QuestionRefSetStrings": "",
                                "RadioOnly": true,
                                "HtmlText": "Don't know/Not sure",
                                "AnnotationSet": [],
                                "CitationSet": [],
                                "FootnoteSet": [],
                                "Id": "6",
                                "SortOrder": 5,
                                "Uid": "s/Assessment1-s78832-q1954-a6"
                            }
                        ],
                        "QuestionReferencesSet": null,
                        "ChildQuestions": null,
                        "HtmlText": "What is the status of an advance care planning assessment?",
                        "AnnotationSet": [],
                        "CitationSet": [],
                        "FootnoteSet": [],
                        "Id": "1954",
                        "SortOrder": 1,
                        "Uid": "s/Assessment1-s78832-q1954"
                    }
]

HTML Code for radio button where trueFalseRadioButton is the custom binding. $data.Selected is the value that will contain frue/false and $data.RadioOnly will have the value either true/false.

<!-- language: lang-html -->

<div data-bind="foreach: GuidelinesSubmitList">
        <div data-bind="foreach: $data.SectionsSet">
            <div data-bind="foreach: $data.SectionsSet">
                <div>
                    <p class="primaryCaseHeader" data-bind="attr:{onClick: 'variableName.CollapseExpandCustom.ToggleSection(\''+$data.Id+'\')'}">
                        <span data-bind="text: $root.SplitGuidelinesQuestionHeading() + '- '+ $data.Heading"></span><img src="/Images/Collapse.png">
                    </p>
                    <div>
                        <div class="primaryCaseMain" data-bind="attr:{id:$data.Id}">
                            <div data-bind="foreach: $data.QuestionsSet">
                                <div class="primaryCaseContainer" data-bind="attr: {id: $data.Id } , visible: $data.Available, toplevel: $data.TopLevel">
                                    <p class="questionHeader">
                                        <span data-bind="text: $data.DisplayValue+'.'"></span>
                                        <span data-bind="html: GetEditListGuidelineQuestion.HtmlReplace($data.HtmlText)"></span>
                                    </p>
                                    <div data-bind="attr:{id: 'colapseID'+$data.Id }" class="questionContainer">

                                        <div data-bind="foreach: $data.AnswersSet">

                                            <!--ko if:$parent.Type == 2 -->
                                            <div data-bind="attr:{class: $parent.Id +' marginTopTbl'}">
                                                <input type="checkbox" data-bind="attr:{id: $data.Id , Qid: $parent.Id , Qref: $data.QuestionRefSetStrings , Uid: $data.Uid , rel: $data.MutuallyExclusive ? 'true' : 'false'} ,checked: $data.Selected, click: $root.answerClick , if: $root.appendQrefQuestion($data.QuestionRefSetStrings)">
                                                <span data-bind="html: GetEditListGuidelineQuestion.HtmlReplace($data.HtmlText)"></span>
                                                <span><b data-bind="text: $root.findQuestionref($data.QuestionRefSet)"></b></span>
                                                <!--ko if:$data.InputType == "text" -->
                                                <input type="text" data-bind="if: Selected, textInput : $data.Value, attr:{id: $data.Id , name:$parent.Id,  Qid: $parent.Id, Qref: $data.QuestionRefSetStrings , Uid: $data.Uid}">
                                                <!-- /ko -->
                                            </div>
                                            <!-- /ko -->
                                            <!--ko if:$parent.Type == 1 -->
                                            <div data-bind="attr:{class: $parent.Id +' marginTopTbl'}">
                                                <input type="radio" data-bind="value: $data.RadioOnly, attr:{id: $data.Id , name:$parent.Id,  Qid: $parent.Id, Qref: $data.QuestionRefSetStrings , Uid: $data.Uid},  trueFalseRadioButton:  $data.Selected , click: $root.answerClick , if: $root.appendQrefQuestion($data.QuestionRefSetStrings)">
                                                <span data-bind="html: GetEditListGuidelineQuestion.HtmlReplace($data.HtmlText)"></span>
                                                <span><b data-bind="text: $root.findQuestionref($data.QuestionRefSet)"></b></span>
                                                <!--ko if:$data.InputType == "text" -->
                                                <input type="text" data-bind="if: Selected , textInput: $data.Value , attr:{id: $data.Id , name:$parent.Id,  Qid: $parent.Id, Qref: $data.QuestionRefSetStrings , Uid: $data.Uid}">
                                                <!-- /ko -->
                                            </div>
                                            <!-- /ko -->
                                        </div>
                                        <div class="subQuestion" style="margin-left: 10px; margin-top: 10px" ></div>

                                    </div>
                                </div>

                            </div>

                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

Knockout code for custom binding

var GuidelineQuestion =
    {

GetGuildlineQuestion: function () {

            var self = this;
            var ajaxUrl = ApplicationRootUrl("GetGuildlineQuestionold", "MCGGuidelines");
            $('#loading').show();

            $.ajax({
                type: "POST",
                url: ajaxUrl,
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                cache: false,
                async: false,
                success: function (data) {
                    $('#MCGSectionHeader').text("Assessment");
                    self.customeGuideline(data.CustomGuideline);
                    self.GuidelinesQuestionHeading(data.Title);
                    self.GuidelinesQuestionList(data.SectionsSet);
                    self.GuidelinesSubmitList(data);
                    if (self.GuidelinesQuestionHeading() != null && self.GuidelinesQuestionHeading() != "") {
                        self.Split_GuidelinesQuestion_Array(self.GuidelinesQuestionHeading().split("-"));
                        self.SplitGuidelinesQuestionHeading(self.Split_GuidelinesQuestion_Array()[0]);
                    }

                    $('#loading').hide();
                    self.AnswerSaveButton(true);
                    original_questions = JSON.stringify(ko.toJS(self.GuidelinesSubmitList()));
                },
                error: function (err) {
                    $('#loading').hide();
                }
            });
        }







 $(document).ready(function () {

    ko.applyBindings(GuidelineQuestion, document.getElementById("GuidelineQuestionAnswers"));
        GuidelineQuestion.GetGuildlineQuestion();
             ko.bindingHandlers.trueFalseRadioButton =
            {
                init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
                    // event handler for the element change event
                    console.log("hello" + valueAccessor());
                    var changeHandler = function () {
                        var elementValue = $(element).val();
                        var observable = valueAccessor();      // set the observable value to the boolean value of the element value
                        observable($.parseJSON(elementValue));
                    };    // register change handler for element
                    ko.utils.registerEventHandler(element,
                                                  "change",
                                                  changeHandler);
                },
                update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
                    var elementValue = $.parseJSON($(element).val());
                    var observableValue = ko.utils.unwrapObservable(valueAccessor()); if (elementValue === observableValue) {
                        element.checked = true;
                    }
                    else {
                        element.checked = false;
                    }
                }
            };
        });
}

Getting an error as observable is not a function

San Jaisy
  • 15,327
  • 34
  • 171
  • 290
user3311567
  • 61
  • 1
  • 2
  • 8
  • 1
    From the error it seams your `$data.Selected` is not a `ko.observable`... – nemesv Sep 09 '15 at 07:04
  • You completely forgot to explain what that custom binding is meant to do. Maybe you want to have a look at the `checked` binding, because it seems to me that you are re-inventing the wheel here. – Tomalak Sep 09 '15 at 07:04
  • 1
    That being said, it's a strong code smell that you set so many custom attributes (like `Qid` etc) to viewmodel data. That pretty much indicates that you did not really understand knockout and that you are doing something wrong. – Tomalak Sep 09 '15 at 07:08
  • @nemesv - $data.Selected is not an observable ... its a array property value return from server side code. Yes I am trying to bind the checked property and value should reflect to the model – user3311567 Sep 09 '15 at 07:12
  • 2
    So, why are you not simply using the `checked` binding? – Tomalak Sep 09 '15 at 07:13
  • @Tomalak - Yes I am trying to for checked binding – user3311567 Sep 09 '15 at 07:13
  • @Tomalak - Because I want to reflect the value change to the model. If i used checked binding then the click value only changed.The unchecked value not changed to model it remain the same. I want to make false for unchecked radio value – user3311567 Sep 09 '15 at 07:17
  • 1
    That's because you are doing it wrong. Knockout perfectly reflects the view state in the viewmodel with the built-in bindings. Please include the relevant part of your viewmodel, the server data and a description of what behavior your want to create in your view, exactly. I can tell you already that your `trueFalseRadioButton` binding is pointless. (BTW, a true/false choice is generally modeled with a checkbox, not with a radio button.) – Tomalak Sep 09 '15 at 07:19
  • @Tomalak - Please find the update code. – user3311567 Sep 09 '15 at 07:40

1 Answers1

0

Please heed the advice from the comments. You're working against Knockout, not with it. Read through the docs, go through the tutorials, and try to rewrite your code with the checked binding.

Having said that, if you go your current route, be sure to unwrap input in a binding handler so that you can pass both observables and plain properties. Like this:

var observable = ko.utils.unwrapObservable(valueAccessor);

For your example:

ko.bindingHandlers.trueFalseRadioButton =
{
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        // event handler for the element change event
        console.log("hello" + valueAccessor());
        var changeHandler = function () {
            var elementValue = $(element).val();
            var observable = ko.utils.unwrapObservable(valueAccessor);
            observable($.parseJSON(elementValue));
        };    // register change handler for element
        ko.utils.registerEventHandler(element,
                                      "change",
                                      changeHandler);
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var elementValue = $.parseJSON($(element).val());
        var observableValue = ko.utils.unwrapObservable(valueAccessor()); if (elementValue === observableValue) {
            element.checked = true;
        }
        else {
            element.checked = false;
        }
    }
};

ko.applyBindings({
  Id: 1,
  items: [{
    Id: 2, 
    Selected: true,
    RadioOnly: ko.observable(true),
    QuestionRefSetStrings: "something",
    Uid: "uid"
  },{
    Id: 3, 
    Selected: true,
    RadioOnly: ko.observable(true),
    QuestionRefSetStrings: "something",
    Uid: "uid"
  }],
  answerClick: function(x){console.log(x);},
  appendQrefQuestion: function(x){console.log(x); return true;}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<div data-bind="foreach: items">
  <input type="radio" data-bind="
    value: $data.RadioOnly, 
    attr:{
        id: $data.Id ,
        name:$parent.Id,
        Qid: $parent.Id,
        Qref: $data.QuestionRefSetStrings,
        Uid: $data.Uid
    },  
    trueFalseRadioButton: $data.Selected,
    click: $root.answerClick,
    if: $root.appendQrefQuestion($data.QuestionRefSetStrings)
  ">
</div>

However, once more, even though IMO this answers your question, with your current setup, you will run into a big load of follow-up issues. Try to switch to using a checked binding (maybe with a writeable computed), or do not use Knockout and go jQuery all out.

Jeroen
  • 60,696
  • 40
  • 206
  • 339
  • Can u please post the code for checked binding.Please with the writeable compute – user3311567 Sep 09 '15 at 07:47
  • Can u please post the code for checked binding.Please with the writeable compute. And i need a false in selected parameter if the radio button is unckecked. – user3311567 Sep 09 '15 at 07:53
  • Have you checked the documentation yet? The examples there are pretty clear. If you try it yourself, and run into specific problems, you can always post a new (preferably bit more concise) question about it. – Jeroen Sep 09 '15 at 07:55
  • I did with the checked binding. But the unchecked radio value is not set to false. However, the new radio value is changed. – user3311567 Sep 09 '15 at 08:36
  • Look, mate: your question is huge, contains a lot of information, but basically boils down to "how to fix the 'observable is not a function' error". My answer is for that question. If you have a new, different question, you should ask that. Make sure you trim your code to a more minimal example though, or you may not get the best response you could get. – Jeroen Sep 09 '15 at 09:18