[解決済み】ユーザークリックで選択されたコンポーネントを含むダイナミックタブ
質問
コンポーネントが自分自身で(タイトルを付けて)登録できるようなタブシステムをセットアップしようとしています。最初のタブは受信箱のようなもので、ユーザーが選択できる多くのアクション/リンク項目があり、これらのクリックのそれぞれは、クリック時に新しいコンポーネントをインスタンス化できるようにする必要があります。アクション/リンクはJSONから入ってきます。
インスタンス化されたコンポーネントは、自分自身を新しいタブとして登録します。
これが「ベスト」なアプローチなのかどうか、よくわからないのですが?今のところ、私が見た唯一のガイドは、静的なタブのためのもので、これは役に立ちません。
今のところ、main でブートストラップされる tabs サービスだけを、アプリ全体で永続化させています。それは次のようなものです。
export interface ITab { title: string; }
@Injectable()
export class TabsService {
private tabs = new Set<ITab>();
addTab(title: string): ITab {
let tab: ITab = { title };
this.tabs.add(tab);
return tab;
}
removeTab(tab: ITab) {
this.tabs.delete(tab);
}
}
質問です。
-
受信トレイに新しい(異なる)タブを作成する動的なリストを持つにはどうすればよいですか?私は
DynamicComponentBuilder
が使われるのでしょうか? -
受信トレイから作成したコンポーネント(クリック時)をタブとして登録し、かつ表示するにはどうしたらよいでしょうか。推測ですが
ng-content
しかし、その使用方法についての情報はあまり見当たりません。
EDITです。 明確化の試み。
受信箱はメールの受信箱と同じだと考えてください。アイテムはJSONとして取得され、複数のアイテムを表示します。アイテムの1つがクリックされると、そのアイテムのアクション「タイプ」で新しいタブが作成されます。そして、このタイプはコンポーネントとなります。
EDIT 2: 画像 .
解決方法は?
更新
アップデート
ngComponentOutlet
が 4.0.0-beta.3 に追加されました。
アップデート
があります。
NgComponentOutlet
同様のことを行う進行中の作品
https://github.com/angular/angular/pull/11235
RC.7
// Helper component to add dynamic components
@Component({
selector: 'dcl-wrapper',
template: `<div #target></div>`
})
export class DclWrapper {
@ViewChild('target', {read: ViewContainerRef}) target: ViewContainerRef;
@Input() type: Type<Component>;
cmpRef: ComponentRef<Component>;
private isViewInitialized:boolean = false;
constructor(private componentFactoryResolver: ComponentFactoryResolver, private compiler: Compiler) {}
updateComponent() {
if(!this.isViewInitialized) {
return;
}
if(this.cmpRef) {
// when the `type` input changes we destroy a previously
// created component before creating the new one
this.cmpRef.destroy();
}
let factory = this.componentFactoryResolver.resolveComponentFactory(this.type);
this.cmpRef = this.target.createComponent(factory)
// to access the created instance use
// this.compRef.instance.someProperty = 'someValue';
// this.compRef.instance.someOutput.subscribe(val => doSomething());
}
ngOnChanges() {
this.updateComponent();
}
ngAfterViewInit() {
this.isViewInitialized = true;
this.updateComponent();
}
ngOnDestroy() {
if(this.cmpRef) {
this.cmpRef.destroy();
}
}
}
使用例
// Use dcl-wrapper component
@Component({
selector: 'my-tabs',
template: `
<h2>Tabs</h2>
<div *ngFor="let tab of tabs">
<dcl-wrapper [type]="tab"></dcl-wrapper>
</div>
`
})
export class Tabs {
@Input() tabs;
}
@Component({
selector: 'my-app',
template: `
<h2>Hello {{name}}</h2>
<my-tabs [tabs]="types"></my-tabs>
`
})
export class App {
// The list of components to create tabs from
types = [C3, C1, C2, C3, C3, C1, C1];
}
@NgModule({
imports: [ BrowserModule ],
declarations: [ App, DclWrapper, Tabs, C1, C2, C3],
entryComponents: [C1, C2, C3],
bootstrap: [ App ]
})
export class AppModule {}
こちらもご覧ください ANGUALL.IO DYNAMIC COMPONENT LOADER(ダイナミックコンポーネントローダー
旧バージョン xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx。
これはAngular2 RC.5で再び変更されました。
以下の例を更新しますが、休暇前の最終日です。
この プランカーの例 RC.5 でコンポーネントを動的に作成する方法を説明します。
更新 - 使用 ViewContainerRef .createComponent()
なぜなら
DynamicComponentLoader
は非推奨であるため、再度アプローチを更新する必要があります。
@Component({
selector: 'dcl-wrapper',
template: `<div #target></div>`
})
export class DclWrapper {
@ViewChild('target', {read: ViewContainerRef}) target;
@Input() type;
cmpRef:ComponentRef;
private isViewInitialized:boolean = false;
constructor(private resolver: ComponentResolver) {}
updateComponent() {
if(!this.isViewInitialized) {
return;
}
if(this.cmpRef) {
this.cmpRef.destroy();
}
this.resolver.resolveComponent(this.type).then((factory:ComponentFactory<any>) => {
this.cmpRef = this.target.createComponent(factory)
// to access the created instance use
// this.compRef.instance.someProperty = 'someValue';
// this.compRef.instance.someOutput.subscribe(val => doSomething());
});
}
ngOnChanges() {
this.updateComponent();
}
ngAfterViewInit() {
this.isViewInitialized = true;
this.updateComponent();
}
ngOnDestroy() {
if(this.cmpRef) {
this.cmpRef.destroy();
}
}
}
更新 - loadNextToLocationを使用します。
export class DclWrapper {
@ViewChild('target', {read: ViewContainerRef}) target;
@Input() type;
cmpRef:ComponentRef;
private isViewInitialized:boolean = false;
constructor(private dcl:DynamicComponentLoader) {}
updateComponent() {
// should be executed every time `type` changes but not before `ngAfterViewInit()` was called
// to have `target` initialized
if(!this.isViewInitialized) {
return;
}
if(this.cmpRef) {
this.cmpRef.destroy();
}
this.dcl.loadNextToLocation(this.type, this.target).then((cmpRef) => {
this.cmpRef = cmpRef;
});
}
ngOnChanges() {
this.updateComponent();
}
ngAfterViewInit() {
this.isViewInitialized = true;
this.updateComponent();
}
ngOnDestroy() {
if(this.cmpRef) {
this.cmpRef.destroy();
}
}
}
オリジナル
あなたの質問から、あなたの要件が何であるかが完全にわかりませんが、私はこれがあなたが望むものを行うべきだと思います。
は
Tabs
コンポーネントは、渡された型の配列を取得し、配列内の各項目について "タブ" を作成します。
@Component({
selector: 'dcl-wrapper',
template: `<div #target></div>`
})
export class DclWrapper {
constructor(private elRef:ElementRef, private dcl:DynamicComponentLoader) {}
@Input() type;
ngOnChanges() {
if(this.cmpRef) {
this.cmpRef.dispose();
}
this.dcl.loadIntoLocation(this.type, this.elRef, 'target').then((cmpRef) => {
this.cmpRef = cmpRef;
});
}
}
@Component({
selector: 'c1',
template: `<h2>c1</h2>`
})
export class C1 {
}
@Component({
selector: 'c2',
template: `<h2>c2</h2>`
})
export class C2 {
}
@Component({
selector: 'c3',
template: `<h2>c3</h2>`
})
export class C3 {
}
@Component({
selector: 'my-tabs',
directives: [DclWrapper],
template: `
<h2>Tabs</h2>
<div *ngFor="let tab of tabs">
<dcl-wrapper [type]="tab"></dcl-wrapper>
</div>
`
})
export class Tabs {
@Input() tabs;
}
@Component({
selector: 'my-app',
directives: [Tabs]
template: `
<h2>Hello {{name}}</h2>
<my-tabs [tabs]="types"></my-tabs>
`
})
export class App {
types = [C3, C1, C2, C3, C3, C1, C1];
}
プランカーエクスペリエンス beta.15 (お使いのPlunkerに合わせたものではありません)
のように、動的に作成されるコンポーネントに渡すことができるデータを一緒に渡す方法もあります(
someData
のように渡す必要があります。
type
)
this.dcl.loadIntoLocation(this.type, this.elRef, 'target').then((cmpRef) => {
cmpRef.instance.someProperty = someData;
this.cmpRef = cmpRef;
});
また、共有サービスでの依存性注入の使用も一部サポートされています。
詳しくは https://angular.io/docs/ts/latest/cookbook/dynamic-component-loader.html
関連
-
[解決済み】Angular2エラー。exportAs "が "ngForm "に設定されたディレクティブは存在しません。
-
[解決済み】ngサーブが機能しない
-
[解決済み] Angular 5:"ControlContainerのプロバイダがありません"
-
[解決済み] ng serve または firebase serve を終了させる方法
-
[解決済み] Electron - ローカルリソースのロードが許可されていません
-
[解決済み] Angular 8 NgForはArray errorやAcces Control Allow originなどのIterableへのバインディングのみをサポートしています。
-
[解決済み] パーサエラーです。式が期待される場所で補間({{}})を得た
-
[解決済み] Angular2の$document.ready()に相当します。
-
[解決済み] Angular2 Selectorが、ネストしたComponentのどの要素にもマッチしない。
-
[解決済み] AngularでKendo Tabstripのタブを閉じるボタンを実装する方法
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】 node_modules/rxjs/internal/types.d.ts(81,44): エラー TS1005: ';' Angular 6のインストール後に予想されたエラー
-
[解決済み】アンギュラーコンポーネントにサービスを注入しようとするとエラー "EXCEPTION: Can't resolve all parameters for component"、なぜ?
-
[解決済み] チョキダーからのエラー(C:┣ᴗ┣)。Error: EBUSY: resource busy or locked, lstat 'C:\DumpStack.log.tmp.
-
[解決済み] typescriptを使用して、同じhtml DOM要素で「シングルクリック」と「ダブルクリック」を処理する方法:Angular 2または4?
-
[解決済み] ag-gridで「表示する行がありません」テキストをプログラムで変更するにはどうすればよいですか?
-
[解決済み] ローカルのワークスペース・ファイル('angular.json')が見つかりませんでした。しかし、同じコードが別のコンピュータで動作します
-
[解決済み] ローカルホストが私のアンギュラーアプリに対して無効な応答を送信しました。
-
[解決済み] Angular 2.0で動的コンポーネントをコンパイルするために動的テンプレートを使用/作成するにはどうすればよいですか?
-
[解決済み] angular ngModuleのentryComponentsとは何ですか?
-
[解決済み] Angular 2の$compileに相当するもの