I lost my mind when trying to get "current native element" on an event with Angular (11) and NativeScript...
I have a container (home component) that contains multiple blocks (block component). Each component have a "onPan" event management, and this event is forward with @Output to let the parent known. Then, the parent (home) listen this pan event...
All of this works. But I can't check WHICH element is on move when the parent get the event. I mean, the "PanGestureEventData" carries a native "view" property, but I wasn't able to retrieve the Angular "nativeElement" from this event.
I tried to add "this" on parent template listener, but I don't know which object it is :x
Did you have any solution to retrieve, on parent, which element from "blocks" QueryList is currently sending the event ?
It's a general case, it could be any custom event that doesn't carry the current target, sent from a child to its parent :)
Thanks !
My snippets :
home.component.html
<GridLayout #refGrid columns="*,*,*,*,*,*" rows="*,*,*,*,*,*" width="100%">
<ns-block #block col="1" row="1" (moveEvent)="onMove(this, $event)"></ns-block>
<ns-block #block col="2" row="1" (moveEvent)="onMove(this, $event)"></ns-block>
<ns-block #block col="3" row="1" (moveEvent)="onMove(this, $event)"></ns-block>
<ns-block #block col="1" row="2" (moveEvent)="onMove(this, $event)"></ns-block>
</GridLayout>
home.component.ts
import {Component, ElementRef, QueryList, ViewChildren} from "@angular/core";
import {PanGestureEventData} from "@nativescript/core";
import {BlockComponent} from "../component/block/block.component";
@Component({
selector: "Home",
templateUrl: "./home.component.html"
})
export class HomeComponent {
@ViewChildren(BlockComponent, { read: ElementRef }) blocks!: QueryList<ElementRef>;
onMove(element, args: PanGestureEventData): void {
console.log("move", element);
}
}
block.component.tns.html
<Image (pan)="onPan($event)"
src="https://images.pexels.com/photos/102104/pexels-photo-102104.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500"></Image>
block.component.ts
import {Component, Output, EventEmitter} from '@angular/core';
import {PanGestureEventData} from "@nativescript/core";
@Component({
selector: 'ns-block',
templateUrl: './block.component.html',
styleUrls: ['./block.component.css']
})
export class BlockComponent {
@Output() moveEvent = new EventEmitter<PanGestureEventData>();
onPan(args: PanGestureEventData): void {
this.moveEvent.emit(args);
}
}
Couldn't you give different template ref variables to each child component and send it to the event handler?
home.component.html
<GridLayout #refGrid columns="*,*,*,*,*,*" rows="*,*,*,*,*,*" width="100%">
<ns-block #block1 col="1" row="1" (moveEvent)="onMove(block1, $event)"></ns-block>
<ns-block #block2 col="2" row="1" (moveEvent)="onMove(block2, $event)"></ns-block>
<ns-block #block3 col="3" row="1" (moveEvent)="onMove(block3, $event)"></ns-block>
<ns-block #block4 col="1" row="2" (moveEvent)="onMove(block4, $event)"></ns-block>
</GridLayout>
home.component.ts
onMove(element, args: PanGestureEventData): void {
console.log("move", element);
}
<ns-block>
In case of a dynamically generated markup using a loop, it becomes more simple since you don't have to individually name the tags. You could directly the current element to the handler using it's template ref variable.
<GridLayout #refGrid columns="*,*,*,*,*,*" rows="*,*,*,*,*,*" width="100%">
<ns-block *ngFor="let item of someArray" #block col="1" row="1" (moveEvent)="onMove(block, $event)"></ns-block>
</GridLayout>