jviotti
jviotti

Reputation: 18909

Knockout.js click binding with parameters

I have this little ViewModel:

function BooksViewModel() {
    var self = this;
    self.books = ko.observableArray(library);

    self.findByLanguage = function(lang) {
        self.books = ko.computed(function() {
            return ko.utils.arrayFilter(library, function(book) { 
                return book.language() === lang; 
            });
        });
    };
}

The findByLanguage method filters the array by language. In the view, im tryign to implement that like this:

<ul class="dropdown-menu">
    <li><a tabindex="-1" href="#" data-bind="click: findByLanguage('C')">C</a></li>
    <li><a tabindex="-1" href="#" data-bind="click: findByLanguage('Cpp')">C++</a></li>
</ul>

I'm attemping to reuse the function by calling the language parameter from there. But if I pass a function with parenthesis on data-bind it automatically gets called.

How can I accomplish this?

Upvotes: 10

Views: 37849

Answers (3)

Andrii Litvinov
Andrii Litvinov

Reputation: 13182

I know the question is old, but in case someone is interested, according to docs, first parameter should be a viewModel, then it works as expected.

<ul class="dropdown-menu">
    <li><a tabindex="-1" href="#" data-bind="click: findByLanguage.bind($data, 'C')">C</a></li>
    <li><a tabindex="-1" href="#" data-bind="click: findByLanguage.bind($data, 'Cpp')">C++</a></li>
</ul>

Upvotes: 3

John Earles
John Earles

Reputation: 7194

You might be interested in a slightly different approach that add extra fields into your View Model.

http://jsfiddle.net/jearles/RN9Dw/

By adding languages into the View Model you can use Knockout to render the menu and the click binding will automatically pass the language that was clicked to the handler function. Additionally, adding selectedLanguage as an observable allows the books computed to change when you select or clear a language.

HTML

<ul class="dropdown-menu" data-bind="foreach: languages">
    <li><a tabindex="-1" href="#" data-bind="text: $data, click: $root.filterByLanguage"></a></li>
</ul>
<button data-bind="click: showAll">Show All</button>

<div data-bind="foreach: books">
    <p><span data-bind="text: name"></span>, <span data-bind="text: language"></span></p>
</div>​

JS

function BooksViewModel() {
    var self = this;

    self.languages = ko.observableArray(['C', 'C++']);
    self.selectedLanguage = ko.observable();
    self.library = [{name: 'Book A', language: 'C'}, {name: 'Book B', language: 'C++'}]; 
    self.books = ko.computed(function() {
        return ko.utils.arrayFilter(self.library, function(book) { 
          return self.selectedLanguage() == null ||
              book.language === self.selectedLanguage(); 
          })
    });

    self.showAll = function() {
        self.selectedLanguage(null);
    }
    self.filterByLanguage = function(lang) {
        self.selectedLanguage(lang);
    };
}

ko.applyBindings(new BooksViewModel());

Upvotes: 9

Jamie Starke
Jamie Starke

Reputation: 9234

The easiest way to accomplish this would be to wrap this in a function that executes only on click, like:

<li><a tabindex="-1" href="#" data-bind="click: function () {findByLanguage('C')}">

Alternatively, you can use the bind context should do the trick.

<li><a tabindex="-1" href="#" data-bind="click: findByLanguage.bind('C')">

Here is an example of the click binding using JS Fiddle (http://jsfiddle.net/uFyaP/1/)

Upvotes: 24

Related Questions