Zoeken op website

javascript - Angular 2/4/5/6 - Het innerHTML van een aangepast component transformeren aan de kant van de componentklasse


Ik wil de volgende basiselement maken: card.component om alles wat de gebruiker definieert in de innerHTML ervan over te nemen in zijn componentklasse, zodat het het kan transformeren en weergeven in zijn template.

Zo gaat de gebruiker deze component gebruiken:

<app-card>hello world, this is a sample text</app-card>

Hier heb je een basisproject op StackBlitz.com dat je kunt forken om het te laten werken.

https://stackblitz.com/edit/angular-cmdpgh?file=src/app/components/card/card.component.ts

Hier heb je een voorbeeld van de code:

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>

waar op de locatie van: {{content}} het component het resultaat moet weergeven van: complexStrTransform(...).

Ik heb op sommige plaatsen gezien dat het mogelijk is om te gebruiken: <ng-content></ng-content> om in de template van de component aan te geven waar je de innerHTML wilt plaatsen, maar ik denk dat dat hier niet de beste optie is omdat ik die innerHTML moet transformeren met zeer complexe wijzigingen die alleen in de componentklasse kunnen worden uitgevoerd.

Enige suggesties?

Dank u voor uw aandacht.

Antwoord #1

Ik weet niet precies of dit is wat je nodig hebt, maar ik heb geprobeerd een kleine oplossing te schrijven om een algemene componentinteractie met jouw voorbeeld te doen,

  1. In je kaartcomponent,

Voeg een invoer toe die we later vanuit de hoofdapp-component kunnen gebruiken,

 @Input('complexInput') complexInputContent: string;

Initialiseer dan de innerHTML naar de toegevoegde globale invoer,

 let innerHTML = this.complexInputContent;
  1. Werk uw app-component bij zoals hieronder,

<app-card  [complexInput]="contentDiv.innerText">


<div #contentDiv contenteditable="true" >

hello world, this is a sample text

</div>


</app-card>

Dit is de werkende oplossing (Preview): https://angular-k5wjbp.stackblitz.io/

Bewerkbare code: https://stackblitz.com/edit/angular-k5wjbp

Referenties: https://angular.io/guide/component-interaction

Antwoord #2

Het vorige antwoord van Dilusha doet een deel van het werk. Het andere deel is om je transform-functie als een pijp te implementeren en een beetje DOM-trucs te gebruiken. Hier is het op Stackblitz.

Werk eerst je transform-functie opnieuw uit als een Pipe (en refactor de component):

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;
  }
}

Voeg vervolgens de ng-content-tag toe aan je component zodat gebruikers eenvoudig inhoud kunnen invoegen. Verberg dat tegelijkertijd met stijl met display: none en wijs het een template-referentievariabele toe zodat je component er toegang toe kan krijgen en het kan weergeven met behulp van de pipe:

<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>

Nu werkt uw component zoals gewenst:

<app-card>hello world, this is a sample text</app-card>

Dit is duidelijk een beetje een trucje, aangezien de originele gebruikersinhoud nog steeds in de DOM bestaat. Maar het klaart de klus vrij efficiënt.