Laurent S.
Laurent S.

Reputation: 6946

Dynamically change the handler of a click binding in knockout.js

I got the following binding working like a charm :

<button class="flatButton buttonPin" data-bind="click:EnterPinMode">Add pin</button>

In my viewmodel I define the Handler like this :

self.EnterPinMode = function(data,event)
{
    //Doing several things here
    //....
}

Now, let's say I want to change the behavior of that button after the first click on it...how could I do it ? I already managed quite easily to change the button text :

self.EnterPinMode = function(data,event)
{
    //Doing several things here
    //....
    var curButton = $(event.target);
    curButton.text("Cancel");
}    

But what about changing the button behaviour ? If I had set this handler through jQuery, that wouldn't be an issue, but is there a way to "replace" the click binding on that control so that now it will call ExitPinMode handler, for example. I've got some doubts on this being possible given the fact that knockout works only with declarative binding (at least without plugin...), but I thought it was worth asking.

Please note that I will actually need some kind of 3 ways toggle, I just simplify it here to a "normal" toggle for the sake of the example.

Upvotes: 1

Views: 1279

Answers (3)

user2443936
user2443936

Reputation: 76

You can try this

var vm = function () {
    var self = this;
    var nextState = 'firstState';
    var states = {
       firstState: function () {
           nextState = 'secondState';
           //Do stuff
       },
       secondState: function () {
           nextState = 'thirdState';
           //Do stuff
       },
       thirdState: function () {
           nextState = 'firstState';
           //Do stuff
       }
   }

   self.EnterPinMode = function () {
       states[nextState].call();
   }
}

What you should try to remember first about MVVM is that you are designing an object to represent your view. If your view will have different states, There is nothing wrong with having your viewmodel know about these states and knowing what to do in what state. Stick with MVVM. You wont be disappointed.

Upvotes: 1

Joseph Gabriel
Joseph Gabriel

Reputation: 8510

I think using a hasBeenClicked flag that's private to the view model is fine, and probably the best solution for this.

If you really want to swap out the handler, that should be easy enough, though, with something like this:

function enterPinMode() {
    //Doing several things here
    //....
    var curButton = $(event.target);
    curButton.text("Cancel");

    //set click handler to a step 2 function
    self.pinAction = exitPinMode;
}
function exitPinMode() {
    //....
}

self.pinAction = enterPinMode;

Upvotes: 1

Sebastien Kovacs
Sebastien Kovacs

Reputation: 213

Maybe one of the simplest solution is to add a boolean like hasBeenClicked set to false at the begining and then set it to true.

Example:

  self.hasBeenClicked  = false;

  self.EnterPinMode = function(data,event)
  {
   if (!self.hasBeenClicked )
     {
      var curButton = $(event.target);
      curButton.text("Cancel");
      self.hasBeenClicked = true;
     }
   else
     {
       //behaviour an a second click
     }
  }    

Hope it helps !

Upvotes: 1

Related Questions