angular - Yalnızca isim bilinmesi durumunda Injector'dan bir pipe almak


Şablonlar gibi boru kullanabilen bir hizmete sahip olmayı planlıyorum. Bu amaçla, kayıtlı boruları almam gerekiyor.

Kod sonunda bu şekilde görünmelidir:

@Injectable()
class MyService {
    construct(private injector: Injector) {}

    // text could be something like 'myDate | date' or 'aVariable | uppercase'
    public interpolate(text: string, params: object = {}): string {
      let p: number = text.lastIndexOf('|');
      if (p > -1) {
        let args = [this.interpolate(text.substring(0, p))];
        let pipeName = text.substr(p+1).trim();
        // how ever we get the rest of the args from pipeName
        pipe = this.getPipe(pipeName)
        pipe.transform.apply(pipe, args);
      } else {
         // how ever we interpolate the base
      }
    }

    private pipeInstances: any = {}
    private getPipe(pipeName) {
      if (!this.pipeInstances[pipeName]) {
        // how to get the pipe?
        this.pipeInstances[pipeName] = this.injector.get(PipesContainer).get(pipeName);
      }

      return this.pipeInstances[pipeName];
    }
}

Sorun şu ki, enjektörden boruları alamazsınız. Önce onları sağlamanız gerekir (bir kez yönlendirmeler için ve bir kez sağlayıcılar için). Onları yeni bir liste tanımlamak yerine Angular'dan (compiler, core - hangisi olursa) almanın bir yolunu arıyorum; bir yerde bir liste olmalı - belki kök modül için.

Cevap #1

Angular'da bir boruyu bu şekilde almak için temiz bir deyimsel yol yok. Çünkü bunlar derleyici tarafından dahili olarak kullanılır ve enjeksiyon için açığa çıkarılmamıştır. Eğer boruların enjeksiyon ile enjekte edilmesi gerekiyorsa, sağlayıcılar olarak tanımlanmalıdırlar.

Borular enjeksiyon yapılabilir olduğundan, bunların örneklerini enjekte edici ile almak bunu yapmanın tek doğru yoludur. Bu, mevcut boruların bir haritası ile uygulanabilir.

export const pipesMap = {
  some: SomePipe
}

export const pipesList = Object.values(pipesMap);

@Injectable();
export class Pipes {
  protected pipesMap = pipesMap;

  constructor(private injector: Injector) {}

  get(pipeName) {
    return this.injector.get(this.pipesMap[pipeName]);
  }
}

...
providers: [pipesList, Pipes, ...],
...

Haritayı doldurmak, bir boru sınıfları dizisi belirleyerek ve bunların adlarını almak için PipeResolver kullanarak otomatikleştirilebilir:

import {PipeResolver} from '@angular/compiler';

const pipeResolver = new PipeResolver();

export const pipesList = [
  SomePipe
];

export const pipesMap = pipesList.reduce((pipesMap, pipeClass) => {
  const pipeName = pipeResolver.resolve(pipeClass, true).name;
  pipesMap[pipeName] = pipeClass;
  return pipesMap;
}, {});

...

Boru hattının her bağlama için derleyici tarafından bir kez örnekleneceği varsayıldığından, injector.get(...) bazı borular için çalışmayabilir. Bu durumda AsyncPipe örnekleyicidir; durum bilgisine sahiptir ve ayrıca derleyici dışından enjekte edilemeyen ChangeDetectorRef bağımlılığını kullanır.

Sonuç olarak, bu her bir boru için çözülmelidir, geliştiricinin ihtiyaçlarına ve borunun iç yapılarına bağlı olarak. İyi tasarlanmış borular genellikle ilgili belgelenmiş servisler için ince sarmalardır, iyi bir uygulama mümkünse bu servisleri doğrudan kullanmaktır.