Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

angular - How to detect async change to ng-content

I made a component which uses the marked package to render markdown content, the thing is it doesn't re-render itself when an async event changes its ng-content element.

Here's the code

import {Component, ElementRef, AfterContentInit} from 'angular2/core';
declare var marked: any;

@Component({
    selector: 'markdown',
    template:
    '<div style="display:none;">' +
    '    <ng-content></ng-content>' +
    '</div>' +
    '<div class="markdown" [innerHTML]="output"></div>'
})
export class MarkdownComponent implements AfterContentInit {
    output: string;

    constructor(
        private element: ElementRef) {
    }

    ngAfterContentInit() {
        const c = this.element.nativeElement.childNodes;
        this.output = marked(c[0].textContent);
    }
}

Here's the HTML snippet:

<markdown>{{info}}</markdown>

And here's the async update:

updateInfo(text: string) {
    this.svc.update(this.info, text).subscribe(
        data => this.info = data.newText);
}

The problem is, when the this.svc.update event fires, the info variable changes value, but the markdown component doesn't get re-rendered.

Thanks!

RESOLUTION

Following the accepted answer's advice (thanks Gunter), here's the new component, it's leaner and simpler:

import {Component} from 'angular2/core';
declare var marked: any;

@Component({
    selector: 'markdown',
    template: '<div class="markdown" [innerHTML]="process(md)"></div>',
    inputs: ['md']
})
export class MarkdownComponent {
    md: string;

    process(s: string) {
        if (!s) return '';
        return marked(s);
    }
}

And here's the new HTML:

<markdown [md]="info"></markdown>

Works perfectly! :)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Even if the Günter's answer is great, I wasn't able to resist to create a little plunkr describing how to use Marked into a component: https://plnkr.co/edit/0oSeaIyMWoq5fAKKlJLA?p=preview.

Here are the details:

  • Marked configuration the HTML file

    <script>
      System.config({
        transpiler: 'typescript', 
        typescriptOptions: { emitDecoratorMetadata: true }, 
        packages: {
          'src': {defaultExtension: 'ts'}
        },
        map: {
          marked: 'https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.5/marked.js'
        }
      });
      System.import('src/boot')
        .then(null, console.error.bind(console));
    </script>
    
  • The component that uses Marked

    import { Component, Input } from 'angular2/core';
    import marked from 'marked';
    
    @Component({
      selector: 'markdown', 
      template: `
        <div [innerHTML]="convertedData"></div>
      `
    })
    export class MarkdownComponent {
      @Input('data')
      data:string;
    
      ngOnChanges() { 
        this.convertedData = marked(this.data);
      }
    }
    
  • The component that uses the previous Markdown component

    import { Component } from 'angular2/core';
    import { MarkdownComponent } from './markdown';
    
    @Component({
      selector: 'my-app', 
      template: `
        <div>
          <markdown [data]="markdown"></markdown>
        </div>
      `,
      directives: [ MarkdownComponent ]
    })
    export class AppComponent {
      constructor() {
        this.markdown = 'Hello';
    
        setTimeout(() => {
          this.markdown = `
    # Title
    
    Some __test__
    `;
        }, 1000);
      }
    }
    

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...