Knockout JS: How to handle Multiple binding errors for Knockout JS using "with" or clearnNode?
I'm working on a prototype for this project. Now the current section is dealing with knockout js "multibinding" issues. I've read about different approaches, including using the "with" statement when referencing the data model in HTML. I also read that using clearNode might be another possible solution when dealing with various data models for rendering. Here are some facts about my current problem.
- I'm using two different data models, each created with two different JSON responses/files (local and api)
- The first mode to use and render knockout bindings is "questionDisplay"
- I used Google Docs to capture the input to be included in the form submission (doesn't matter, but some calibration is explained in the code)
- During form submission, the information will be sent to the google drive file and the "next" button will trigger the "resultDisplay" modal
- At this point the problem occurs, I get "multiple bindings"
I tried using the "with" statement to "pinpoint" the exact model of each knockout template, but I was thinking, since they are only instantiated during the function call and not accessible? I don't know how to start refactoring the code to be able to use the "with" statement.
I also tried clearNode by including an id name in the root, where the knockout item is used to declare the name of the data model, that id is used in clearNode during the second KO render... The idea is to clear first it and then reuse the same node. Although in the snippet I've provided, I'm using "template" in the transparent node, since I tried every node, it happens to be the last one I tried
I've also read that during '.applyBindings', can I include the element name? I have tried several things without success.
PS: I should say again, this is prototype code, so, very confusing. Shout out to Nathan Fisher ( https://stackoverflow.com/users/29467/nathan-fisher )!
JS
//functions.js
function resultDisplay() {
parseJsonWithSelect();
var self = this;
self.data = ko.observableArray(jresponse);
}
function questionDisplay() {
var self = this;
var mappedData = qna.map(function(item) {
item.optionGroupName = "optionGroup_" + item.questionId;
item.selectedAnswer = ko.observable();
return item;
});
self.data = ko.observableArray(mappedData);
}
function initResultDisplay() {
var dataModel = new resultDisplay();
ko.cleanNode("template");
ko.applyBindings(dataModel);
$("#searchResultDisplay").modal("show");
}
function initQuestionDisplay() {
$("#inBetween").modal("hide");
var qnaDataModel = new questionDisplay();
$("#questionsDisplay").modal("show");
ko.applyBindings(qnaDataModel);
}
HTML
<!-- Questions modal -->
<div
class="modal fade"
id="questionsDisplay"
tabindex="-1"
role="dialog"
aria-labelledby="questionsDisplayLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="questionsDisplayLabel">
QUESTIONS
</h5>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
</div>
<div
class="modal-body"
data-bind="template: {name: 'template', data: $data}"
></div>
<script type="text/html" id="template">
<div class="diplay-frame" data-bind="foreach: {data: data, as: '_data'}">
<div class="question-box">
<h2 class="question" id="ques" data-bind="text: _data['question']"/>
<div data-bind="foreach: {data: _data['answers'], as: 'answer'}">
<input type="radio" id="ans" data-bind="checked: $parent.selectedAnswer, attr:{name: $parent.optionGroupName, value: $data}" />
<span data-bind="text: answer"/>
</div>
</div>
</div>
</script>
<button
type="button"
onclick="captureAnswers()"
class="btn btn-secondary"
data-dismiss="modal"
>
Next
</button>
</div>
</div>
</div>
<!-- Search result Display Modal -->
<div
class="modal fade"
id="searchResultDisplay"
tabindex="-1"
role="dialog"
aria-labelledby="searchResultDisplayLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="searchResultDisplayLabel">
Search Results
</h5>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
</div>
<div
class="modal-body"
data-bind="template: {name: 'template', data: $data}"
></div>
<script type="text/html" id="template">
<div class="diplay-frame" data-bind="foreach: {data: data, as: '_data'}">
<div class="result-box">
<div class="bgtint"></div>
<section class="businesscard">
<div class="flip">
<div class="front">
<div class="logo">
<img class="profile_image" width="50px" height="50px" data-bind="attr:{src: _data['profile_image']}"/>
<h2 class="user_name" data-bind="text: _data['username']"/>
<div class="introduction">COMPANY NAME GOES HERE!</div>
<div class="arrow"></div>
</div>
</div>
<div class="userinfo">
<ion-icon name="call">PHONE</ion-icon>
<div class="name">
</div>
</div>
</section>
</div>
</div>
</script>
</div>
<div class="modal-footer">
</div>
</div>
</div>
`
Yes, you can't call it twice applyBindings
on the entire document and expect to get rid of it ;-) But this method does take an element as its second parameter, so the binding is only applied to that element. So in your case you can call:
ko.applyBindings(dataModel, document.querySelector('#searchResultDisplay'));
and:
ko.applyBindings(qnaDataModel, document.querySelector('#questionsDisplay'));