javascript - Angular 2/4/5/6 - カスタムコンポーネントの innerHTML をコンポーネントクラス側で変換する
私は次の基本コンポーネントを作りたいです: card.component がユーザーがその innerHTML に定義したものをコンポーネントクラスに取り込み、それを変換してテンプレートに表示できるようにするコンポーネントです。
これはユーザーがこのコンポーネントを使用する方法です:
<app-card>hello world, this is a sample text</app-card>
ここに、StackBlitz.com 上でフォークして動作させることができるベースプロジェクトがあります。
https://stackblitz.com/edit/angular-cmdpgh?file=src%2Fapp%2Fcomponents%2Fcard%2Fcard.component.ts
こちらがコードのプレビューです:
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-card',
templateUrl: 'card.component.html',
styleUrls: [ 'card.component.css' ],
})
export class CardComponent implements OnInit {
private content: string;
ngOnInit() {
// please, override this to get the real innerHTML on: 'app.component.html'
let innerHTML = 'testing';
this.content = CardComponent.complexStrTransform(innerHTML);
}
private static complexStrTransform(str: string): string {
// complex transformations here
let result = '';
for (let i = 0; i < str.length; i++) {
let c = str[i];
result += c;
result += c.toUpperCase();
result += '|';
}
result = '!!!' + result + '!!!';
return result;
}
}<mat-card>
<mat-card-content>
{{content}}
</mat-card-content>
<mat-card-actions>
<button mat-button>LIKE</button>
<button mat-button>SHARE</button>
</mat-card-actions>
</mat-card>次の場所で:{{content}}、コンポーネントは次の結果を表示する必要があります:complexStrTransform(...).
私はいくつかの場所で、コンポーネントのテンプレートで innerHTML を置きたい場所を指定するために <ng-content></ng-content> を使用できると見たことがありますが、ここではそれが最適な方法ではないと思います。なぜなら、その innerHTML を非常に複雑な変更で変換する必要があり、それはコンポーネントのクラスでしか行えないからです。
何か提案はありますか?
ご注目いただきありがとうございます。
回答 #1
正確にこれがあなたの必要としているものかはわかりませんが、あなたの例を使って一般的なコンポーネントのやり取りを行うための小さな解決策を書いてみました。
- あなたのカードコンポーネントで、
メインアプリコンポーネントから後で使用できる入力を追加してください。
@Input('complexInput') complexInputContent: string;
次に、追加されたグローバル入力に innerHTML を初期化してください。
let innerHTML = this.complexInputContent;
- アプリコンポーネントを以下のように更新してください,
<app-card [complexInput]="contentDiv.innerText">
<div #contentDiv contenteditable="true" >
hello world, this is a sample text
</div>
</app-card>これは動作する解決策(プレビュー)です: https://angular-k5wjbp.stackblitz.io/
編集可能なコード: https://stackblitz.com/edit/angular-k5wjbp
参考文献: https://angular.io/guide/component-interaction
回答 #2
Dilushaの前回の回答は仕事の一部を済ませています。もう一つの部分は、あなたのtransform関数をパイプとして実装し、少しDOMのトリックを使うことです。こちらがStackblitzでの例です。
まず、あなたの transform 関数を Pipe として作り直し(そしてコンポーネントをリファクタリング)してください:
import { Component, Pipe, PipeTransform } from '@angular/core';
@Component({
selector: 'app-card',
templateUrl: 'card.component.html',
styleUrls: ['card.component.css'],
})
export class CardComponent { }
@Pipe({ name: 'complexStr' })
export class ComplexStrPipe implements PipeTransform {
transform(str: string): string {
// complex transformations here
let result = '';
for (let i = 0; i < str.length; i++) {
let c = str[i];
result += c;
result += c.toUpperCase();
result += '|';
}
result = '!!!' + result + '!!!';
return result;
}
}
次に、ユーザーが簡単にコンテンツを挿入できるように、コンポーネントにng-contentタグを追加します。同時に、display: noneを使用してスタイルでそれを非表示にし、コンポーネントがアクセスしてパイプを使って表示できるようにテンプレート参照変数を割り当てます:
<mat-card>
<mat-card-content>
{{inner.innerText | complexStr}}
</mat-card-content>
<mat-card-actions>
<button mat-button>LIKE</button>
<button mat-button>SHARE</button>
</mat-card-actions>
</mat-card>
<div #inner style="display: none">
<ng-content></ng-content>
</div>
これでコンポーネントは望んだ通りに動作します:
<app-card>hello world, this is a sample text</app-card>
これは明らかに少しごまかしですが、元のユーザーコンテンツは依然としてDOMに存在しています。しかし、作業はかなり効率的に行えます。
