像元素属性

时间:2016-11-02 12:04:25

标签: javascript angular frontend

大家好!

我正在学习AngularJS 2一段时间,现在基于Laravel 5 REST API创建我自己的应用程序。无论如何 - 这不是非常重要的atm。

重要的是我想为整个应用程序提供翻译,我发现了一个很难解决的问题。

所以 - 从一开始......我创建了我的 ResourcesService ,它正在翻译字符串:

getTranslation ( key: string, replace: Array<TranslationReplace> = null, locale: string = null, fallback: boolean = null ): Observable<Resource> {

    var params = "key=" + key +
        ( replace ? "&replace=" + JSON.stringify(replace) : '') +
        ( locale ? "&locale=" + locale : '') +
        ( fallback ? "&fallback=" + fallback : '');
    var headers = new Headers({'Content-Type':'application/x-www-form-urlencoded'});

    return this.http.post(this.apiUrl + 'getTranslation', params, {headers: headers})
        .map(this.extractData)
        .startWith({ name: 'Loading...', value: 'Translating...' })
        .catch(this.handleError);

}

我创建了一个提供翻译的 TranslateComponent ,这是整个组件:

import {Component, Input, Injectable, OnInit, OnChanges, SimpleChange} from "@angular/core";
import {ResourcesService} from "../services/resources.service";
import {TranslationReplace} from "../models/TranslationReplace";

@Component({
    selector: 'translate',
    template: `{{translation}}`
})

@Injectable()
export class TranslateComponent implements OnInit, OnChanges {

    @Input() ref: string;
    @Input() replace: Array<TranslationReplace>;
    @Input() locale: string;
    @Input() fallback: boolean;

    private translation: string;
    constructor(private resourcesService: ResourcesService) {}

    ngOnInit() : void {
        this.getTranslation();
    }

    ngOnChanges(changes: {[propKey: string]: SimpleChange}) {
        for (let propName in changes) {
            if(propName == 'replace') {
                this.getTranslation();
            }
        }
    }

    private getTranslation(): void {
        this.resourcesService.getTranslation(this.ref, this.replace, this.locale, this.fallback).forEach(translation => this.translation = translation.value );
    }
}

所有工作都非常完美,并且要求翻译我只需要调用选择器:

<translate [ref]="'string.to_translate'"></translate>

但是...

现在我想在属性中使用翻译。

所以我通过创建翻译的引用并在属性中调用它来找到实现它的丑陋方式。但它非常讨厌...

首先,我需要将此位添加到我的模板中:

<translate [ref]="'string.to_translate'" style="display:none;" #myStringTranslation></translate>

接下来在我的元素中调用它并通过引用询问属性:

<input type="text" [(ngModel)]="input" #input="ngModel [placeholder]="myStringTranslation.translation">

我真的不喜欢这个想法。

我正在寻找的是以某种方式称呼它,我不知道......发出它?让它看起来更好。不要创建额外的元素。

所以我的问题是: 我可以做得更好吗?我可以以某种方式直接从没有引用的属性调用转换吗?

** -----更新----- **

好的,我吸取了教训:)感谢 Meir 向我展示了正确的方向以及教程的Angular.io网站。

最后我在我的应用程序中添加了 TranslateDirective

import {Directive, Input, ElementRef, OnChanges, OnInit, SimpleChange, Renderer} from "@angular/core";
import {TranslationReplace} from "../models/TranslationReplace";
import {ResourcesService} from "../services/resources.service";

@Directive({
    selector: '[translate]'
})
export class TranslateDirective implements OnInit, OnChanges {

    @Input('translate') ref: string;
    @Input('translateReplace') replace: Array<TranslationReplace>;
    @Input('translateLocale') locale: string;
    @Input('translateFallback') fallback: boolean;
    @Input('translateAttr') attr: string;

    private translation: string;

    constructor(
        private elRef: ElementRef,
        private renderer: Renderer,
        private resourcesService: ResourcesService
    ) {}

    ngOnInit():void {
        this.getTranslation();
    }

    ngOnChanges(changes: {[propKey: string]: SimpleChange}):void {
        for (let propName in changes) {
            if(propName == 'replace') {
                this.getTranslation();
            }
        }
    }

    private getTranslation(): void {
        if(this.attr)
            this.resourcesService.getTranslation(this.ref, this.replace, this.locale, this.fallback).forEach(translation =>
            {
                this.translation = translation.value;
                this.renderer.setElementAttribute(this.elRef.nativeElement,this.attr,this.translation);
            });
    }
}

现在可以轻松地将翻译添加到以下属性中:

<input type="text" [(ngModel)]="input" #input="ngModel [translate]="'string.to_translate'" [translateAttr]="'placeholder'">

感谢您的帮助!!

1 个答案:

答案 0 :(得分:2)

您可以将其转换为属性指令:

@Directive({
  selector: 'translate'
})
export class TranslateDirectiev {
  @Input() translate: string;

  constructor(private elRef: ElementRef){}

  ngOnChanges(changes: SimpleChanges): void {
       if(this.translate){
          var translatedText: string = translateSvc.translate(this.translate);
          this.renderer.setElementProperty(this.elementRef.nativeElement, 'innerHTML', translatedText);
      }
  }

}

这是一个没有服务注入的简单示例。此外,对于输入字段,您可能需要使用不同的方法并更新value属性而不是innerHtml