### Tell us about the problem
I'm using Nativescript with Typescript and I have found a problem when I use the special keyword _$Parents_.
Main.xml:
<Page loaded="pageLoaded">
...
<ListView items="{{ items }}">
<ListView.itemTemplate>
<Label text="{{ $value }}" col="0"/>
<Label text="myTest" tap="{{ $parents['ListView'].onTap, $parents['ListView'].onTap}}" />
</ListView.itemTemplate>
</ListView>
...
</Page>
Main.ts:
export function pageLoaded(args: EventData) {
// Gets the page.
let page = <Page>args.object;
page.bindingContext= new MainModel("test");
}
Main-Model.ts:
export class MainModel extends Observable {
....
private name: string;
constructor(name: string) {
....
this.name = name;
}
public onTap(event: EventData) {
console.log(this.name); // Prints undefined..
}
When I use the keyword _$Parents_ the method _onTap_ is called correctly, but the variable _name_ has the value _undefined_.
If the method is called outside the ListView the variable _name_ has the correct value "_test_".
### Which platform(s) does your issue occur on?
Android
### Please provide the following version numbers that your issue occurs with:
In your particular case, the scope of this in your onTap method will return the binded data for your tapped list view cell. So the scope of this is no longer your view model but the object passed as binding for your cell.
e.g.
<GridLayout rows="*, auto" columns="*">
<ListView row="0" items="{{ items }}">
<ListView.itemTemplate>
<StackLayout>
<Label text="{{ $value }}" col="0"/>
<Label text="{{ $parents['ListView'].name, $parents['ListView'].name }}" tap="{{ $parents['ListView'].onTap, $parents['ListView'].onTap }}" />
</StackLayout>
</ListView.itemTemplate>
</ListView>
<Button row="1" text="onOtherTap" tap="{{ onOtherTap }}" />
</GridLayout>
export class HelloWorldModel extends Observable {
public name: string;
public items: Array<number>
constructor() {
super();
// Initialize default values.
this.name = "Cell name";
this.items = [1, 2, 3, 4, 5, 6, 7];
}
public onTap(args: EventData) {
console.log(args.object); // e.g. Label
var tappedLabel = <Label>args.object;
console.log(tappedLabel.text)
console.log(args.eventName); // e.g. tap
console.log(this) // binded data for the cell template (e.g. 7)
}
public onOtherTap(args: EventData) {
console.log(this); // HelloWorldModel
console.log(this.name) // "Cell name"
}
}
Thanks @NickIliev,
I understand..
Now to get the correct value of the variable _name_ I'm using the _.parent_
args.object.parent ... .parent
But I don't like this type of solution, because there could be problems if the DOM is changed.
Is there another practice to get the value of the model? What is the best practice?
EDIT
I could use: let context = args.object.page.bindingContext; console.log(context.name);
Indeed at this very moment using the parent annotation is one of the applicable way I can think of for solving your issue. To avoid using endless .parent annotations which may lead to confusion in your code (and also as you mentioned are not very good solution when the layouts are changed) you can attach directly to the binding context of your current view's page (assuming that you have provided the binding context for the page and not for some nested elements).
e.g. (for your case)
var currentPage = args.object.page;
console.log(currentPage.bindingContext.name)
All properties available for your View can be found here
Thank you guys, I was trying to figure this out and this is the answer.
I had to import the View first,
import { View } from ‘ui/core/view’;
Then, inside my onTap() method,
var view = <View>args.object;
var model = view.page.bindingContext;
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
Indeed at this very moment using the parent annotation is one of the applicable way I can think of for solving your issue. To avoid using endless .parent annotations which may lead to confusion in your code (and also as you mentioned are not very good solution when the layouts are changed) you can attach directly to the binding context of your current view's page (assuming that you have provided the binding context for the page and not for some nested elements).
e.g. (for your case)
All properties available for your View can be found here