Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: components without a selector #1662

Closed
btford opened this issue May 4, 2015 · 20 comments
Closed

Feat: components without a selector #1662

btford opened this issue May 4, 2015 · 20 comments
Labels
effort2: days feature Issue that requests a new feature state: Needs Design

Comments

@btford
Copy link
Contributor

btford commented May 4, 2015

With the router, it's now possible to have components that are instantiated without needing a selector. However, a call to compiler.compileInHost with a component without a selector in the Component annotation throws:

// throws
compiler.compileInHost(SelectorlessCmp).then( ... )

@Component()
@View({
  template: 'hello!'
})
class SelectorlessCmp {}

I think this is a reasonable case to support.

Related: #2336

@tbosch
Copy link
Contributor

tbosch commented May 4, 2015

Someone needs to define what kind of element the router should create for this component. Right now, we are using the selector for this.

@jelbourn
Copy link
Member

jelbourn commented May 4, 2015

This is also something that makes sense for Components you always want to open dynamically (such as overlays).

It would be totally reasonable to, in the absence of a selector, just use a <div>

@btford
Copy link
Contributor Author

btford commented May 4, 2015

Wait, so compileInHost will create an element matching the selector in the containing element? That's kind of surprising to me.

I agree with @jelbourn; a div would suffice as a default.

@tbosch
Copy link
Contributor

tbosch commented May 4, 2015

@btford yes.

@btford
Copy link
Contributor Author

btford commented May 4, 2015

I don't think this behavior is bad, but selector doesn't really imply that to me. We should definitely make sure this is documented.

Can we use a div in cases when selector is missing, then?

@mhevery
Copy link
Contributor

mhevery commented May 5, 2015

👍 for using div where no selector

@yjbanov
Copy link
Contributor

yjbanov commented Jan 15, 2016

How about automatically kebab-casing the class name and making it a selector if one is not specified explicitly? Example:

MaterialButton => <material-button>

This would allow us to make selector completely optional even for components that are not instantiated dynamically.

@0x-r4bbit
Copy link
Contributor

@yjbanov I might be missing something, but does that work with minification?

@yjbanov
Copy link
Contributor

yjbanov commented Jan 19, 2016

@PascalPrecht For production the name could be extracted ahead-of-time via a build step prior to minification and left intact even if the class name is obfuscated. During development you generally do not minify the code and therefore the name can be extracted dynamically at runtime without a build step.

@wardbell
Copy link
Contributor

I did not know that selector is required nor is that apparent in documentation. It has always worked for me without a selector ... no objection from A2 at all. I argue that the selector should remain optional.

I omit the selector because it serves no obvious purpose and sends the wrong message. When I specify a selector, I'm implying that Angular should look for a matching target in the parent. That's just not the case with routing. Nor is it the case if I should decide to deploy the component dynamically.

I hadn't given much thought to what element is created for the component. I assumed that the result of the template compilation was just dropped into a <div> ... if necessary ... which it really isn't if the template has it's own container:

<div>
   ... content
</div>

If I really cared about creating a wrapper element, I don't need the selector to do that. I just write:

<my-wrapper>
 ... content
</my-wrapper>

I'm clearly missing your point @yjbanov. And, FWIW, creating an element called <selector> is far worse than creating a <div>; the name is not obvious and it's another thing that I might think I have to know that actually does nothing for me. We have too many of those now.

@yjbanov
Copy link
Contributor

yjbanov commented Jan 19, 2016

@wardbell: I merely suggested a method for getting an element name automatically if the developer hasn't specified a selector. Whether we should do that is a separate question. Having to deal with extra wrappers is a valid concern.

I like your reasoning that selector is there to, well, select a component to be used at some location in the template. If instantiated dynamically, there's no need for a selector, and angular's addition of a wrapper element feels redundant.

@wardbell
Copy link
Contributor

We are on the same page ;-)

@kasperpeulen
Copy link

@wardbell I 100% agree with you, I suspected it to work like that as well.

I assumed that the result of the template compilation was just dropped into a

... if necessary ... which it really isn't if the template has it's own container.

Why is it necessary to create a div (when the template has no container)? Can't we just drop the NodeFragment there? div is also random in some sense I guess. Why not span then?

@yjbanov
Copy link
Contributor

yjbanov commented Jan 19, 2016

@wardbell: Thought of one problem for making selectors not appear in the DOM when instantiated dynamically: it makes introspection harder. If I wanted to find some component on the page in the browser's dev tools I'd first look at element names. If element names are sometimes missing it makes this method of looking for components unreliable. IOW, I'd be querying this same selector in my mind after the component is instantiated, so one could argue that the selector and component element should exist in tandem. The same could apply to tests. If a test is trying to verify that a component appears on the page, it would be very easy to query the same selector.

@kasperpeulen: I agree, any automatic wrapper feels random. That's actually what makes the current approach of requiring a selector more consistent: you always get a wrapper irrespective of the method you used to instantiate the component, and the wrapper is always named after the selector*.

* one little wart in using the selector as a basis for the element name is that not all selectors can be reverse-engineered into a decent element name. I'm curious what happens today if the selector is my-button[raise="high"].

@wardbell
Copy link
Contributor

@yjbanov I agree that introspection is a challenge until the developer of the component offers help. The dev can do that in all kinds of ways with identifying markup in the template itself.

Unfortunately, programmatic introspection is only marginally improved by having an element type other than <div>. I have struggled to find well-named components within all kinds of containers including routed components when I don't know the type of thing I'm looking for. For example, how do I get the child within a tab-pane within a tab-container control ... when that child could be any kind of component? I haven't found the A2 query mechanism for that ... other than to throw an arbitrary local var on it and search for that.

OTOH, if I _do_ know the component I'm looking for, it isn't hard at all ... with or without a known element. I just ask for viewChild or contentChild by component name (I forget which).

Also I've never had a problem finding the routed component element as a human probing in the browser tools. It's right there, next to <router-outlet></router-outlet>. That's a pretty good clue for e2e testing as well.

@yjbanov
Copy link
Contributor

yjbanov commented Jan 20, 2016

I haven't found the A2 query mechanism for that

If there's always the same tag corresponding to a component then you don't need an Angular-specific mechanism to find it. You just document.querySelector('my-component').

@kasperpeulen
Copy link

  • one little wart in using the selector as a basis for the element name is that not all selectors can be reverse-engineered into a decent element name. I'm curious what happens today if the selector is my-button[raise="high"].

Yes, using a selector, to not select something, but to create something seems off. For example I have this component I route to:

<div *ngIf="ready">
  <editor></editor>
  <splitter></splitter>
  <preview></preview>
</div>

I guess not a good idea, to use here the 'div[*ngIf="ready"]` as selector instead

@mhevery
Copy link
Contributor

mhevery commented Jul 1, 2016

This is obsolete, and no longer relevant / actionable. To keep our issues clean, we are aggressively closing them.

The new router makes this obsolete.

@achieverprince
Copy link

Please have a look at this issue in router
http://stackoverflow.com/questions/41743128/the-selector-ng-component-did-not-match-any-elements-error

Error: The selector “ng-component” did not match any elements error
While using router
How do i handle this? is it a bug in @angular/compiler , cos this happened only while packaging through webpack!!

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 10, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
effort2: days feature Issue that requests a new feature state: Needs Design
Projects
None yet
Development

No branches or pull requests

10 participants