【问题标题】:How to create a Component with a dynamic template? (Component transclude with inline template)如何使用动态模板创建组件? (使用内联模板嵌入组件)
【发布时间】:2016-07-03 22:22:10
【问题描述】:

我正在尝试创建一个内部具有动态模板字符串的组件,该字符串可以访问模板上的局部变量。我尝试过的每种方法都以“动态模板字符串”结尾,而不是 $compile'd(角度 1 术语,请原谅)。

这是下面组件的代码。在您看到评论的地方,我想在ngFor 中插入一个可以引用item 的模板字符串。

@Component({
  selector: 'ion-alpha-scroll',
  template: `
    <ion-scroll [ngStyle]="calculateScrollHeight()" scrollX="false" scrollY="true">
      <ion-list class="ion-alpha-list-outer">
        <div *ngFor="let items of sortedItems | mapToIterable;">
          <ion-item-divider id="scroll-letter-{{items.key}}">{{items.key}}</ion-item-divider>
          <ion-item *ngFor="let item of items.value">
            <!-- how can I pass a dynamic template here that can reference item ? -->
          </ion-item>
        </div>
      </ion-list>
    </ion-scroll>
    <ul class="ion-alpha-sidebar" [ngStyle]="calculateDimensionsForSidebar()">
      <li (click)="alphaScrollGoToList(letter)" *ngFor="let letter of alphabet">
        <div class="letter">{{letter}}</div>
      </li>
    </ul>
  `,
  pipes: [MapToIterable]
})
export class IonAlphaScroll {
  @Input() listData: any;
  @Input() key: string;
  @Input() template: string;
  ....
}

理想情况下,我希望ion-alpha-scroll 的嵌入内容在ngFor 中引用item。我尝试在组件的必要ngFor 中使用ng-content,但没有运气 -

<ion-alpha-scroll *ngIf="breeds" [listData]="breeds" key="$t">
  {{item.$t}}
</ion-alpha-scroll>

我试过的一件事是这样的——

<ion-alpha-scroll *ngIf="breeds" [listData]="breeds" key="$t" [template]="alphaScrollTemplate">
</ion-alpha-scroll>

alphaScrollTemplate 只是一个包含{{item.$t}} 的字符串。然后我尝试在评论提出问题的组件中引用它,但它不起作用 -

...
<ion-item *ngFor="let item of items.value">
  {{template}}
  <!-- this just outputs {{item.$t}} literally -->
</ion-item>
...

我真的很好奇 Angular 2 是否也能做到这一点。我刚刚找到this question which is very similar to mine。任何帮助或建议将不胜感激,谢谢。

【问题讨论】:

标签: angular angular2-components


【解决方案1】:

这是我用于 angular 2.0.0-rc.3 的解决方案

此解决方案创建一个动态组件并使用ViewContainerRefComponentFactory 加载它。 Here is the ionic 2 component on GitHub.

export function createComponentFactory(resolver: ComponentResolver, metadata: ComponentMetadata): Promise<ComponentFactory<any>> {
  const cmpClass = class DynamicComponent {};
  const decoratedCmp = Component(metadata)(cmpClass);
  return resolver.resolveComponent(decoratedCmp);
}

@Directive({
  selector: 'dynamic-html-outlet',
})
export class DynamicHTMLOutlet {
  @Input() src: string;
  @Input() ionAlphaScrollRef: any;
  @Input() currentPageClass: any;

  constructor(private vcRef: ViewContainerRef, private resolver: ComponentResolver) {
  }

  ngOnChanges() {
    if (!this.src) return;

    const metadata = new ComponentMetadata({
      selector: 'dynamic-html',
      template: this.src,
      pipes: [MapToIterable]
    });
    createComponentFactory(this.resolver, metadata).then(factory => {
      const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
      let component = this.vcRef.createComponent(factory, 0, injector, []);
      component.instance.ionAlphaScrollRef = this.ionAlphaScrollRef;
      component.instance.currentPageClass = this.currentPageClass;
    });
  }
}

@Component({
  selector: 'ion-alpha-scroll',
  template: `
    <dynamic-html-outlet
      [src]="alphaScrollTemplate"
      [ionAlphaScrollRef]="ionAlphaScrollRef"
      [currentPageClass]="currentPageClass">
    </dynamic-html-outlet>
  `,
  pipes: [MapToIterable],
  directives: [DynamicHTMLOutlet]
})
export class IonAlphaScroll {
  @Input() listData: any;
  @Input() key: string;
  @Input() itemTemplate: string;
  @Input() currentPageClass: any;
  @Input() triggerChange: any;
  private _scrollEle: HTMLElement;
  sortedItems: any = {};
  alphabet: any = [];
  alphaScrollTemplate: string;
  ionAlphaScrollRef = this;

  constructor(
    @Host() private _content: Content,
    private _elementRef: ElementRef,
    private vcRef: ViewContainerRef,
    private resolver: ComponentResolver
  ) {

  }

  ngOnInit() {
    this.alphaScrollTemplate = `
      <style>
        .ion-alpha-sidebar {
          position: fixed;
          right: 0;
          display: flex;
          flex-flow: column;
          z-index: 50000;
        }

        .ion-alpha-sidebar li {
          flex: 1 1 auto;
          list-style: none;
          width: 15px;
          text-align: center;
        }
      </style>

      <ion-scroll class="ion-alpha-scroll" [ngStyle]="ionAlphaScrollRef.calculateScrollDimensions()" scrollX="false" scrollY="true">
        <ion-list class="ion-alpha-list-outer">
          <div *ngFor="let items of ionAlphaScrollRef.sortedItems | mapToIterable; trackBy:ionAlphaScrollRef.trackBySortedItems">
            <ion-item-divider id="scroll-letter-{{items.key}}">{{items.key}}</ion-item-divider>
            <ion-item *ngFor="let item of items.value">
              ${this.itemTemplate}
            </ion-item>
          </div>
        </ion-list>
      </ion-scroll>
      <ul class="ion-alpha-sidebar" [ngStyle]="ionAlphaScrollRef.calculateDimensionsForSidebar()">
        <li *ngFor="let letter of ionAlphaScrollRef.alphabet" tappable (click)="ionAlphaScrollRef.alphaScrollGoToList(letter)">
          <a>{{letter}}</a>
        </li>
      </ul>
    `;

    setTimeout(() => {
      this._scrollEle = this._elementRef.nativeElement.querySelector('scroll-content');
      this.setupHammerHandlers();
    });
  }

  ngOnChanges(changes: {[propertyName: string]: SimpleChange}) {
    let tmp = {};
    for (let i = 0; i < this.listData.length; i++) {
      let letter = this.listData[i][this.key].toUpperCase().charAt(0);
      if (typeof tmp[letter] === 'undefined') {
        tmp[letter] = [];
      }
      tmp[letter].push(this.listData[i]);
    }

    this.alphabet = this.iterateAlphabet(tmp);
    this.sortedItems = tmp;
  }

  // ....
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-16
    • 1970-01-01
    • 1970-01-01
    • 2017-03-24
    • 1970-01-01
    • 2023-03-09
    • 2019-12-28
    • 2012-10-27
    相关资源
    最近更新 更多