Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass an input value into a ngComponentOutlet created component?

Tags:

angular

I have a component like:

@Component({
  selector: 'app-item',
  template: '<p>{{title}}</p>'
})
export class TitleComponent {
  @Input() title:string;
}

@Component({
  selector: 'app-foo',
  template: '<ng-container *ngComponentOutlet="outlet"></ng-container>'
})
export class FooComponent {
  outlet = TitleComponent;
}

How do you pass input title value on the ng-container for the TitleComponent or how can I set this value?

like image 802
Fran b Avatar asked Feb 05 '17 20:02

Fran b


People also ask

What is NgComponentOutlet?

NgComponentOutletlinkInstantiates a Component type and inserts its Host View into the current View. NgComponentOutlet provides a declarative approach for dynamic component creation.

What is ComponentFactory in angular?

ComponentFactorylinkBase class for a factory that can create a component dynamically. Instantiate a factory for a given type of component with resolveComponentFactory() . Use the resulting ComponentFactory. create() method to create a component of that type. Deprecated: Angular no longer requires Component factories.

What are dynamic angular components?

What dynamic components are. Dynamic means, that the components location in the application is not defined at buildtime. That means, that it is not used in any angular template. Instead, the component is instantiated and placed in the application at runtime.


3 Answers

As Reno has already mentioned, you can use an injector to inject values.

For the sake of completeness, here is an example with a dynamic "title" value:

export const TITLE = new InjectionToken<string>('app.title'); 


@Component({
  selector: 'app-item',
  template: '<p>{{title}}</p>'
})
export class TitleComponent implements OnInit {
  @Input() title:string;

  constructor(@Inject(TITLE) private titleInjected: string){

  } 

  ngOnInit() {
    this.title = this.title || this.titleInjected;
  }

}


@Component({
  selector: 'app-foo',
  template: '<ng-container *ngComponentOutlet="outlet; injector: myInjector"></ng-container>'
})
export class FooComponent {
  outlet = TitleComponent;
  myInjector: Injector;

  constructor(injector: Injector){
    let title = 'My dynamic title works!';
    this.myInjector = ReflectiveInjector.resolveAndCreate([{ provide: TITLE, useValue: title }], injector);
  }
}


@NgModule({
  providers: [
    { provide: TITLE, useValue: '' }
  ]
})
export class AppModule { }
like image 117
Pierre Chavaroche Avatar answered Oct 19 '22 10:10

Pierre Chavaroche


An example solution is shown in the ngComponentOutlet documentation, specifically the second example with the @Injectable, as titusfx also mentioned.

Here is what it would look like with your use case:

@Injectable()
class Info {
  title = 'a little hacky';
}

@Component({
  selector: 'app-item',
  template: '<p>{{info.title}}</p>'
})
export class TitleComponent {
  // @Input() title:string;
  constructor(public info: Info){ }
}

@Component({
  selector: 'app-foo',
  template: '<ng-container *ngComponentOutlet="outlet; injector: myInjector"></ng-container>'
})
export class FooComponent {
  outlet = TitleComponent;
  myInjector: Injector;
  constructor(injector: Injector){
    this.myInjector = ReflectiveInjector.resolveAndCreate([Info], injector);
  }
}
like image 33
Renaud Avatar answered Oct 19 '22 10:10

Renaud


Consider using ng-dynamic-component library to work with dynamic components.

like image 4
Андрей Воробьев Avatar answered Oct 19 '22 09:10

Андрей Воробьев