在Jquery插件模板内部绑定Angular2组件



我正在angular 2项目中使用剑道。

正确设置小部件没有问题:

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

当它运行时,插件会修改DOM(据我所知,在不修改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实现了这一点,但感觉不对。

我在这个线程中找到了一些需要的细节: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();
                })
            });
        });        
    }
}

参数:

  • componentType:要绑定的组件类。它使用反射来拉动所需的选择器
  • 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 );

在组件需要更改状态并重新提交一些内容之前,您的解决方案运行良好。因为我还没有发现任何能力为Angular之外生成的元素(jquery、vanilla-js甚至服务器端)获取ViewContainerRef第一个想法是通过设置一个间隔来调用detectChanges()。经过几次迭代,我终于找到了一个适合我的解决方案

到目前为止,在2017年,你必须用ComponentResolverFactory取代ComponentResolver,并做几乎相同的事情:

    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

忘记上面所有的话。它可以工作,但只需遵循这个答案

相关内容

  • 没有找到相关文章

最新更新