angular2別のファイルからng-templateを使用する方法? ng-templateを使用するのと同じHTML内に配置すると機能しますが、ng-templateを別のファイルに移動すると機能しません。 ng-templateを独自のファイルに移動して別のhtmlファイルで使用する方法はありますか?
info-message.html
<ng-template #messageTemplate>
Hi
</ng-template>
<ng-container *ngTemplateOutlet="messageTemplate;"></ng-container>
ng-templateと使用法が同じファイルにあるため、上記は正常に動作しています
message-template.html
<ng-template #messageTemplate>
Hi
</ng-template>
info-message.html
<ng-container *ngTemplateOutlet="messageTemplate;"></ng-container>
これは機能していません。別のhtml内の別のファイルにある"messageTemplate"を使用する方法はありますか(例:info-message.html)
前もって感謝します。
これ見たことある? https://github.com/angular/angular/issues/275 dawidgarusが提供する例があります
テンプレートを別のファイルで再利用する場合は、テンプレートの内容を別のコンポーネントに変換する必要があります。そうすれば、そのコンポーネントをどこでも再利用できます。
別のファイルをロードする場合は、(<ng-template>
の代わりに)別のファイルでコンポーネントを定義できます。次に、<ng-container>
を使用して、コンポーネント全体を*ngComponentOutlet
に挿入します。
あなたはここで例を使って完全なsulotionを見つけることができます: https://stackoverflow.com/a/59180628/265868
説明と移植性の理由から@ peter554による回答を拡張します。これにより、コンポーネント間でテンプレートを使用できます。
使用するには:
'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);
}
}
彼、@ peter554は、 Angular CDKポータルパッケージ に関してホイールの再発明について言及しています。ただし、私は彼/この実装が、アプリケーションフローでの使用方法と、コンポーネントからポータルアウトレットを含む別のコンポーネントへのテンプレートの移植が容易である(コンポーネントからコンポーネント->ポータルテンプレートへのアクセスを許可する)ことに、より意味があると思います。たとえば、 Angular Material MatBottomSheet (idcBottomSheet))を実装するコンポーネントテンプレート内。
「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>
'output'要素(MatBottomSheetコンポーネントテンプレート内):
<ng-container [idcPortalOutlet]="'appIdcBottomSheet'"></ng-container>
次のようなものを使用できます(テンプレートは別のコンポーネントから使用されます)。
@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;
}
}
この動作は「ポータル」を介して実現できます。これは、Angularアプリケーションで便利でかなり一般的なパターンです。たとえば、トップレベルのアプリの近くにグローバルサイドバーアウトレットがあり、子コンポーネントがローカル<ng-template/>
を指定する場合があります。テンプレート全体の一部として、この場所にレンダリングされます。
<ng-template/>
は、目的のアウトレットが定義されているファイルの外部で定義される場合がありますが、<ng-template/>
をsomeコンポーネント。これは、<ng-template/>
のラップのみを担当する最小限のコンポーネントにすることができますが、<ng-template/>
が重要な役割を果たすだけの複雑なコンポーネントになることもあります。
このコードは、ポータルの1つの可能な基本的な実装を示しています。
@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;
}
}
3つの部分を使用して動作します。
<ng-template/>
に基づいており、コンテンツがレンダリングされるアウトレットの名前を入力として受け取ります。<ng-container/>
、およびアウトレットを定義します。これは非常に単純なものでは多くの作業のように思えるかもしれませんが、この配管が整えば、簡単に(再)使用できます。
<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>
一般に、十分にテストされ、文書化された安定した実装がすでに利用可能である場合でも、ホイールを再発明することは良い考えではありません。 Angular CDK は このような実装 を提供します。実際には、これを使用するのではなく、それを使用することをお勧めします。