11 votes

Est-il possible d'afficher une seule instance d'un composant angulaire à plusieurs endroits ?

Disons que j'ai un code html comme celui-ci :

      <div *ngIf="(isVisible | async)">
        <app-mycomponent></app-mycomponent>
      </div>
      <div *ngIf="!(isVisible | async)">
        <app-mycomponent></app-mycomponent>
      </div>

avec un bouton qui bascule sur isVisible. Cela crée une nouvelle instance de composant chaque fois que je fais basculer la visibilité.

Ma question est donc la suivante : puis-je modifier l'implémentation pour que la même instance de AppMyComponent soit utilisée lorsque la visibilité est basculée ? Par exemple, en ayant un composant wrapper qui ajoute le composant AppMyComponent dynamiquement ou quelque chose comme ça.

EDIT : Mon cas réel est assez complexe et même si cet exemple n'a pas de sens, je suis très intéressé de savoir si cela peut être fait.

EDIT2 : Voici stackbliz cela résout mon problème.

2 votes

Si je comprends bien, vous voulez faire de votre AppMyComponent a singleton ? Tout d'abord, je ne pense pas qu'il y ait un moyen de faire en sorte que les component class singleton et deuxièmement, pourquoi avez-vous besoin de cela ? En général, nous faisons une service singleton

1 votes

Peut-être qu'un exemple plus concret de ce que vous voulez faire serait utile, car dans cet exemple de code, vous affichez la même chose dans chaque condition, donc je m'interroge sur la nécessité de la condition.

0 votes

Si vous souhaitez modifier quelque chose dans l'app-mycomponent lorsque quelque chose a changé dans le composant parent, vous pouvez le faire en utilisant @Input avec des setters - comme indiqué ici -. angular.io/guide/

9voto

David Points 11437

Cette réponse est basée sur le exemple de stackblitz prévue dans le présent réponse à une question similaire que j'ai posée.

Étape 1 : Créez une directive que vous utiliserez partout où vous voulez avoir votre composant réutilisable.

@Directive({
  selector: '[reusable-outlet]',
})
export class ReusableDirective implements OnInit {

  constructor(
    private viewContainerRef: ViewContainerRef,
    private reusableService: ReusableService
  ) { }

  public ngOnInit(): void {
    this.reusableService.attach(this.viewContainerRef);
  }

}

Étape 2 Créez le service qui sera en charge de :

  • créer dynamiquement le composant qui sera réutilisé
  • attacher et détacher ce composant au conteneur de vue de la directive créée à l'étape ~1.

Remarque : Savoir quand détacher le composant est basé sur les événements du routeur, mais il devrait être possible de le baser sur des messages à la place, si vous avez besoin de changer l'emplacement de votre composant sans avoir à modifier la navigation.

@Injectable()
export class ReusableService {

  private componentRef: ComponentRef<ReusableComponent>;

  private currentViewContainerRef: ViewContainerRef;

  constructor(
    private componentFactoryResolver: ComponentFactoryResolver,
    private injector: Injector,
    private router: Router
  ) {
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(ReusableComponent);
    this.componentRef = componentFactory.create(injector);

    this.router.events.subscribe(event => {
      if (event instanceof NavigationStart && this.currentViewContainerRef) {
        this.detach(this.currentViewContainerRef);
      }
    });
  }

  public attach(viewContainerRef: ViewContainerRef) {
    this.currentViewContainerRef = viewContainerRef;
    viewContainerRef.insert(this.componentRef.hostView);
  }

  public detach(viewContainerRef: ViewContainerRef) {
    viewContainerRef.detach(viewContainerRef.indexOf(this.componentRef.hostView));
  }

}

0voto

Ahmad mnzr Points 525

1) Insérer la vue dans #dynamicComponentContainer .

2) Nous pouvons garder la trace d'un composant ou de tous les composants dans une variable ou dans un objet et les détruire :-.

3) Ou, détruire le composant précédent lors du chargement d'un nouveau composant dans le DOM en stockant la dernière référence et le nouveau composant. .destroy() avant d'en insérer un nouveau.

.html

 <ng-container #dynamicComponentContainer id="dynamicComponentContainer"></ng-container>

.ts

public loadComponent(cmptName){
     switch (cmptName) {
         case 'abcComponent':
             cmptName = abcComponent;
             break;
         case 'cdeComponent':
             cmptName = cdeComponent;
             break;
        }

    let componentRef = this.componentFactoryResolver.resolveComponentFactory(cmptName).create(this.injector);

     // check for duplicates and update with new one
      //   this.checkForDuplicateCmp(componentRef);

     //   send data to respecting component using `inputdata`       
     componentRef.instance['inputdata'] = initCmpInputdata;

     let indexView = this.dynamicComponentContainer.length;
                            this.dynamicComponentContainer.insert(componentRef.hostView, indexView);

    // keep reference of lastComponent added to DOM
     this.lastComponent = componentRef;

    }      

public remove component(){
    // destroy components as on click
        this.lastComponent.destroy();

      //or
       //for (var j = 1; j < this.dynamicComponentContainer.length; j++) {
      //  this.dynamicComponentContainer.remove(j);  //or pass j 
      //       }
      //    }

abcComponent.ts

@Input() inputdata: any;

Note:- Pour des instances multiples de l'abccomoponent, appelez

loadComponent(abccomoponent )

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X