I have a view model Which has to be attached to a click event of an <li>
tag. Here is the viewmodel and markup
var viewModel =
{
Folders: ['Inbox', 'Archive', 'Sent', 'Spam'],
SelectedFolder: ko.observable('Inbox'),
chosenFolderId: ko.observable(),
navigate: function () {
self.chosenFolderId(folder);
}
};
ko.applyBindings(viewModel);
And the markup is
<ul class="nav nav-list bs-docs-sidenav affix" data-bind="foreach:Folders">
@*<li data-bind="css:{active: $data == chosenFolderId() }">*@
<li>
<a href="#" data-bind="click:navigate">
<!-- ko text: $data -->
<!-- /ko -->
<i class="icon-chevron-right"></i>
</a>
</li>
</ul>
The problem is in this line
<a href="#" data-bind="click:navigate">
and
<li data-bind="css:{active: $data == chosenFolderId() }">
Both The line above is not getting attached to the Navigate
function and chosenFolderId
observable respectively. It says Navigate
is undefined . It cannot be parsed. Same goes for
chosenFolderId`.
Any idea why is it happening ?
The function you want to bind to the element's click event. You can reference any JavaScript function - it doesn't have to be a function on your view model. You can reference a function on any object by writing click: someObject. someFunction .
A binding context is an object that holds data that you can reference from your bindings. While applying bindings, Knockout automatically creates and manages a hierarchy of binding contexts. The root level of the hierarchy refers to the viewModel parameter you supplied to ko. applyBindings(viewModel) .
You have a few problems with your current approach:
When you use a foreach binding e.g data-bind="foreach:Folders"
inside your ul
the "currect context" will be the items in your folder collection.
So if you want to access the navigate
or the chosenFolderId
methods you need to use $parent
, or $root
to access the your "root" viewmodel (you can read more about the binding context):
<ul class="nav nav-list bs-docs-sidenav affix" data-bind="foreach:Folders">
<li data-bind="css:{active: $data == $parent.chosenFolderId() }">
<a href="#" data-bind="click: $parent.navigate">
<!-- ko text: $data -->
<!-- /ko -->
<i class="icon-chevron-right"></i>
</a>
</li>
</ul>
You have some problem in your view model as well. If you have complex functions like navigate
which tries to use self
you should use a function as a viewmodel instead of an object literal where you can store this
:
var viewModel = function() {
var self = this;
self.Folders = ['Inbox', 'Archive', 'Sent', 'Spam'];
self.SelectedFolder = ko.observable('Inbox');
self.chosenFolderId = ko.observable();
self.navigate = function(folder) {
self.chosenFolderId(folder);
}
};
ko.applyBindings(new viewModel());
Note that: your navigate
function needs a folder
parameter to make it work and Knockout will pass the current item for you.
Here is a working JSFiddle.
If you want to do it with an object literal as your view model here is JSFiddle which demonstrates that approach.
However you should be aware what are the strength and weeknesses of the two view model creation approach. This SO question summarizes it well: Difference between knockout View Models declared as object literals vs functions
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With