angular: document that namespaces are not supported in a directive's selector

I’m submitting a…


[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report  
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
[ ] Other... Please describe:

Current behavior

Directive’s selector has no colon support (while component’s selector handles colon properly).

@Directive({
  selector: '[ns:selector]'
})
<span ns:selector></span>

Does not work at all and produce no errors.

At the same time selector without namespace (selector: '[selector]') works with any namespace in markup. E.g., with <span ns:selector></span>.

Also tried to use with XML mode https://www.w3.org/TR/html5-diff/#syntax but no success.

Expected behavior

Colon-separated namespaces in Directive’s selector recognized and processed properly.

Minimal reproduction of the problem with instructions

https://stackblitz.com/edit/angular-gitter-35fnah

What is the motivation / use case for changing the behavior?

Use colon (XML namespaces) in Directive’s selector and in a markup.

Proof of interest: question (not mine) https://stackoverflow.com/questions/39005486/angular-2-selector-with-namespace without an answer.

Environment


Angular version: 6.0.3


Browser:
- [x] Chrome (desktop) version 67

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 15 (11 by maintainers)

Most upvoted comments

@manklu I understand your points, but you’re actually talking about namespace shouldn’t be supported in HTML template, rather than in Directive selector.

Given Directive is an enhancer of the elements, and namespaces are already supported in elements:

Then Angular should take the responsibility to make any element interceptable/spyable, it’s for consistency.

Also, it’s NOT a bunch of work as it’s only for selector matching. Namespaces are already well-handled anywhere else than selector in Angular framework.

If Angular is going to drop support of namespace in view, then I’ll be fine with that, but obviously it’s not.

There’re several concerns:

1. Namespace is never being supported as part of selector

https://github.com/angular/angular/blob/d76531d16eb57391a8ee4cf3375a550e72307b67/packages/compiler/src/selector.ts#L11-L21

If element selector works, that would just be an unexpected accident. Tried and it won’t work.

2. Lacking of supporting namespace should be documented

It’s a known fact that directive selector is a subset of CSS selector, but the detail of subsetting should be well-documented.

3. Unsupported selector type should raise error

Current way of matching RegExp is too weak and tricky, there should be a selector parser and applying restricted rules.

In the repro above, [ns\\:selector] is parsed like selector which is not expected: https://stackblitz.com/edit/angular-gitter-63fzu7?file=app/app.component.html.

See also https://github.com/angular/angular/issues/2589 & https://github.com/angular/angular/issues/6600.

4. Single-element selector should be supported

Even with namespace being part of the selector, it’s still for single element and doesn’t break any design, should be supported by Angular compiler.


It’s actually not a big deal for marking it bug or feature for now, as the problem cannot be easily solved.

@manklu I’m kind of agree with you now since namespace used in HTML-based documents wouldn’t result a different HTML shape:

image

Even when wring <svg:svg></svg:svg> is supported in template, it would still result <svg></svg> in the view.

So there’d no difference in selector.


EDIT: but that’s for specific Renderer implementation, while Directive application is irrelevant to that. So in a non-DOM platforms, namespaces could be handled differently than using createElementNS, which can indeed result to different view shape.

Directive selector is only meant for template, not for view. A Directive with attribute/class selector would still be there even when the attribute/class being removed. Whether a namespace prefix being preserved at runtime doesn’t affect the existence of Directive.

The template code:

<ns:el></ns:el>

Will be compiled to:

renderer.createElement(/* name */'el', /* namespace */'ns')

This is the current behavior, not a proposal. And namespace URI mapping is not related to the compilation process, which is still the existing behavior.

For the Directive matching process, it’s assumed that normalized template being the actual HTML (with property-binding and event-binding meant an attribute), and check whether a selector matches or not:

image

And the namespace URI mapping is a platform-specific operation for the view, no matter the static mapping which Angular did today or the smart mapping you proposed (can be fulfilled by custom Renderer), it’s not for the template, and shouldn’t be considered here.

@mhevery Given namespace is a valid part of element/attribute selector, why shouldn’t it be supported?

@trotyl Two thoughts.

  1. Namespaces are only allowed with XHTML.
  2. It is a big bunch of work to do it correctly.

With namespaces implemented correctly, you would get something like this:

@Directive({
  selector: '[http://example.org/QualifiedNamespace:selector]'
})
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ns1="http://example.org/QualifiedNamespace">
  <head>
    <title>Title of document</title>
  </head>
  <body>
    <p>
      <span ns1:selector></span>
    </p>
  </body>
</html>

It seems to me it is not implemented in the template compiler @trotyl @mhevery This is feature request?

The syntax will be similar to Vue:

<h1 v-on:click="say('hello world')"></h1>

<button @click.prevent="onClick">
</button>

It would be very cool if you could independently parse through directives templates

@Directive({
  selector: '[v-on:click]'
})
class VClickDirective {
 // add event listener onclick 
}
@Directive({
  selector: '[@click.{*}]',
  provide: [SeparatorParser]
})
class CustomClickDirective {
 constructor(separator: SeparatorParser) {
   // <button @click.prevent="onClick"></button>
   const values = separator.getValues(); // ['prevent']
   const values = separator.getKeys(); //  { 'prevent': 0 }
   // or anything API
 }
}