Skip to content

@ViewChild fails on built-in {N} components given their class name #1064

@justindujardin

Description

@justindujardin

Overview

Angular is unable to match queries against class names for built-in {N} components. The following basic view query will fail and return undefined.

@Component({
  selector: 'comp-1',
  template: `<GridLayout></GridLayout>`
})
class CompOne implements AfterViewInit {
  @ViewChild(GridLayout) ref: GridLayout;
  ngAfterViewInit() {
    console.log("child ref is -> " + this.ref);
  }
}

Reproduction
https://play.nativescript.org/?id=ezJW7O_-Yw0QbA-pQC280&template=play-ng

Why it fails
The best way I've had it explained was by @vakrilov in Slack: The built-in {N} components are similar to the native elements in a Browser (HTMLButtonElement, HTMLInputElement, etc.) You would not query for @ViewChild(HTMLInputElement) in the Browser, so why would you query for @ViewChild(Image) or @ViewChild(Label) in {N}+Angular?

Problems
The browser element analogy makes sense as a way to explain the limitation, but it breaks down under scrutiny from a developer experience point of view. In the browser case all of the built-in elements are named consistently HTML[name]Element, so you know immediately by name if an element can be queried for using its class name. In the {N} case the built-ins are called "components" in the docs, and have no hint in their names (Image, Label, etc.) to let you know they're built-in so you have to think about it each time you write a view query.

The point I'm making here is subtle, and I understand that, but I think it's worth discussing as it has the potential to address a common stumbling block and/or point of confusion for developers getting started with {N}+Angular.

Solutions
I see at least a few ways you could try to address this:

  1. Use developer education by way of tutorials and documentation updates to make this limitation clear and understandable to users. I suspect this is a challenging way to go about things because it's hard to get people to read things before they go ask someone else for help.

  2. Update built-in names with common convention to make it more obvious that they're native elements. I don't seriously think anyone would attempt this, but it's an option.

  3. Throw an error when a developer writes a query for a built-in element. This would give developers timely feedback and keep them moving without lifting the query restriction. I don't know how realistic this is because the ViewQuery stuff is pretty buried in angular's guts and hooking it might not be straightforward.

  4. Declare built-ins as components to Angular. I believe that {N} has all the information it needs to do this. It already has a hook for declaring components registerElement which could potentially be used to decorate the view classes with @Directive and add them to an Angular module that is imported. I have verified that built-ins are queried if they're decorated and declared as components. You could even go further to map all their {N} declared properties as @Inputs.

  5. Keep this issue closed, and maybe it's a good reference for when people stumble.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions