Passing parameter using onclick or a click binding with KnockoutJS

JavascriptHtmlknockout.jsOnclick

Javascript Problem Overview


I have this function:

function make(place)
{
  place.innerHTML = "somthing"
}

I used to do this with plain JavaScript and html:

<button onclick="make(this.parent)">click me</button>

How can I do this using idiomatic knockout.js?

Javascript Solutions


Solution 1 - Javascript

Use a binding, like in this example:

<a href="#new-search" data-bind="click:SearchManager.bind($data,'1')">
  Search Manager
</a>

var ViewModelStructure = function () {
    var self = this;
    this.SearchManager = function (search) {
        console.log(search);
    };
}();

Solution 2 - Javascript

If you set up a click binding in Knockout the event is passed as the second parameter. You can use the event to obtain the element that the click occurred on and perform whatever action you want.

Here is a fiddle that demonstrates: http://jsfiddle.net/jearles/xSKyR/

Alternatively, you could create your own custom binding, which will receive the element it is bound to as the first parameter. On init you could attach your own click event handler to do any actions you wish.

http://knockoutjs.com/documentation/custom-bindings.html

HTML

<div>
    <button data-bind="click: clickMe">Click Me!</button>
</div>

Js

var ViewModel = function() {
    var self = this;
    self.clickMe = function(data,event) {
      	        
      var target = event.target || event.srcElement;
        
      if (target.nodeType == 3) // defeat Safari bug
        target = target.parentNode;
        
      target.parentNode.innerHTML = "something";
    }
}
        
ko.applyBindings(new ViewModel());
    

Solution 3 - Javascript

I know this is an old question, but here is my contribution. Instead of all these tricks, you can just simply wrap a function inside another function. Like I have done here:

<div data-bind="click: function(){ f('hello parameter'); }">Click me once</div>
<div data-bind="click: function(){ f('no no parameter'); }">Click me twice</div>

var VM = function(){
   this.f = function(param){
     console.log(param);
   }
}
ko.applyBindings(new VM());

And here is the fiddle

Solution 4 - Javascript

A generic answer on how to handle click events with KnockoutJS...

Not a straight up answer to the question as asked, but probably an answer to the question most Googlers landing here have: use the click binding from KnockoutJS instead of onclick. Like this:

function Item(parent, txt) {
  var self = this;
  
  self.doStuff = function(data, event) {
    console.log(data, event);
    parent.log(parent.log() + "\n  data = " + ko.toJSON(data));
  };
  
  self.doOtherStuff = function(customParam, data, event) {
    console.log(data, event);
    parent.log(parent.log() + "\n  data = " + ko.toJSON(data) + ", customParam = " + customParam);
  };
  
  self.txt = ko.observable(txt);
}

function RootVm(items) {
  var self = this;
  
  self.doParentStuff = function(data, event) {
    console.log(data, event);
    self.log(self.log() + "\n  data = " + ko.toJSON(data));
  };
  
  self.items = ko.observableArray([
    new Item(self, "John Doe"),
    new Item(self, "Marcus Aurelius")
  ]);
  self.log = ko.observable("Started logging...");
}

ko.applyBindings(new RootVm());

.parent { background: rgba(150, 150, 200, 0.5); padding: 2px; margin: 5px; }
button { margin: 2px 0; font-family: consolas; font-size: 11px; }
pre { background: #eee; border: 1px solid #ccc; padding: 5px; }

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>

<div data-bind="foreach: items">
  <div class="parent">
    <span data-bind="text: txt"></span><br>
    <button data-bind="click: doStuff">click: doStuff</button><br>
    <button data-bind="click: $parent.doParentStuff">click: $parent.doParentStuff</button><br>
    <button data-bind="click: $root.doParentStuff">click: $root.doParentStuff</button><br>
    <button data-bind="click: function(data, event) { $parent.log($parent.log() + '\n  data = ' + ko.toJSON(data)); }">click: function(data, event) { $parent.log($parent.log() + '\n  data = ' + ko.toJSON(data)); }</button><br>
    <button data-bind="click: doOtherStuff.bind($data, 'test 123')">click: doOtherStuff.bind($data, 'test 123')</button><br>
    <button data-bind="click: function(data, event) { doOtherStuff('test 123', $data, event); }">click: function(data, event) { doOtherStuff($data, 'test 123', event); }</button><br>
  </div>
</div>

Click log:
<pre data-bind="text: log"></pre>


*A note about the actual question...

The actual question has one interesting bit:

// Uh oh! Modifying the DOM....
place.innerHTML = "somthing"

Don't do that! Don't modify the DOM like that when using an MVVM framework like KnockoutJS, especially not the piece of the DOM that is your own parent. If you would do this the button would disappear (if you replace your parent's innerHTML you yourself will be gone forever ever!).

Instead, modify the View Model in your handler instead, and have the View respond. For example:

function RootVm() {
  var self = this;
  self.buttonWasClickedOnce = ko.observable(false);
  self.toggle = function(data, event) {
    self.buttonWasClickedOnce(!self.buttonWasClickedOnce());
  };
}

ko.applyBindings(new RootVm());

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>

<div>
  <div  data-bind="visible: !buttonWasClickedOnce()">
    <button data-bind="click: toggle">Toggle!</button>
  </div>
  <div data-bind="visible: buttonWasClickedOnce">
    Can be made visible with toggle...
    <button data-bind="click: toggle">Untoggle!</button>
  </div>
</div>

Solution 5 - Javascript

Knockout's documentation also mentions a much cleaner way of passing extra parameters to functions bound using an on-click binding using function.bind like this:

<button data-bind="click: myFunction.bind($data, 'param1', 'param2')">
    Click me
</button>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBlaShadowView Question on Stackoverflow
Solution 1 - JavascriptJuliano SalesView Answer on Stackoverflow
Solution 2 - JavascriptJohn EarlesView Answer on Stackoverflow
Solution 3 - JavascriptSalvador DaliView Answer on Stackoverflow
Solution 4 - JavascriptJeroenView Answer on Stackoverflow
Solution 5 - JavascriptgazubiView Answer on Stackoverflow