javascript - 在元素属性中像函数一样使用 AngularJS 2 Component

标签 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'">

感谢您的帮助!!

最佳答案

你可以把它变成一个属性指令:

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

}

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

关于javascript - 在元素属性中像函数一样使用 AngularJS 2 Component,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40379528/

相关文章:

javascript - 向我的下划线模板添加一个计数

node.js - 未满足与 ngx-webstorage 的对等依赖性但不想更新到 Angular 5.0.0

javascript - Angular/TypeScript 使用动态键创建对象

javascript找到深度嵌套的对象

javascript - 点击事件时无法上传 dicom 图像 - webMango

javascript - 如何制作边框动画?

html - 如何使用:target selector to affect different elements?

javascript - 棘手的扫描仪在文本文件或 Textarea 输入中获取字符串命令?

javascript - React + Passport.js

angular - 如何从组件访问 "root"ViewContainerRef