Reputation: 1998
I'm trying to add an click event to my button that will send the Id, Category and Name as parameters only when the button is clicked.
<tbody data-bind="foreach: tehTab()">
<tr>
<td data-bind="text: $data.Category"></td>
<td data-bind="text: $data.Name"></td>
<td>
<button type="button" class="btn chart_btn" role="button" data-toggle="popover" data-trigger="focus" data-html="true" data-placement="right" container="body" tabindex="0" data-original-title="" title="" style="border:none; background-color:white" data-bind="attr: { id: $data.Id,'data-contentwrapper':'.chartdraw' + $data.Id},click: getLast7($data.Id, $data.Category, $data.Name) , text:$data.Value"></button>
<div data-bind="css: 'chartdraw' + $data.Id" class="chartdrawetc" style="display:none">ASD</div>
</td>
</tr>
</tbody>
even if I try to change:
click: getLast7($data.Id, $data.Category, $data.Name)
with
attr: { id: $data.Id ,onclick: getLast7($data.Id, $data.Category, $data.Name)
it still fires the getLast7 method as many times as the tehTab length.
What am I doing wrong?
Upvotes: 12
Views: 29699
Reputation: 3192
If you want to retain your original binding syntax, have the function in your viewmodel return a function.
ko.applyBindings({
Id: 15,
Value: ko.observable('Click Me!'),
Category: 'standard category',
getLast7: function(id, category, name){
return function() {
console.log("You clicked and passed in " + id + ", " + category + ", " + name);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<button data-bind="click: getLast7($data.Id, $data.Category, 'Hello World!'), text:$data.Value">
Upvotes: 0
Reputation: 5115
You can also simply wrap the click handler (getLast7 in your case) in a function. You can then supply it any parameter you'd like. Properties from $data, custom values or even properties from different contexts:
ko.applyBindings({
container: {
containerId: 42,
items: [{
id: 1,
category: 'item category',
name: 'item name',
log: function(id, category, name, custom, containerId) {
console.log(`id: ${id}, category: ${category}, name: ${name}, custom text: ${custom} containerId: ${containerId}`);
}
}]
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div data-bind="with: container">
<div data-bind="foreach: items">
<button type="button" data-bind="click: function() { log($data.id, $data.category, $data.name, 'custom text', $parent.containerId); }">Click me</button>
</div>
</div>
Upvotes: 0
Reputation: 714
I always use that and works fine.
html:
<input type="button" value="click to test" data-bind="click: $root.getCompleteDetails" />
javascript:
getCompleteDetails: function (item, event) {
// you can access all properties in item parameter
}
I hope it helps.
Upvotes: 0
Reputation: 98
For click binding inside a loop, use this to get values of entry in current row.
<tbody data-bind="foreach: DataList">
<tr>
<td><input type="label" data-bind="text: Id"></td>
<td><input type="label" data-bind="text: Category"></td>
<td><input type="label" data-bind="text: Name"></td>
<td><input type="button" data-bind="click: $parent.getCompleteDetails" value="View Details"/></td>
</tr>
</tbody>
In Knockout script, get current row entries using this keyword
self.DataList =ko.observableArray([]); //this is used to populate the data entries.
self.getCompleteDetails= function() {
alert(this.Id);
alert(this.Category);
alert(this.Name);
}
Upvotes: 0
Reputation: 23372
Even though you can fix it with a bind
in your click binding, I don't think this is the best solution.
The click
binding passes the clicked model to the listener by default. Bind will create a new function for each item and moves logic to your views.
Here's an example:
var data = [
{ Id: 0, Category: "A", Name: "A0" },
{ Id: 1, Category: "B", Name: "B1" },
{ Id: 2, Category: "C", Name: "C2" },
{ Id: 3, Category: "D", Name: "D3" }
];
ko.applyBindings({
data: data,
log: function(item) {
console.log(item);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<ul data-bind="foreach: data">
<li data-bind="click: $parent.log, text: Name"></li>
</ul>
Create an extra onClick
function if you need to extract properties to an argument list:
var data = [
{ Id: 0, Category: "A", Name: "A0" },
{ Id: 1, Category: "B", Name: "B1" },
{ Id: 2, Category: "C", Name: "C2" },
{ Id: 3, Category: "D", Name: "D3" }
];
var log = function(id, cat, name) {
console.log("Item ", id, "was clicked. (name:", name, "category:", cat);
}
ko.applyBindings({
data: data,
onClick: function(item) {
log(item.Id, item.Category, item.Name);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<ul data-bind="foreach: data">
<li data-bind="click: $parent.onClick, text: Name"></li>
</ul>
Upvotes: 2
Reputation: 24915
Adding ()
after function name will call it. You will have to use .bind
click: getLast7.bind(this, $data.Id, $data.Category, $data.Name)
function vm(){
this.notify = function(str){
console.log(str)
}
}
ko.applyBindings(new vm())
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.0.0/knockout-min.js"></script>
<div data-bind="click: notify.bind(this, 'Hello')">Click me</div>
Upvotes: 31