4

我正在使用angular 2項目中的kendo。在Jquery插件模板中綁定Angular2組件

獲取小部件設置正確是沒有問題的:

ngOnInit() { 
    let options = inputsToOptionObject(KendoUIScheduler, this); 
    options.dataBound = this.bound; 
    this.scheduler = $(this.element.nativeElement) 
     .kendoScheduler(options) 
     .data('kendoScheduler'); 

} 

當運行,該插件修改DOM(和,我knowleged,沒有modifiying由angular2維護的影子DOM)。我的問題是,如果我想在插件的任何地方使用組件,就像在模板中一樣,Angular不知道它是否存在,並且不會綁定它。

例子:

public views:kendo.ui.SchedulerView[] = [{ 
    type: 'month', 
    title: 'test', 
    dayTemplate: (x:any) => { 
     let date = x.date.getDate(); 
     let count = this.data[date]; 
     return `<monthly-scheduler-day [date]="test" [count]=${count}"></monthly-scheduler-day>` 
    } 
}]; 

每月調度天階:

@Component({ 
    selector: 'monthly-scheduler-day', 
    template: ` 
      <div>{{date}}</div> 
      <div class="badge" (click)=dayClick($event)>Available</div> 
    ` 
}) 
export class MonthlySchedulerDayComponent implements OnInit{ 
    @Input() date: number; 
    @Input() count: number; 
    constructor() { 
     console.log('constructed'); 
    } 
    ngOnInit(){    
     console.log('created'); 
    } 

    dayClick(event){ 
     console.log('clicked a day'); 
    } 

} 

是否有一個「正確」的方式綁定微件創建的標記裏面這些組件?我設法通過偵聽來自窗口小部件的綁定事件,然後遍歷它創建的元素並使用DynamicComponentLoader,但感覺不對。

回答

0

,我發現了一些我需要在這個線程的詳細信息:https://github.com/angular/angular/issues/6223

我掀起這項服務,以處理結合我的部件:

import { Injectable, ComponentMetadata, ViewContainerRef, ComponentResolver, ComponentRef, Injector } from '@angular/core'; 

declare var $:JQueryStatic; 

@Injectable() 
export class JQueryBinder { 
    constructor(
     private resolver: ComponentResolver, 
     private injector: Injector 
    ){} 

    public bindAll(
     componentType: any, 
     contextParser:(html:string)=>{}, 
     componentInitializer:(c: ComponentRef<any>, context: {})=>void): 
      void 
     { 
     let selector = Reflect.getMetadata('annotations', componentType).find((a:any) => { 
      return a instanceof ComponentMetadata 
     }).selector; 

     this.resolver.resolveComponent(componentType).then((factory)=> { 
      $(selector).each((i,e) => { 
       let context = contextParser($(e).html()); 
       let c = factory.create(this.injector, null, e); 
       componentInitializer(c, context); 
       c.changeDetectorRef.detectChanges(); 
       c.onDestroy(()=>{ 
        c.changeDetectorRef.detach(); 
       }) 
      }); 
     });   
    } 
} 

PARAMS:

  • 組件類型:該你想要綁定的組件類。它使用反射來拉它需要
  • contextParser選擇:回調,是以現有的子html並構造一個上下文對象(任何你需要初始化組件狀態)
  • componentInitializer - 回調與上下文初始化已創建的組件您解析

用法示例:

let parser = (html: string) => { 
     return { 
      date: parseInt(html) 
     }; 
    }; 

    let initer = (c: ComponentRef<GridCellComponent>, context: { date: number })=>{ 
     let d = context.date; 

     c.instance.count = this.data[d]; 
     c.instance.date = d; 
    } 

    this.binder.bindAll(GridCellComponent, parser, initer); 
0

很好,直到組件需要改變其狀態,並重新呈現一些東西,你的解決方案正常工作。 因爲我還沒有發現任何能夠獲得ViewContainerRef的Angular(jquery,vanilla js或者甚至服務器端)以外生成的元素 第一個想法是通過設置間隔來調用detectChanges()。經過幾次迭代後,我終於找到了適合我的解決方案。

所以在2017年爲止,您必須更換ComponentResolver與ComponentResolverFactory和做幾乎同樣的事情:

let componentFactory = this.factoryResolver.resolveComponentFactory(componentType), 
     componentRef = componentFactory.create(this.injector, null, selectorOrNode); 

    componentRef.changeDetectorRef.detectChanges(); 

之後,你可以模擬通過訂閱其NgZone的EventEmitters組件實例連接到變更檢測週期:

let enumerateProperties = obj => Object.keys(obj).map(key => obj[key]), 
     properties = enumerateProperties(injector.get(NgZone)) 
         .filter(p => p instanceof EventEmitter); 

    let subscriptions = Observable.merge(...properties) 
            .subscribe(_ => changeDetectorRef.detectChanges()); 

當然不要忘了退訂的破壞:

componentRef.onDestroy(_ => { 
     subscriptions.forEach(x => x.unsubscribe()); 
     componentRef.changeDetectorRef.detach(); 
    }); 

UPD堆棧溢出後再一次UPD

忘掉上面的所有單詞。它的作品,但只是按照這answer