Call element methods

Some element features have no attribute: you scroll a <scroll-view> to a position, or play a <video>, by calling a method on the element. These are UI methods, functions a native element exposes that you call by name (see Glossary).

Call a method from an event handler

src/app/app.ts
import { Component, ElementRef, viewChild } from '@angular/core';
import { LYNX_ELEMENTS } from '@blotch/angular-lynx';

@Component({
  selector: 'app-root',
  imports: [LYNX_ELEMENTS],
  template: `
    <scroll-view #list scroll-orientation="vertical" style="height: 300px;">
      @for (n of rows; track n) {
        <view style="height: 48px;">
          <text>Row {{ n }}</text>
        </view>
      }
    </scroll-view>
    <view (bindtap)="backToTop()">
      <text>Back to top</text>
    </view>
  `,
})
export class App {
  readonly rows = Array.from({ length: 50 }, (_, i) => i + 1);
  readonly list = viewChild.required('list', { read: ElementRef });

  backToTop(): void {
    this.list().nativeElement.invoke?.('scrollTo', { offset: 0, smooth: true });
  }
}
  • viewChild(…, { read: ElementRef }) gives you the element. nativeElement.invoke(method, params) calls a UI method on it.
  • It's fire-and-forget. invoke() returns nothing, and a failed call isn't reported.
  • The ?. matters outside handlers. Your app's background thread copy has no native elements, so its nativeElement has no invoke. Handlers run only on the main thread, but ?. keeps the same call safe in a constructor or ngOnInit, which run on both.

Each element's methods and their parameters are on its API page, such as <video>. Lynx's element reference lists more, such as <scroll-view>'s scrollTo and autoScroll.

Get a method's result

To read a result, such as an element's size and position, call invoke() in a main-thread script. There it returns a Promise:

src/app/app.ts
import { Component } from '@angular/core';
import {
  LYNX_ELEMENTS,
  LynxMainThreadEvent,
  mainThreadFn,
  type MainThread,
} from '@blotch/angular-lynx';

type Rect = { left: number; top: number; width: number; height: number };

const logSize = mainThreadFn((event: MainThread.TouchEvent) => {
  event.currentTarget
    .invoke('boundingClientRect')
    .then((rect: Rect) => console.log(`${rect.width} × ${rect.height}`));
});

@Component({
  selector: 'app-root',
  imports: [LYNX_ELEMENTS, LynxMainThreadEvent],
  template: `
    <view [mainThreadBindtap]="logSize" style="padding: 24px;">
      <text>Tap to log my size</text>
    </view>
  `,
})
export class App {
  readonly logSize = logSize;
}
  • boundingClientRect returns the element's size and position. left and top are measured from the top-left corner of the LynxView that shows your app.
  • The Promise rejects if the method fails.
  • console.log output shows in Lynx DevTool (see Debugging).

Select an element with lynx.createSelectorQuery()

Lynx's own API finds an element by selector and calls a method on it, and Lynx's documentation uses it for every UI method. It exists only on the background thread. Template handlers run on the main thread, where calling it throws lynx.createSelectorQuery is not a function.

So wrap the query in a backgroundFn(), and call it from a handler with runOnBackground():

import { backgroundFn } from '@blotch/angular-lynx';

// Runs on the background thread, where createSelectorQuery() exists.
const pause = backgroundFn((id: string) => {
  lynx
    .createSelectorQuery()
    .select(`#${id}`)
    .invoke({
      method: 'pause',
      success: (result) => console.log('paused', result),
      fail: (res) => console.error(`pause failed, code ${res.code}`),
    })
    .exec();
});

// In a template handler:
// runOnBackground(pause, 'player');
  • #player matches the element's id, as in <video id="player">. A class (.name) or a tag name (video) also works.
  • exec() sends the query. Nothing runs until you call it.
  • success receives the method's result. It runs later, so the result can't come back through runOnBackground(). To use a result, call invoke() in a main-thread script, as shown above.
  • fail receives { code, data }. Without a fail callback, a failed call shows an error screen.
codeMeaning
1Unknown error
2No element matches the selector
3The element has no method with that name
4The parameters aren't valid
5The selector isn't supported
6The element has no native view to call it

LynxAccessibility.requestFocus() calls the requestAccessibilityFocus method through createSelectorQuery(), so the same thread rule applies to it.