Knockout.js Foreach适用于JSON的子对象,但不适用于ViewModel

Knockout.js Foreach适用于JSON的子对象,但不适用于ViewModel,knockout.js,knockout-mapping-plugin,Knockout.js,Knockout Mapping Plugin,我正在成功地将分层JSON数据绑定到我的视图。但是,一旦我使用knockout.mapping将相同的JSON数据投影到viewmodel中,foreach函数就不会遍历子数组 绑定到viewModel数据时,我知道子数据(答案)在那里,因为我可以使用 意见如下: <div data-bind="foreach: $data"> <p data-bind="html: QuestionText"> <!-- this section outputs

我正在成功地将分层JSON数据绑定到我的视图。但是,一旦我使用knockout.mapping将相同的JSON数据投影到viewmodel中,foreach函数就不会遍历子数组

绑定到viewModel数据时,我知道子数据(答案)在那里,因为我可以使用

意见如下:

<div data-bind="foreach: $data">
    <p data-bind="html: QuestionText">

    <!-- this section outputs [object Object] when bound to pageViewModel or Json -->
    <p data-bind="html: Answers">

        <!-- RadioButtonSelection-->
        <div data-bind="if: QuestionSelectionMode == 'RadioButtonSelection'">
            <span data-bind="foreach: $data.Answers">
                <input type="radio" data-bind="attr: {name: $parent.QuestionId}, value: AnswerId" /><span data-bind="text: AnswerText"></span>
            </span>
        </div>

        <!-- CheckBoxSelection-->
        <div data-bind="if: QuestionSelectionMode == 'CheckBoxSelection'">
            <span data-bind="foreach: $data.Answers">
                <div><input type="checkbox" data-bind="value: AnswerId"/><span data-bind="text: AnswerText"></span></div>
            </span>
        </div>

        <!-- DropDownListSelection-->
        <div data-bind="if: QuestionSelectionMode == 'DropDownListSelection'">
            <select data-bind="options: $data.Answers, optionsText: 'AnswerText', optionsValue: 'AnswerId'"></select>
        </div>

    </p>
</div>

ViewModel代码:

<script type="text/javascript">

    /* get the first page of questions and bind them */
    @{ 

        string startUrl = "URL-Removed" + ViewData["formId"] + "?page=" + ViewData["pageNumber"];

    }

    var pageViewModel;


    $.ajax({ url: '@startUrl' ,
        async: false,
        dataType: 'json',
        success: function (data) {
            //console.log("JSON received:  " + JSON.stringify(data));            

            // when i bind to the view model the parent question text shows, but not the child answers
            pageViewModel = ko.mapping.fromJS(data);
            ko.applyBindings(pageViewModel);
            //ko.applyBindings(data);
        },
        error: function (jqXHR, textStatus, errorThrown) {
            console.log("Error: TextStatus: " + textStatus + " errorThrown: " + errorThrown);
        }
    });
    </script>

/*获取问题的第一页并将其绑定*/
@{ 
string startUrl=“URL Removed”+ViewData[“formId”]+“?page=“+ViewData[“pageNumber”];
}
var模型;
$.ajax({url:'@startUrl',
async:false,
数据类型:“json”,
成功:功能(数据){
//log(“接收到的JSON:+JSON.stringify(数据));
//当我绑定到视图模型时,会显示父问题文本,但不会显示子问题的答案
pageViewModel=ko.mapping.fromJS(数据);
应用绑定(pageViewModel);
//ko.应用绑定(数据);
},
错误:函数(jqXHR、textStatus、errorshown){
log(“错误:TextStatus:”+TextStatus+“errorhorn:”+errorhorn);
}
});
以下是JSON中的一些数据:

 [{"FormId":0,"QuestionId":28807,"QuestionSelectionMode":"StaticTextSelection","QuestionText":"<hr />\r\n<div><span style=\"font-size: medium\"><span style=\"color: #003366\"><strong>Event Details</strong></span></span></div>","DisplayOrder":1,"PageNumber":1,"Answers":[]},{"FormId":0,"QuestionId":28782,"QuestionSelectionMode":"RadioButtonSelection","QuestionText":"<div><span style=\"font-size: larger\"><strong>What type of patient safety event is being reported?</strong></span><span style=\"font-size: x-small\"><strong>&nbsp; </strong><font color=\"#ff0000\" size=\"1\">(Required)</font></span></div>","DisplayOrder":2,"PageNumber":1,"Answers":[{"AnswerId":460935,"QuestionId":0,"AnswerTypeId":null,"RegularExpressionId":null,"AnswerText":"Reached the patient","DisplayOrder":1,"Selected":null,"DefaultText":null,"Mandatory":null,"ValidatorId":null,"SyncRefMandatory":null,"FieldLength":null,"AnswerFormId":null,"EntryMaskId":null,"ShowTimeSelector":null,"Disabled":false},{"AnswerId":460936,"QuestionId":0,"AnswerTypeId":null,"RegularExpressionId":null,"AnswerText":"Did not reach the patient (Near Miss)","DisplayOrder":2,"Selected":null,"DefaultText":null,"Mandatory":null,"ValidatorId":null,"SyncRefMandatory":null,"FieldLength":null,"AnswerFormId":null,"EntryMaskId":null,"ShowTimeSelector":null,"Disabled":false},{"AnswerId":460937,"QuestionId":0,"AnswerTypeId":null,"RegularExpressionId":null,"AnswerText":"Unsafe Condition","DisplayOrder":3,"Selected":null,"DefaultText":null,"Mandatory":null,"ValidatorId":null,"SyncRefMandatory":null,"FieldLength":null,"AnswerFormId":null,"EntryMaskId":null,"ShowTimeSelector":null,"Disabled":false}]},{"FormId":0,"QuestionId":46080,"QuestionSelectionMode":"RadioButtonSelection","QuestionText":"<div><span style=\"font-size: larger\"><strong>Was the patient harmed?</strong></span></div>","DisplayOrder":3,"PageNumber":1,"Answers":[{"AnswerId":632595,"QuestionId":0,"AnswerTypeId":null,"RegularExpressionId":null,"AnswerText":"Yes","DisplayOrder":1,"Selected":null,"DefaultText":null,"Mandatory":null,"ValidatorId":null,"SyncRefMandatory":null,"FieldLength":null,"AnswerFormId":null,"EntryMaskId":null,"ShowTimeSelector":null,"Disabled":false},{"AnswerId":632596,"QuestionId":0,"AnswerTypeId":null,"RegularExpressionId":null,"AnswerText":"No","DisplayOrder":2,"Selected":null,"DefaultText":null,"Mandatory":null,"ValidatorId":null,"SyncRefMandatory":null,"FieldLength":null,"AnswerFormId":null,"EntryMaskId":null,"ShowTimeSelector":null,"Disabled":false}]}, and so on...
[{“FormId”:0,“QuestionId”:28807,“QuestionSelectionMode”:“StaticTextSelection”,“QuestionText”:“
\r\n事件详细信息”,“DisplayOrder”:1,“PageNumber”:1,“Answers”:[]},{“FormId”:0,“QuestionId”:28782,“QuestionSelectionMode”:“RadioButtonSelection”,“QuestionText”::“报告的是哪种类型的患者安全事件?(必需)”,“显示顺序”:2,“页码”:1,“答案”:[{“AnswerId”:460935,“QuestionId”:0,“AnswerTypeId”:null,“RegularExpressionId”:null,“AnswerText”:“到达患者”,“显示顺序”:1,“选中”:null,“DefaultText”:null,“强制”:null,“ValidatorId”:null,”SyncRefMandatory“:null,“FieldLength”:null,“AnswerFormId”:null,“EntryMaskId”:null,“ShowTimeSelector”:null,“Disabled”:false},{“AnswerId”:460936,“QuestionId”:0,“AnswerTypeId”:null,“RegularExpressionId”:null,“AnswerText”:“未到达患者(未遂)”,“DisplayOrder”:2,“Selected”:null,“DefaultText”:null,“Mandatorial”:null,“ValidatorId”:nullSyncRefMandatory:null,“FieldLength”:null,“AnswerFormId”:null,“EntryMaskId”:null,“ShowTimeSelector”:null,“Disabled”:false},{“AnswerId”:460937,“QuestionId”:0,“AnswerTypeId”:null,“RegularExpressionId”:null,“AnswerText”:“不安全条件”,“DisplayOrder”:3,“Selected”:null,“DefaultText”:null,“Mandatory”:null,“ValidatorId”:null,“SyncRefMandatorial”:nullFieldLength“,”AnswerFormId“,”null“,”EntryMaskId“,”null“,”ShowTimeSelector“,”null“,”Disabled“,”false“}],”{”FormId“:0,“QuestionId“,”提问选择模式“,”RadioButtonSelection“,”提问文本“,”患者是否受到伤害?,”显示顺序“:3,”页码“:1,“回答“:”[{“AnswerId”:0,“AnswerTypeId”:null,”RegularExpressionId:null,“AnswerText”:“是”,“显示顺序”:1,“选定的”:null,“默认文本”:null,“强制的”:null,“验证ID”:null,“SyncRefMandatory”:null,“FieldLength”:null,“AnswerFormId”:null,“EntryMaskId”:null,“ShowTimeSelector”:null,“禁用的”:false},{“AnswerId”:632596,“问题ID”:0,“AnswerTypeId”:null,“RegularExpressionId”:null,“AnswerText”“:”否“,”DisplayOrder“:2,“Selected”:null,“DefaultText”:null,“Mandatory”:null,“ValidatorId”:null,“SyncRefMandatory”:null,“FieldLength”:null,“AnswerFormId”:null,“EntryMaskId”:null,“ShowTimeSelector”:null,“Disabled”:false}]}等等。。。

有什么想法吗?

在if绑定中,您要放入一个完整的语句,而不仅仅是引用viewmodel上的属性。因此,您需要调用observable(作为函数),而不仅仅是引用它。翻译:而不是

<div data-bind="if: QuestionSelectionMode == 'CheckBoxSelection'">

你应该

<div data-bind="if: QuestionSelectionMode() == 'CheckBoxSelection'">

下面是更新后的标记:

<div data-bind="foreach: $data">
    <p data-bind="html: QuestionText">

    <!-- RadioButtonSelection-->
    <div data-bind="if: QuestionSelectionMode() == 'RadioButtonSelection'">
        <span data-bind="foreach: Answers">
            <input type="radio" data-bind="attr: {name: $parent.QuestionId}, value: AnswerId" /><span data-bind="text: AnswerText"></span>
        </span>
    </div>

    <!-- CheckBoxSelection-->
    <div data-bind="if: QuestionSelectionMode() == 'CheckBoxSelection'">
     <span data-bind="foreach: Answers">
            <div><input type="checkbox" data-bind="value: AnswerId"/><span data-bind="text: AnswerText"></span></div>
        </span>
    </div>

    <!-- DropDownListSelection-->
    <div data-bind="if: QuestionSelectionMode() == 'DropDownListSelection'">
        <select data-bind="options: Answers, optionsText: 'AnswerText', optionsValue: 'AnswerId'"></select>
    </div>

</div>​

这是一把小提琴:

还有几点需要注意:

  • 您正在尝试对p标记执行“html:answers”绑定。html绑定旨在告诉knockout您的viewmodel中有一个html字符串,您希望将其放入现有标记中。但是,然后您在p标记中定义了各种其他标记。只需完全删除此标记

  • 为了让JSON解析器满意,我必须更正JSON,这样您就可以使用双斜杠而不是单斜杠(请参阅fiddle)。这可能与您的服务处理方式无关

  • $data在绑定中是隐式的,因此不必绑定到“$data.Answers”,您可以只绑定到“Answers”。无论哪种方式都可以,但删除$data会使绑定更干净

  • 从技术上讲,p标记中不应该包含div标记

  • p标签应该是闭合的


  • 数据是什么样子的?这里是部分数据转储:谢谢,CodeThug。我假设映射库在默认情况下正在将所有属性转换为可观察对象对吗?保留thuggin。这是正确的。从的文档中,所有属性都转换为可观察对象,所有数组都转换为可观察对象。