Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditional 'click' binding with Knockout

Tags:

knockout.js

I am binding the click event to every list item in a list:

        <ul class="modal-subject-list" data-bind="foreach: filteredSubjects">
            <li data-bind="click: $parent.pickSubject, css: {alreadyAddedBackground: hasBeenAdded}">
                <!-- Lots of code here -->
            </li>
        </ul>

I want to disable the click: binding if 'hasBeenAdded' resolves to true. I know some messy ways to take care of it:

  1. Have two list items, one for if: hasBeenAdded, and the other for if: !hasBeenAdded. This is far from DRY
  2. Handle this check with javascript and leave the view alone - I don't like this because unnecessary markup is being generated for list items that should be essentially disabled.

Is there a way to register a "clickIf" binding?

like image 691
RobVious Avatar asked Sep 23 '13 22:09

RobVious


People also ask

How do you bind a function in knockout JS?

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 .

What is $parent in knockout?

$parent : This is the view model object in the parent context, the one immeditely outside the current context. $root : This is the main view model object in the root context, i.e., the topmost parent context. It's usually the object that was passed to ko.

What is two-way binding in knockout JS?

KO is able to create a two-way binding if you use value to link a form element to an Observable property, so that the changes between them are exchanged among them. If you refer a simple property on ViewModel, KO will set the form element's initial state to property value.


2 Answers

Do this

    <ul class="modal-subject-list" data-bind="foreach: filteredSubjects">
        <li data-bind="click: hasBeenAdded ? null : $parent.pickSubject">
            <!-- Lots of code here -->
        </li>
    </ul>

http://jsfiddle.net/7hcj6/

Read -

If the filteredSubject has been added, do nothing, else add to the list or whatever.

like image 101
PW Kad Avatar answered Oct 29 '22 23:10

PW Kad


Just want to expand on @PW Kad's answer in case it helps others.

I found that I could apply a condition to the knockout event node so that all or none of the handlers are bound. In my case, I needed to bind events only to inputs that were not read only. So this does work if you need to do something similar. Happy coding.

event: $data.SomeProperty() ? null : { multiple event handlers }

Example Code:

<input type="number"
       data-bind="value: $data.Value,
                  css: $data.Css,
                  attr: {
                      title: $data.Title,
                      min: $data.Min,
                      max: $data.Max,
                      readonly: $data.ReadOnly
                  },
                  event: $data.ReadOnly() ? null : {  // <----- HERE
                      focus: $root.onFocus,
                      blur: $root.onBlur,
                      input: $root.onInput,
                      keypress: $root.onKeypress
                   }" />
like image 35
Roberto Avatar answered Oct 29 '22 22:10

Roberto