1

目前试图弄清楚为什么会发生这种情况,但如果我&?在 NG1 组件上有一个可选的函数绑定 (),那么 NG2 将在其上放置一个 EventEmitter:/

这不是我所期望的,并且会破坏我们通常在null/时所做的一些代码undefined

这是我们所拥有的示例:

class MyController {
  public onInit: () => string;
  public onAction: () => void;

  public resultFromNg2: string;
  public onActionHasValue: boolean;
  public typeOfOnAction: string;

  public $onInit() {
    this.resultFromNg2 = this.onInit();
    this.onActionHasValue = this.onAction != null;
    this.typeOfOnAction = typeof this.onAction;
  }
}

export const ng1DemoComponent = {
  selector: "ng1-demo",
  template: `
    <div>Hello, {{ $ctrl.username }}!</div>
    <div>resultFromNg2: {{ $ctrl.resultFromNg2 }}</div>
    <div>onActionHasValue: {{ $ctrl.onActionHasValue }} - typeof: {{ $ctrl.typeOfOnAction }}</div>
  `,
  bindings: {
    username: "<",
    onInit: "&?",
    onAction: "&?"
  },
  controller: MyController
};

@Directive({
  selector: ng1DemoComponent.selector
})
export class Ng1DemoComponentFacade extends UpgradeComponent {
  @Input() username: string;
  @Input() onInit: () => string;
  @Input() onAction: () => void;

  constructor(elementRef: ElementRef, injector: Injector) {
    super(ng1DemoComponent.selector, elementRef, injector);
  }
}

可测试环境:https ://stackblitz.com/edit/angular-hybrid-upgrade-dpjv4p?file=ng1%2Fng1-demo.component.ts

在这段代码中,我希望onAction设置为undefined以便我可以正确分配我的其他属性,但目前它不起作用:/

我也尝试删除?, 所以 from &?to &,但现在可能是 NG1 给出了angular.noop..

关于如何在不重写内容的情况下完成这项工作的任何想法?

非常感谢您提供的任何帮助!

注意:我们希望在 NG1 中保留一部分代码库,因为我们现在无法使用我们拥有的代码库来转换所有代码库。

4

1 回答 1

1

Angular 的UpgradeComponent构造函数调用这个:

private initializeOutputs() {
  // Initialize the outputs for `=` and `&` bindings
  this.bindings.twoWayBoundProperties.concat(this.bindings.expressionBoundProperties)
      .forEach(propName => {
        const outputName = this.bindings.propertyToOutputMap[propName];
        (this as any)[outputName] = new EventEmitter(); // <--- sets it to an EventEmitter
      });
}

它将对象上定义的每个&绑定设置为即使(不幸的是)绑定是可选的并且当前未分配。bindingsEventEmitter

不过,您可以做的一件事是使用$onChanges()NG1 组件控制器中的生命周期挂钩来帮助您确定哪些绑定已分配,哪些尚未分配。

这个钩子在之前触发$onInit()并被一个对象调用,该对象保存所有与 currentValue 和 previousValue 的单向绑定的更改。

这意味着该对象仅对已分配值的每个绑定都有一个属性。因此,在您的情况下,该“更改”对象将具有usernameonInit属性,但具有onAction属性。

当然,有不同的方法可以利用它,但一种简单的方法是这样的:

在您的控制器上创建一个assignedBindings成员,并在$onChanges()中为其分配changes传入的对象:

// ng1DemoComponent MyController

assignedBindings;

public $onChanges(changes) {
  this.assignedBindings = changes;
}

所以this.assignedBindings看起来像这样:

{
  onInit: { previousValue: undefined, /* ... */ }, // <-- SimpleChange instance
  username: { previousValue: undefined, /* ... */ } // <-- SimpleChange instance
}

然后更新$onInit()以检查任何您只想设置为EventEmitters 的绑定属性(如果它们实际已分配),并将属性设置为(null如果未分配):

// ng1DemoComponent MyController

public $onInit() {
  this.resultFromNg2 = this.onInit();

  if (!this.assignedBindings.onInit) { // <--- verify onInit assigned
    this.onInit = null;
  }

  if (!this.assignedBindings.onAction) { // <--- verify onAction assigned
    this.onAction = null;
  }

  this.onActionHasValue = this.onAction != null;
  this.typeOfOnAction = typeof this.onAction;
}

您可能需要进一步检查currentValue每个SimpleChange实例是否会随时间变化,但您明白了。

这是您的 StackBlitz 的一个分支,展示了这种方法。它可能有点hacky,但它似乎工作。

顺便说一句,感谢您创建 StackBlitz — 这对尝试调查此问题有很大帮助。

于 2021-04-09T22:24:21.370 回答