web-dev-qa-db-fra.com

angular2 ng-template dans un fichier séparé

angular2 comment utiliser ng-template depuis un autre fichier? Lorsque je place le ng-template dans le même HTML que celui où je l'utilise, cela fonctionne, mais lorsque je déplace ng-template dans un fichier séparé, cela ne fonctionnera pas. Existe-t-il un moyen de déplacer ng-template dans son propre fichier et de l'utiliser dans différents fichiers html?

info-message.html

<ng-template #messageTemplate>
    Hi
</ng-template>

<ng-container *ngTemplateOutlet="messageTemplate;"></ng-container>

ci-dessus fonctionne bien parce que le modèle ng et l'utilisation sont dans le même fichier

message-template.html

<ng-template #messageTemplate>
    Hi
</ng-template>

info-message.html

<ng-container *ngTemplateOutlet="messageTemplate;"></ng-container>

Cela ne fonctionne pas. Existe-t-il un moyen d'utiliser "messageTemplate" qui se trouve dans un fichier séparé à l'intérieur d'un autre html (Ex: info-message.html)

Merci d'avance.

12
Pratap A.K

Avez-vous vu cette? https://github.com/angular/angular/issues/275 Il y a un exemple fourni par dawidgarus

La suggestion est que si vous souhaitez réutiliser votre modèle dans différents fichiers, vous devez convertir ce qui se trouve à l'intérieur du modèle en un composant distinct, puis vous pouvez réutiliser ce composant où vous le souhaitez.

2
KlavierCat

Si vous chargez un fichier séparé, vous pouvez définir un composant dans le fichier séparé (au lieu d'un <ng-template>). Et puis injectez le composant entier dans le <ng-container> en utilisant le *ngComponentOutlet.

Vous pouvez trouver le sulotion complet avec exemple ici: https://stackoverflow.com/a/59180628/265868

0
Gil Epshtain

Extension de la réponse de @ peter554 pour des raisons d'explication et de portabilité. Cela vous permettra d'utiliser un modèle entre les composants.

Pour utiliser:

'app.module.ts'
import {NgModule} from '@angular/core';
import {
    IdcPortalDirective, IdcTemplatePortalDirective,
    PortalService
} from './idc-template-portal/idc-template-portal.component';

@NgModule({
    declarations: [
        IdcPortalDirective,
        IdcTemplatePortalDirective
    ],
    imports: [],
    exports: [],
    providers: [
        PortalService
    ],
    bootstrap: [AppComponent]
})
export class AppModule {}
'./idc-template-portal/idc-template-portal.component.ts'
import {
    AfterViewInit,
    Directive,
    Injectable,
    Input,
    OnInit, Output,
    TemplateRef,
    ViewContainerRef
} from '@angular/core';
/*** Input Template ***/
/*** <ng-template idcPortal [outlet]="'outletname'">Template Contents</ng-template> ***/
@Directive({
    selector: '[idcPortal]'
})
export class IdcPortalDirective implements OnInit {
    @Input() outlet: string;
    @Output() inlet: string = this.outlet;

    constructor(private portalService: PortalService, public templateRef: TemplateRef<any>) {}

    ngOnInit():void {
        this.portalService.registerInlet(this);
    }

}
/*** Output Container ***/
/*** <ng-container [idcPortalOutlet]="'outletname'"></ng-container> ***/
@Directive({
    selector: '[idcPortalOutlet]'
})
export class IdcTemplatePortalDirective implements OnInit, AfterViewInit {
    @Input() appPortalOutlet: string;
    @Output() outlet: string = this.appPortalOutlet;

    constructor(private portalService: PortalService, public viewContainerRef: ViewContainerRef) {}

    ngOnInit():void {
        this.portalService.registerOutlet(this);
    }

    ngAfterViewInit() {
        this.portalService.initializePortal(this.appPortalOutlet);
    }

}
@Injectable({
    providedIn: 'root'
})
export class PortalService {
    outlets = new Map<string, IdcTemplatePortalDirective>();
    inlets = new Map<string, IdcPortalDirective>();

    registerOutlet(outlet: IdcTemplatePortalDirective) {
        this.outlets[outlet.outlet] = outlet;
    }

    registerInlet(inlet: IdcPortalDirective) {
        this.inlets[inlet.inlet] = inlet;
    }

    initializePortal(portal:string) {
        const inlet: IdcPortalDirective = this.inlets[portal];
        const outlet: IdcTemplatePortalDirective = this.outlets[portal];
        outlet.viewContainerRef.clear();
        outlet.viewContainerRef.createEmbeddedView(inlet.templateRef);
    }
}

Il, @ peter554, mentionne réinventer la roue en ce qui concerne paquet de portails Angular CDK . Cependant, je trouve que cette/cette implémentation a plus de sens dans la façon dont elle est utilisée dans le flux d'application et la facilité avec laquelle un modèle peut être porté d'un composant à un autre composant qui contient la sortie du portail (permettant au composant de composant-> modèle de portail Par exemple, dans un modèle de composant implémentant Angular Material MatBottomSheet (idcBottomSheet)).

L'élément 'input':

<!--
/*
  For example, perhaps you have a mobile view
  where a template is hidden (via css) and ported
  over to a MatBottomSheet component template to be 
  popped up when requested (by button click). 
*/
-->
<button #bottomsheetButton (click)="openBottomSheet(Notes)" mat-button>
    <mat-icon>notes</mat-icon>
</button>
<!--/* hidden in mobile view mode. */-->
<ng-content *ngTemplateOutlet="Notes"></ng-content>
<ng-template #Notes idcPortal [outlet]="'idcBottomSheet'"><!--/* template to port */-->
    <form>
        <mat-form-field class="w-100 h-100">
            <mat-label>A place for your thoughts:</mat-label>
            <textarea matInput
                      cdkTextareaAutosize
                      #autosize="cdkTextareaAutosize"
                      cdkAutosizeMinRows="10"
                      cdkAutosizeMaxRows="10"
                      placeholder="Angular. It makes me feel...">
            </textarea>
        </mat-form-field>
    </form>
</ng-template>

L'élément 'output' (à l'intérieur de votre modèle de composant MatBottomSheet):

<ng-container [idcPortalOutlet]="'appIdcBottomSheet'"></ng-container>
0
Eric Shoberg

Vous pouvez utiliser quelque chose comme ça (le modèle est utilisé à partir d'un autre composant):

@Component(
    template: '<ng-container *ngTemplateOutlet="infoMessage.template;"></ng-container>'
)
export class MessageTemplate {
    infoMessage: InfoMessage;    
}

@Component(
    ....
)
export class InfoMessage{    
    @ContentChild('columnTemplate') template: TemplateRef<any>;

    constructor(private messageTemplate: MessageTemplate) {
        messageTemplate.infoMessage = this;
    }
}
0
bluray

Ce comportement peut être obtenu via un "portail". Il s'agit d'un modèle utile et assez courant dans les applications Angular. Par exemple, vous pouvez avoir une sortie de barre latérale globale vivant près du niveau d'application supérieur, puis les composants enfants peuvent spécifier un <ng-template/> Local , dans le cadre de leur modèle global, à rendre à cet emplacement.

Notez que bien que <ng-template/> Puisse être défini en dehors du fichier où la sortie souhaitée est définie, il est toujours nécessaire de placer le <ng-template/> À l'intérieur du modèle de certains composants. Cela peut être un composant minimaliste qui n'est responsable que de l'encapsulation du <ng-template/>, Mais il pourrait également être un composant compliqué où le <ng-template/> D'intérêt ne joue qu'un rôle mineur.

Ce code illustre une implémentation de base possible d'un portail.

@Directive({
  selector: '[appPortal]'
})
export class PortalDirective implements AfterViewInit {
  @Input() outlet: string;

  constructor(private portalService: PortalService, private templateRef: TemplateRef<any>) {}

  ngAfterViewInit(): void {
    const outlet: PortalOutletDirective = this.portalService.outlets[this.outlet];
    outlet.viewContainerRef.clear();
    outlet.viewContainerRef.createEmbeddedView(this.templateRef);
  }
}

@Directive({
  selector: '[appPortalOutlet]'
})
export class PortalOutletDirective implements OnInit {
  @Input() appPortalOutlet: string;

  constructor(private portalService: PortalService, public viewContainerRef: ViewContainerRef) {}

  ngOnInit(): void {
    this.portalService.registerOutlet(this);
  }
}

@Injectable({
  providedIn: 'root'
})
export class PortalService {
  outlets = new Map<string, PortalOutletDirective>();

  registerOutlet(outlet: PortalOutletDirective) {
    this.outlets[outlet.appPortalOutlet] = outlet;
  }
}

Il fonctionne en trois parties:

  • Une directive "portail". Celui-ci vit sur le <ng-template/> Souhaité et prend en entrée le nom de la prise sur laquelle le contenu doit être rendu.
  • Une directive "portail". Cela vit sur une prise, par exemple un <ng-container/>, et définit la sortie.
  • Un service "portail". Il est fourni au niveau racine et stocke les références aux prises du portail afin qu'elles soient accessibles par les portails.

Cela peut sembler beaucoup de travail pour quelque chose d'assez simple, mais une fois cette plomberie en place, elle est facile à (ré) utiliser.

<div class="container">
  <div class="row">
    <div class="col-6">
      <app-foo></app-foo>
    </div>
    <div class="col-6">
      <ng-container [appPortalOutlet]="'RightPanel'"></ng-container>
    </div>
  </div>
</div>

// foo.component.html
<h1>Foo</h1>
<ng-template appPortal [outlet]="'RightPanel'">
 <h1>RIGHT</h1>
</ng-template>

En général, ce n'est pas une bonne idée de réinventer la roue alors qu'il existe déjà des implémentations bien testées, documentées et stables. Le Angular CDK fournit ne telle implémentation et je vous conseille de l'utiliser plutôt que le vôtre dans la pratique.

0
Peter554