My problem is that when I click a href tag displayed using an observableArray, it does not refresh my UI. I have to use a list control.
I have a list control displaying 6 folders and then a table showing same 6 folders with 6 href tags. When I change the selection in listbox control, files get refreshed, pretty easily and smoothly. But, I want/need to refresh those files using href tags. Please let me know if anyone has any answer.
I have taken most of the code from example from this location: knockout tutorial
Java script file “proto.js”:
var folders = [
{ name: "Folder 3", fileNames: ['File 3_1', 'File 3_2', 'File 3_3']},
{ name: "Folder 4", fileNames: ['File 4_1', 'File 4_4', 'File 4_2', 'File 4_3'] },
{ name: "Folder 5", fileNames: ['File 5_1', 'File 5_4', 'File 5_5', 'File 5_2', 'File 5_3'] },
{ name: "Folder 6", fileNames: ['File 6_1', 'File 6_4', 'File 6_6', 'File 6_5', 'File 6_2', 'File 6_3'] },
{ name: "Folder 2", fileNames: ['File 2_2', 'File 2_1'] },
{ name: "Folder 1", fileNames: ['File 1_1'] }
];
var FileExplorerViewModel = function (lists, selectedList) {
this.folders = ko.observableArray(lists);
this.editingList = {
name: ko.observable(selectedList),
fileNames: ko.observableArray()
};
this.changeFolder = ko.computed({
read: function () {
alert("changeFolder: Read");
return this.editingList;
},
write: function (folder) {
alert("changeFolder: write");
alert(folder.name);
if (folder && this.editingList) {
alert("changeFolder: Write executing");
selectedList = folder.name;
}
},
owner: this //FileExplorerViewModel
}, this);
this.sortFolders = function () {
this.folders.sort(function (a, b) {
return a.name < b.name ? -1 : 1;
});
};
this.sortFiles = function () {
this.editingList.fileNames.sort(function (a, b) {
return a < b ? -1 : 1;
});
};
this.findSavedList = function (name) {
var lists = this.folders();
return ko.utils.arrayFirst(lists, function (list) {
return list.name === name;
});
};
ko.computed(function () {
//alert("ko.computed");
// Observe viewModel.editingList.name(), so when it changes (i.e., user selects a different list) we know to copy the saved list into the editing list
var savedList = this.findSavedList(this.editingList.name());
if (savedList) {
var userNamesCopy = savedList.fileNames.slice(0);
this.editingList.fileNames(userNamesCopy);
} else {
this.editingList.fileNames([]);
}
}, this);
};
$(document).ready(function () {
ko.applyBindings(new FileExplorerViewModel(folders, "Folder 4"));
});
HTML file: “proto.html”
<!
DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8" />
<title>File Explorer Prototype</title>
<link rel="stylesheet" type="text/css" href="css/jquery.mobile-1.1.0.css" />
<script type="text/javascript" src="../cordova-1.6.0.js"></script>
<script type="text/javascript" src="../jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="scripts/knockout-2.0.0.js"></script>
<script type="text/javascript" src="Proto.js"></script>
</head>
<body class="homeBody">
<div class='listChooser'>
<!--<button data-bind='click: deleteList, enable: editingList.name'>Delete</button>
<button data-bind='click: saveChanges, enable: hasUnsavedChanges'>Save</button>-->
<!--<select data-bind='options: folders, optionsValue: "name", value: editingList.name'> </select>-->
<select multiple="multiple" data-bind="options: folders, optionsValue: 'name', value: editingList.name"></select>
<button data-bind='click: $root.sortFolders'>Sort Folders</button>
<table>
<tbody data-bind="foreach: folders">
<tr><td>
<span data-bind="text: name"></span>
<a href="#" data-bind="click: $root.changeFolder">Change</a>
<!--<a data-bind="attr: {href: name}, click: $root.changeFolder">Change Folder</a>-->
<br />
</td></tr>
</tbody>
</table>
</div>
<p>Currently viewing <b><font color="red"><span data-bind='text: editingList.fileNames().length'></span></font></b> file(s) from folder <b><font color="red"><span data-bind="text: editingList.name"></span></font></b>:</p>
<button data-bind='click: $root.sortFiles'>Sort Files</button>
<div data-bind='with: editingList'>
<ul data-bind='foreach: fileNames'>
<li>
<div data-bind="text: $data"> </div>
</li>
</ul>
</div>
</body>
</html>
All your changeFolder computed is doing on write is
selectedList = folder.name, but this doesn’t affect anything else.. I think maybe you meant to do:this.editingList.name(folder.name)instead. Here’s how that works: http://jsfiddle.net/antishok/KXhem/44/This works, but it could be much simpler with a few changes. Don’t base things on the name of the folder you’re currently working, base it on the folder itself. You should rarely need to use the
optionsValuebinding, because using it means overriding the default functionality which is that KO maps each option to the actual object and uses the actual object identity as “value”. I also changed the computed to a simple subscribe, and simplified thechangeFolderfunction – there was no reason for it to be a writeable computed. Updated fiddle: http://jsfiddle.net/antishok/KXhem/45/