2

I have a parent component with a template that references multiple instances of the same child component. The child components would have the same component/template implementation but should be instantiated multiple times and would render different data sets. I looked into a lot of posts like Instance Angular 2 Component Two times but all of them seemed to use the deprecated directives component attribute.

parent.template.html

<child-component data="foo"></child-component>
<child-component data="baz"></child-component>

data.service.ts

import { Injectable } from '@angular/core';

@Injectable()
export class DataService {
    getFooData(): Object {
        return { name: 'Foo' }
    }

    getBazData(): Object {
        return { name: 'Baz' }
    }
 }

child.template.html

<h1>{{objectToRender.name}}</h1>

child.component.ts

import { Component, Input, OnInit } from '@angular/core';
import { DataService }              from './data.service';

@Component({
    selector:       'child-component',
    templateUrl:    'child.template.html',
    providers:      [ DataService ]
})
export class ChildComponent  implements OnInit {
    @Input() data: String;
    objectToRender: Object;
    ds:             DataService

    constructor( private dataService: DataService ) {
        this.ds = dataService;
    }

    ngOnInit(){
        switch( this.data ) {
            case 'foo':
                this.objectToRender = this.ds.getFooData();
            case 'baz':
                this.objectToRender = this.ds.getBazData();
        }
    }

}    

app.module.ts

import { NgModule }             from '@angular/core';
import { BrowserModule }        from '@angular/platform-browser';
import { AppComponent }         from './app.component';
import { ParentComponent}     from './parent.component';
import { ChildComponent }     from './child.component';


@NgModule({
    imports:      [ BrowserModule ],
    declarations: [ AppComponent, ParentComponent, ChildComponent ],
    bootstrap:    [ AppComponent ]
})
export class AppModule { }

Result: Baz Baz

Expected: Foo Baz

An even simplified version of my problem can be seen in this Plunker. I've omitted template files all together and use the root app component as a parent. https://plnkr.co/edit/QI5lGH3S9a5o3b1ajPBl?p=preview

Many Thanks in advance !

Community
  • 1
  • 1
Stefan Gladkov
  • 115
  • 2
  • 7
  • What is " the deprecated directives component attribute."? – Günter Zöchbauer Nov 22 '16 at 19:16
  • shouldn't you go for *ngFor ? – Nitishkumar Singh Nov 22 '16 at 19:16
  • I don't get what the problem is. What are you trying to accomplish? What is the current behavior? What is the expected behavior? – Günter Zöchbauer Nov 22 '16 at 19:16
  • @GünterZöchbauer, The `directives` attribute on the `@Component` decorator has be deprecated in the final version of Angular 2. – ppovoski Nov 22 '16 at 19:19
  • https://angular.io/docs/ts/latest/guide/ngmodule.html. Just move it to `declarations: [...]` of `@NgModule()` – Günter Zöchbauer Nov 22 '16 at 19:19
  • @Günter Zöchbauer Currently it renders everything, however the child component is a singleton so

    {{objectToRender.name}}

    would always be Baz ( The last instance of the component to be rendered )
    – Stefan Gladkov Nov 22 '16 at 19:20
  • @Günter Zöchbauer I currently have it there, and this is the behavior that I see where it assigns the same dataset to all the instances of the child-component in the parent component – Stefan Gladkov Nov 22 '16 at 19:22
  • You can still add `providers: []` to `@Component()`, that's what seems to be relevant with your question. Only `directives:` was removed from `@Component()`. – Günter Zöchbauer Nov 22 '16 at 19:25
  • @Nitishkumar Singh I thought of using *ngFor as well, however, these child components would be used on different pages so I don't want to copy paste the same code in different templates. They are also not ordered in the sense that I can have child-component-> something-else -> another-thing -> child-component -> child-component – Stefan Gladkov Nov 22 '16 at 19:31
  • you can create an component, which will use *ngFor and insert that component everywhere. so you won't need to code it again. – Nitishkumar Singh Nov 22 '16 at 19:34
  • @Nitishkumar Singh Yes that's what I want to do in the end, however if I use child-component multiple times on the same template the data always resolves to the last instance of it. In my example it would always be 'Baz' as again, the parent component treats the child as a singleton. What I'm really after is something like a Component factory that I can call to create new instances of the child component every time it is referenced in the parent component. – Stefan Gladkov Nov 22 '16 at 19:39
  • @Günter Zöchbauer I tried that, however I still get the same result: 'BAZ' 'BAZ' – Stefan Gladkov Nov 22 '16 at 19:40
  • Have you actually tried with the exact code as in your question? This just works. I can hardly imagine anything that could cause this to not work. Plunker doesn't work for me today, otherwise I had tried to reproduce. – Günter Zöchbauer Nov 22 '16 at 19:41
  • @Günter Zöchbauer my example is a simplified version of what I have as I have a lot of code in those components that I wanted to omit from my post. I'll create a Plunker and edit my question to show the behavior that I experience a bit better. – Stefan Gladkov Nov 22 '16 at 19:44
  • Then you should try with the simplified code. I'm quite sure there is some bug that is not included in the code in the question or false assumption. – Günter Zöchbauer Nov 22 '16 at 19:45
  • it's your data service, which is singleton not your child components. please edit your question. I think you need to provide different inputs, so that your service can return data respective to their child component – Nitishkumar Singh Nov 22 '16 at 19:46
  • @Nitishkumar Singh Please elaborate, my data service is a singleton, however the 2 child components should be calling different functions to get data from it and should just render the response. In my e.g. the first child component should call getFooData() and second child should call getBazData() which would result in different responses to be rendered on the view. – Stefan Gladkov Nov 22 '16 at 19:48
  • @Nitishkumar Singh Is that not the case though ? Different methods of the DataService would be called depending on the value of data attribute – Stefan Gladkov Nov 22 '16 at 19:51
  • can you share your parent component.ts? – Nitishkumar Singh Nov 22 '16 at 20:02
  • @Nitishkumar Singh Please refer to the provided Plunker in my updated question, I've simplified it even further where I remove html templates all together and use the root app component as a parent. – Stefan Gladkov Nov 22 '16 at 20:09

1 Answers1

3

It's the missing break;

    switch( this.data ) {
        case 'foo':
            this.objectToRender = this.ds.getFooData();
            break;
        case 'baz':
            this.objectToRender = this.ds.getBazData();
            break;
    }

Plunker example

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567