使用angular回调丢失包含函数的范围

时间:2017-12-15 23:51:27

标签: javascript angular typescript

我有一段代码,我得到了一些奇怪的输出。当我不认为它时,函数中使用的参数正在改变。

代码的入口点。

handleAction(action : HAction){
    this.openForm("marksForm","Form");
  }

打开表单的方法。

public openForm(name : string, type : string){
    console.log("Name",name)
    let cb = this.createComponentInitCallback(this.compService.getComponentType(type),
                                                name);
    let itemconfig ={
        type: 'row',
        content: [{
          type: 'component',
          title: 'Form Test',
          componentName: 'h-form',
          componentState: {}
        }]
      }
      let tryRegister = false;
    try{
      this.goldenLayout.getComponent(name);
    }catch(e){console.log("registering component",name); tryRegister=true;}
    if(tryRegister)
      this.goldenLayout.registerComponent(name,cb);
    if(this.goldenLayout.root.contentItems[0])
      this.goldenLayout.root.contentItems[ 0 ].addChild(itemconfig);
    else
      this.goldenLayout.root.addChild(itemconfig);
  }

此方法创建定义的回调函数。

public createComponentInitCallback(componentType: Type<any>, name : string ): ComponentInitCallback {
    console.log("1Name",name);
    let f = (container: GoldenLayout.Container, componentState: any) => {
      console.log("2Name",name);
      this.ngZone.run(() => {
        console.log("3Name",name);
        // Create an instance of the angular component.
        const factory = this.componentFactoryResolver.resolveComponentFactory(componentType);
        const injector = this._createComponentInjector(container, componentState);
        const componentRef = this.viewContainer.createComponent(factory, undefined, injector);
        console.log("4Name",name)
        componentRef.instance.name=name;
        // Bind the new component to container's client DOM element.
        container.getElement().append($(componentRef.location.nativeElement));


        this._bindEventHooks(container, componentRef.instance);

        // Store a ref to the compoenentRef in the container to support destruction later on.
        (container as any)[COMPONENT_REF_KEY] = componentRef;
      });
    };

    return f;
  }

您将看到我的日志语句。此回调在GoldenLayout库中执行。但是,我很确定这应该有用。

以下是产出:

  

名称marksForm

     

1Name marksForm

     

2名h-form

     

3名h-form

     

4名h-form

第一个控制台输出是记录传递给此方法的内容。你可以看到它显然在改变我,所以我必须做错事。奇怪的是,componentType参数工作得很好。

我在这里做错了什么?

2 个答案:

答案 0 :(得分:1)

依赖于词法this并且应该作为回调传递的函数应始终绑定到上下文。

可以使用createComponentInitCallback或箭头函数将

bind方法绑定到上下文(请参阅绑定原型方法与箭头实例方法的this explanation):

constructor() {
   this.createComponentInitCallback = this.createComponentInitCallback.bind(this);
}

或者产生的回调可以绑定到上下文:

let cb = this.createComponentInitCallback(this.compService.getComponentType(type),
                                            name).bind(this);

考虑到this不存在与当前类实例不同的情况,第一个选项更可取。

至于功能范围,在任何情况下都不会丢失。如果name作为父函数中的参数传递,它将在嵌套函数中保持不变。

答案 1 :(得分:0)

除非您使用Angular HttpModule进行调用,否则使用外部库进行的任何异步调用都将导致您的调用从原始范围运行。 要缓解这种情况,您需要将此值分配给回调可以使用的本地变量。

public createComponentInitCallback(componentType: Type<any>, name : string ): ComponentInitCallback {
    console.log("1Name",name);
    let self = this;
    let f = (container: GoldenLayout.Container, componentState: any) => {
      console.log("2Name",name);
      this.ngZone.run(() => {
        console.log("3Name",name);
        // Create an instance of the angular component.
        const factory = self.componentFactoryResolver.resolveComponentFactory(componentType);
        const injector = self._createComponentInjector(container, componentState);
        const componentRef = self.viewContainer.createComponent(factory, undefined, injector);
        console.log("4Name",name)
        componentRef.instance.name=name;
        // Bind the new component to container's client DOM element.
        container.getElement().append($(componentRef.location.nativeElement));


        self._bindEventHooks(container, componentRef.instance);

        // Store a ref to the compoenentRef in the container to support destruction later on.
        (container as any)[COMPONENT_REF_KEY] = componentRef;
      });
    };

    return f;
  }