Let's assume that I have the list of items that I would like to display on the screen. Each item should be displayed as the row with the item id, name and value. Additionally, there should be a button that allows the user to remove the item from the list.
Here is the item model:
import observableModule = require("data/observable");
class ItemModel extends observableModule.Observable {
constructor(id: number, name: string, value: string) {
super();
this.set("id", id);
this.set("name", name);
this.set("value", value);
}
remove() {
console.log("inside remove method in item model");
}
}
export = ItemModel;
Here is the page view model:
import observableModule = require("data/observable");
import observableArrayModule = require("data/observable-array");
import itemModel = require("./itemModel");
class BindingsTestViewModel extends observableModule.Observable {
items: observableArrayModule.ObservableArray<itemModel>;
constructor() {
super();
this.items = new observableArrayModule.ObservableArray<itemModel>();
this.items.push(new itemModel(100, "Item 1", "Value 1"));
this.items.push(new itemModel(101, "Item 2", "Value 2"));
this.items.push(new itemModel(102, "Item 3", "Value 3"));
this.items.push(new itemModel(103, "Item 4", "Value 4"));
}
remove() {
console.log("inside remove method in main VM");
}
}
export = BindingsTestViewModel;
And finally, here is the view:
<Page loaded="load">
<StackLayout orientation="vertical">
<ListView items="{{ items }}">
<ListView.itemTemplate>
<GridLayout columns="50px,*,*,auto" cssClass="itemContainer" >
<Label col="0" text="{{ '#' + id }}" cssClass="itemId" />
<Label col="1" text="{{ name }}" cssClass="itemName"/>
<Label col="2" text="{{ value }}" />
<Button col="3" cssClass="deleteButton" text="Delete" tap="{{ remove }}">
</Button>
</GridLayout>
</ListView.itemTemplate>
</ListView>
</StackLayout>
</Page>
The viewModel is instantiated and assigned to page.bindingContext on page load. The list of items is observable array and it is bound to ListView widget. As you can see there is the button in the item template that has event handler defined for tap event - tap="{{ remove }}".
So, when I click "Delete" button, the remove() method is invoked on the page view model (parent) and not item model. That's quite unexpected, because the same handlebars syntax for the text bindings - text={{ name }} causes getting the value from the current item model. That means that the context for data binding declarations and event handler declarations is not the same.
tap="{{ remove(id) }}"tap="{{ function() { remove(id); } }}"tap="remove(id)"tap="function() { remove(id); }"Indeed you can use function from your view-model as event handler:
...tap="{{ remove }}"...
and you can access the UI element and the bindingContext like this:
function remove(args) {
var btn = args.object;
var item = btn.bindingContext;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With