5

[UPDATE] Please read the comment history to understand the context.


All:

I am pretty new to angular2, when I follow its quickstart guide, one question confuses me:

I simplify the app.component.ts as:

import { Component } from "angular2/core";
@Component({
    selector: "my-app",
    template: "<div>{{title}}</div>"
})
export class AppComponent {
        title = "Tour of Heroes" + Math.random();
}

And I add another my-app tag into index.html like:

  <body>
    <my-app>Loading...</my-app>
    <my-app>Loading...</my-app>
  </body>

I wonder why the second one can not get rendered?

Another question related to this is:

If I put two instance of same component, each one will keep their own member variable, but if I inject service into one component, then all component instances share the same service instance, I find the only obvious diff is they use different annotation( other than this, they both export a class): @Component and @Injectable, and one in directives array while the other in providers array. I wonder if these 2 annotation tell angular how can treat the instance or the directives array and providers array do that?

Kuan
  • 11,149
  • 23
  • 93
  • 201
  • Comments can be deleted, if the comments contain information vital to answering the question, than you should mirror that info into the question. – Tezra Jun 07 '17 at 14:48

3 Answers3

4

Angular2 doesn't allow to bootstrap the same component twice in an HTML page.

This is however possible to bootstrap different application components if you want in a same HTML page.

See this documentation for more details:

Edit

Regarding your second question, you need to be aware that @Component and @Injectable are decorators. They are responsible to "wrap" target instances and allow dependency injections by providing right dependency instances in constructor based on configured metadata.

Regarding hierarchical injectors, you could have a look at this link:

Community
  • 1
  • 1
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • Thanks, so this mean only the root app component may have this restriction issue? If I put component inside app component, then everything is ok? – Kuan Mar 07 '16 at 18:57
  • Yes, it's only at the bootstrap level. You can use component like you want inside your Angular2 application ;-) – Thierry Templier Mar 07 '16 at 18:58
  • 1
    See the doc for more details: https://angular.io/docs/ts/latest/api/platform/browser/bootstrap-function.html. Section "Bootstrapping Multiple Applications". – Thierry Templier Mar 07 '16 at 18:59
  • Thanks, I wonder how does Angular2 decides when to generate a new one or reuse a existing instance? Is that because if I use `@Injectable` or use `@Componnet`? – Kuan Mar 07 '16 at 19:09
  • You could have a look at this answer: http://stackoverflow.com/questions/34804298/whats-the-best-way-to-inject-one-service-into-another-in-angular-2-beta/34807397 regarding hierarchical injectors... – Thierry Templier Mar 07 '16 at 19:19
  • 1
    Components are instantiated according to their use in templates. Services relies on where their providers are configured. For example, if you put a provider when bootstrapping the application, a single instance will be shared by the whole application. – Thierry Templier Mar 07 '16 at 19:26
  • Thanks, two things to clear: **1** so if I register serviceA in app component's providers array, then I also put it in subcomponent's providers array(subcomponent is under app), then there will be 2 instances of serviceA? **2** If I only register serviceA in app level, the way to use it in subcomponent is to add import {serviceA} from "somewhere" and directly use it in subcomponent, is that correct? – Kuan Mar 07 '16 at 19:35
  • 1
    You're welcome! For 1) yes two instances of the service (one per level) For 2) yes only import the class and the same instance will be injected... – Thierry Templier Mar 07 '16 at 19:40
  • One last thing: as for component(not service), how angular knows it should generate new instance rather than inject a existing component instance?(is that because we register the component inside the directives array and everything inside that will get a new instance each time?) – Kuan Mar 07 '16 at 19:51
2

This is currently not supported. You need to initialize each root component with bootstrap(AppComponent) but that only works if both components have different selectors.

See also https://github.com/angular/angular/issues/7136

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    Yes, it works fine for components inside other components. The root component has also other limitations https://github.com/angular/angular/issues/1858 – Günter Zöchbauer Mar 07 '16 at 18:58
  • Thanks, I wonder how does Angular2 decides when to generate a new one or reuse a existing instance? Is that because if I use `@Injectable` or use `@Componnet`? – Kuan Mar 07 '16 at 19:09
  • 1
    Angular DI is hierachical. Each component, directive, pipe, ... has its own injector, each child components injector is a child of the injector of the parent component. `bootstrap()` creates the root injector. When DI looks up a dependency it iterates from the requesting component towards root. When it finds a provider it requests the instance from there. The injector where the provider was found keeps a single instance of the dependency and returns the same every time. If you get a new instance or the same depends where you register a provider. – Günter Zöchbauer Mar 07 '16 at 19:13
  • If you register a provider on a component, each component gets its own instance. If you register with `bootstrap()` all components, directives, ... get the same instance (global singleton). – Günter Zöchbauer Mar 07 '16 at 19:14
  • Thanks, I update my question(I guess ur answer is from a slightly diff perspective, but it helps me to understand my question). And just rephrase and expand to verify my understanding: so the providers array decide all instances of same component will share a service instance but different components will each own service instance. So to wrap it up: the number of instance of one service is decided by how many different components register it in providers array and each service instance will serve all instance of same component. Is this correct? – Kuan Mar 07 '16 at 19:37
  • 1
    You update is quite hard to understand. `providers` on a component is as explained in a previous comment if the component instance gets its own service instance or if one provided by a parent injector is injected. `directives` is for registering components and directives to be used in the view (HTML). If a directive is registered and a selector matches then Angular creates an instance. Some `CORE_DIRECTIVES` `ngFor`, and similar a applied globally and don't need to be added to `directives` – Günter Zöchbauer Mar 07 '16 at 19:37
  • One last thing: as for component(not service), **how** angular knows it should generate new instance rather than inject an existing component instance?(is that because we register the component inside the directives array and everything inside that will get a new instance each time?) – Kuan Mar 07 '16 at 19:54
  • 1
    Angular usually injects services not components. When new instances are created is what I tried to explain above. It depends on where the service is registered as provider. Components and directives are always new instances for each tag that matches the selector. – Günter Zöchbauer Mar 07 '16 at 19:59
  • Thanks, got it. I guess I have to accept "this is the way HOW angular works" but without knowing HOW. – Kuan Mar 07 '16 at 20:04
  • DI takes a while to wrap the head around. Once you got it its quite simple. – Günter Zöchbauer Mar 07 '16 at 20:07
-1

To my knowledge, apart from the main component you can use any other component multiple times in the same html page.

Can achieve this by using @Input decorator Declare an attribute to your selector element/directive in html and get the value of that attribute in Component by using @Input decorator

import { Component,Input } from "angular2/core";

@Component({
    selector: "my-app",
    template: "<div>{{title}}</div>"
})
export class AppComponent {
        @Input() title;
}    
  <body>
    <my-app title = "somedata1">Loading...</my-app>
    <my-app title = "somedata2">Loading...</my-app>
  </body>

Can find an example in this link

Angular2 .. Using the same component to show different data on the same page depending on service response

praveen
  • 489
  • 6
  • 12