1
votes

I'm using useShadowDom: false with my components in an attempt to support more browsers without having to use the troublesome web_components polyfill. With the shadow DOM enabled, I would do something like this:

void onShadowRoot(ShadowRoot root) {
  root.querySelector('.btn-go-back').onClick.listen((e) {
    if (goBackHandler != null) {
      goBackHandler();
    }
  });
}

onShadowRoot would run after my component's template was loaded and therefore all the components elements exist in the DOM. Without Shadow DOM enabled, I inject the component's root element in the constructor, and do something like this:

MyComponent(this._root){
  _root.querySelector('.btn-go-back').onClick.listen((e) {
    if (goBackHandler != null) {
      goBackHandler();
    }
  });
}

This doesn't work because the component's template hasn't been loaded into the DOM yet, so the root element doesn't have any children to query yet.

I've tried implementing AttachAware, and querying the root element in the attach() method, and the template isn't loaded at that point either.

So, if I'm not using the shadow DOM, how can I know when the template has been loaded into the DOM so I can query elements within my component?

Edit

Attempting to use ShadowRootAware and onShadowRoot with useShadowRoot: false will result in the following error if you try to query against the provided ShadowRoot object:

Unsupported operation: Not supported

STACKTRACE:
#0      EmulatedShadowRoot._notSupported     (package:angular/core_dom/emulated_shadow_root.dart:5:21) 
#1      EmulatedShadowRoot.querySelector (package:angular/core_dom/emulated_shadow_root.dart:32:63)

I also tried a combination of:

  • Injecting the root element in the constructor and
  • querying against the root element within onShadowRoot which worked, kinda, but now I'm seeing this in the console output:

[WebPlatformShim] WARNING: Failed to set up Shadow DOM shim for [find-result].

InvalidCharacterError: The string contains invalid characters. '[find-result]' is not a valid attribute name.

So, for some reason, even with useShadowDom set to false on all my Components, it's still attempting to use the ShadowDom shim. I'm assuming this is because it is because I've implemented ShadowRootAware which constructs an EmulatedShadowRoot. So, I think I need a solution that avoids onShadowRoot

3
The error message seems to be caused by this bug github.com/angular/angular.dart/issues/1189Günter Zöchbauer
Yep, I saw that (noted in comment to Alexandre). Funny thing is, it still fails when I use a class selector, so .find-result instead of [find-result]w.brian

3 Answers

5
votes

You can query the template of a emulated component as follows:

class Component implements ShadowRootAware {
  Element el;

  Component(this.el);

  void onShadowRoot(_) {
    this.el.querySelector('.blah');
  }
}

The error message:

[WebPlatformShim] WARNING: Failed to set up Shadow DOM shim for [find-result].

is caused by the css shim. This is one of the limitations of the shim (you can use only element selectors).

You can disable the css shim. Then you will not see the error, but you won't have CSS encapsulation.

See more here:

https://github.com/angular/angular.dart/wiki/CSS-Shim

2
votes

We schedule child elements querying on the next event loop iteration. I'm not aware about particular internal implementation details, but it reliably works fine for us:

MyComponent(Element root) {
  // Schedule child elements querying on the next event loop iteration when
  // AngularDart will render the child DOM.
  new Future(() {
    root.querySelector('.btn-go-back').onClick.listen((e) {
      if (goBackHandler != null) {
        goBackHandler();
      }
    });
  });
}
1
votes

You can also use onShadowRoot even with useShadowDom: false. However the parameter provided is not a ShadowRoot object.