自定义角度指令不适用于插值

时间:2019-05-14 15:10:14

标签: angular

我有一个自定义Angular指令,需要几个输入。其目的是突出显示与指令matchTerm相加的元素的匹配部分。它应该与预输入结果列表一起使用,以便在用户键入返回的结果时突出显示匹配的字符串。

这是整个指令:

import { Directive, Input, ElementRef, OnChanges, SimpleChanges } from '@angular/core';
import { highlightStringMatches } from './typeahead.util';

@Directive({
    selector: '[hsaTypeaheadResult]',
})
export class TypeaheadResultDirective implements OnChanges {
    @Input() matchTerm: string = '';
    @Input() highlightMatches: boolean = true;
    @Input() caseInsensitiveMatch: boolean = true;

    constructor(private _element: ElementRef) {
        console.log({ element: this._element });
    }

    ngOnChanges(changes: SimpleChanges) {
        console.log({ changes });
        if (changes.matchTerm && this.highlightMatches) {
            this.markStringMatches(this._element);
        }
    }

    public markStringMatches(ref: ElementRef) {
        const itemString = ref.nativeElement.textContent.trim();

        console.log({
            itemString,
            matchTerm: this.matchTerm,
            highlightMatches: this.highlightMatches,
            caseInsensitiveMatch: this.caseInsensitiveMatch,
        });

        ref.nativeElement.innerHTML =
            this.highlightMatches && this.matchTerm
                ? highlightStringMatches(itemString, this.matchTerm, this.caseInsensitiveMatch)
                : itemString;
    }
}

如果执行以下操作,该指令将起作用:

<ul>
    <li hsaTypeaheadResult matchTerm="res">Result 1</li>
    <li hsaTypeaheadResult matchTerm="res">Result 2</li>
    <li hsaTypeaheadResult matchTerm="res">Result 3</li>
</ul>

每个li的“ Res”以粗体显示。但是,如果我执行以下任一操作,将无法正常工作:

<ul>
    <li hsaTypeaheadResult matchTerm="res" *ngFor="let result of resultsArr">{{ result }}</li>
</ul>
<ul>
    <li hsaTypeaheadResult matchTerm="res">{{ results[0] }}</li>
    <li hsaTypeaheadResult matchTerm="res">{{ results[1] }}</li>
    <li hsaTypeaheadResult matchTerm="res">{{ results[2] }}</li>
</ul>

每次在使用指令的元素的大括号中插入变量时,变量的值都不会显示在屏幕上:

output results

即使在*ngFor元素上也有结构性li指令的情况下,我尝试将ngFor放在ng-template标记上,但是仍然没用。

您可以看到一个full example on Stackblitz here。我不确定为什么它不适用于插值。在您可以在Stackblitz项目上看到的测试中,一旦发现循环在我的应用程序中无法使用插值,并且仍然可以通过测试,就使用了ngFor循环。

我已经在一个全新的Angular CLI项目以及一个Stackblitz中进行了尝试,并且这些项目都没有其他对它产生负面影响的依赖项。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:0)

考虑了一段时间后,我意识到使用内插时,指令的构造函数中的ElementRef.nativeElement.textContent为空。因此,我意识到这一定意味着我在指令中运行该函数的时间过早。为了进行测试,我使用了setTimeout并等待了2秒钟,然后运行该函数以突出显示匹配项。当我这样做时,该指令按预期工作。

此后,仅需找到在视图准备好后运行的生命周期方法即可,AfterViewInit可以完美地工作。指令代码如下:

import { Directive, Input, ElementRef, OnChanges, SimpleChanges, AfterViewInit } from '@angular/core';
import { highlightStringMatches } from './typeahead.util';

@Directive({
    selector: '[hsaTypeaheadResult]',
})
export class TypeaheadResultDirective implements OnChanges, AfterViewInit {
    @Input() matchTerm: string = '';
    @Input() highlightMatches: boolean = true;
    @Input() caseInsensitiveMatch: boolean = true;

    constructor(private _element: ElementRef) {}

    ngOnChanges(changes: SimpleChanges) {
        if (changes.matchTerm && this.highlightMatches && this._element.nativeElement.textContent) {
            this.markStringMatches(this._element);
        }
    }

    ngAfterViewInit() {
        if (this.matchTerm && this.highlightMatches && this._element.nativeElement.textContent) {
            this.markStringMatches(this._element);
        }
    }

    public markStringMatches(ref: ElementRef) {
        const itemString = ref.nativeElement.textContent.trim();

        ref.nativeElement.innerHTML =
            this.highlightMatches && this.matchTerm
                ? highlightStringMatches(itemString, this.matchTerm, this.caseInsensitiveMatch)
                : itemString;
    }
}