如何使用动态模板创建组件? (组件内联模板包含在内) [英] How to create a Component with a dynamic template? (Component transclude with inline template)

查看:80
本文介绍了如何使用动态模板创建组件? (组件内联模板包含在内)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个组件,该组件内部具有动态模板字符串,该字符串可以访问模板上的局部变量.我尝试过的每种方法都以动态模板字符串"结尾而不是$compile(用1角表示,请问好).

I'm trying to create a component that has a dynamic template string inside of it that can access the local variables on the template. Every approach I've tried ends up with the "dynamic template string" not being $compile'd (angular 1 terminology, please excuse me).

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

Here is the code for the component below. Where you see the comment I would like to insert a template string that can reference item in the ngFor.

@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,但没有运气-

Ideally I would like to have the transcluded content of the ion-alpha-scroll reference the item in the ngFor. I tried using ng-content in the necessary ngFor of the component and had no luck -

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

我尝试过的一件事就是这样-

One thing I tried was like this -

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

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

The alphaScrollTemplate is just a string containing {{item.$t}}. I then tried to reference it in the component where the comment is asking the question but it doesn't work -

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

我真的很好奇,甚至在角度2的情况下是否也有可能.我刚刚发现这个问题与我的非常相似.谢谢您的任何帮助或建议.

I'm really curious if this is even possible with angular 2 yet. I just found this question which is very similar to mine. Any help or suggestions will be greatly appreciated, thanks.

推荐答案

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

Here is the solution I used for angular 2.0.0-rc.3

此解决方案创建一个动态组件,并使用ViewContainerRefComponentFactory加载它. 这是GitHub上的ionic 2组件.

This solution creates a dynamic component and loads it by using ViewContainerRef and ComponentFactory. 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;
  }

  // ....
}

这篇关于如何使用动态模板创建组件? (组件内联模板包含在内)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆