I am having difficulties with knockout. From my model, I am sending in a JSON object that contains a list of credentials. Each credential has a "Id", "Name", and "Selected" property. In my view, I have 2 lists. The first shows all credentials with "Selected" value equal to "false". The second list shows all items that have "Selected" value equal to "true".
Initially, all the items will have "Selected" value equal to false. When I double click the item in the list, the "Selected" value toggles so that it is removed from the first list and added the the second. My issue is that I can't seem to get the binding to work correctly. At first I was able to get the first list to populate correctly and I could manually enter in a value (Id) to the toggle function so that upon loading the page, whatever item I specified was listed properly on the second list. However, I was doing this incorrectly because I was changing the raw input data, not an observable array so my view wouldn't update correctly.
This is how I currently have it. As of right now when it goes into the toggleselected function, it isn't retrieving the correct credential (whereas before it was working when I used the raw, non observable data). I'm definitely missing something!
MODEL (just the one method that creates the JSON):
private void createJsonForAllCredentials()
{
List<CredentialLookupDto> credentials = proxy.Credential_RetrieveAll();
var optimizedCred = from c in credentials
select new
{
Name = c.Name,
Id = c.CredentialId,
Selected =
SelectedQualification != null && SelectedQualification.Credentials != null &&
SelectedQualification.Credentials.Any(p => p.CredentialId == c.CredentialId)
};
this.JsonAllCredentials = JsonConvert.SerializeObject(optimizedCred);
}
VIEW:
<div>
<table>
<tr>
<td class="fieldName_td">
@Html.Label("Available Credentials")
</td>
<td class="fieldData_td">
<select data-bind="foreach: $root.AllCredentials" multiple="multiple" name="ddallcredentials" id="allCredentials">
<!-- ko if: !Selected -->
<option data-bind="text:Name,value:Id"></option>
<!-- /ko -->
</select>
</td>
</tr>
</table>
</div>
<div>
<table>
<tr>
<td class="fieldName_td">
@Html.Label("Selected Credentials")
</td>
<td class="fieldData_td">
<select data-bind="foreach: $root.AllCredentials" multiple="multiple" name="ddSelectedCredentials" id="selectedCredentials">
<!-- ko if: Selected -->
<option data-bind="text:Name,value:Id"></option>
<!-- /ko -->
</select>
</td>
</tr>
</table>
</div>
}
@section scripts {
@Scripts.Render("~/Scripts/knockout-2.2.1.js", "~/jscripts/Administration/Interfaces/QualificationList.js", "~/Scripts/knockout.mapping-latest.js")
<script type="text/javascript">
$(function () {
TestNWJS.QualificationList.Init(@Html.Raw(Model.JsonAllCredentials));
})
</script>
}
VIEWMODEL:
///<reference path="~/Scripts/jquery-1.9.1.js" />
///<reference path="~/Scripts/knockout-2.2.1.js" />
///<reference path="~/Scripts/knockout.mapping-latest.js" />
var TestNWJS = TestNWJS || {};
TestNWJS.QualificationList = (function () {
//private functions
function CreateQualificationModel(allCredentialsList) {
TestNWJS.QualificationList.ViewModel = {};
TestNWJS.QualificationList.ViewModel.AllCredentials = ko.observableArray(allCredentialsList).extend({ notify: 'always' });
}
function toggleselected(array,id) {
var credential = ko.utils.arrayFirst(array, function (credential) {
var stringToInt = parseInt(id);
return credential.Id === stringToInt;
});
if (credential.Selected == false) {
credential.Selected = true;
}
else {
credential.Selected = false;
}
return credential;
}
//public function
return {
Init: function (allCredentialsList) {
CreateQualificationModel(allCredentialsList);
$("#allCredentials").live('dblclick', function (e) {
toggleselected(this.value);
});
$("#selectedCredentials").live('dblclick', function (e) {
toggleselected(this.value);
});
ko.applyBindings(TestNWJS.QualificationList.ViewModel);
}
}
})();
Again, just for clarification, the initial list loads correctly. This issue is when I want to double click an item to trigger the "toggleselected" function (the double click trigger works), the function does not work correctly. It returns a null value for "credential", thus meaning that my ko.utils.arrayFirst implementation isn't correct. There are potentially other issues related to binding as well. And finally, I was able to get everything to work correctly when I passed in the raw data "allCredentialsList" instead of "TestNWJS.QualificationList.ViewModel.AllCredentials". The reason I am doing so is because "TestNWJS.QualificationList.ViewModel.AllCredentials" is observable thus triggering a view update when a property changes (in this case the "Selected" property upon a double click).