Angular:如何获得默认的@Input 值?

Fab*_*ian 5 javascript angular

我们正在开发组件,在使用它们时,我们希望使用与 DOM 节点相同的机制来有条件地定义属性。因此,为了完全阻止属性显示,我们将值设置为 null 并且它不存在于最终的 HTML 输出中。伟大的!

<button [attr.disabled]="condition ? true : null"></button>
Run Code Online (Sandbox Code Playgroud)

现在,当使用我们自己的组件时,这不起作用。当我们设置时null,我们实际上null将组件@Input 作为值。任何默认设置值都将被覆盖。

...
@Component({
    selector: 'myElement',
    templateUrl: './my-element.component.html'
})

export class MyElementComponent {
    @Input() type: string = 'default';
...
Run Code Online (Sandbox Code Playgroud)
<myElment [type]="condition ? 'something' : null"></myElement>
Run Code Online (Sandbox Code Playgroud)

因此,无论何时我们读取type组件中的 ,我们都会得到null而不是设置的'default'值。

我试图找到一种方法来获取原始默认值,但没有找到。它存在于及时ngBaseDef访问 constructor 时,但这在生产中不起作用。我希望ngOnChanges给我这样做了,因此能够防止第一个变化的现实(默认)值null设置,但previousValueundefined

我们想出了一些方法来解决这个问题:

  • 定义一个default对象并为每个输入设置默认值null
  • 再次寻址模板中的 DOM 元素,而不是设置为 null
<myElement #myelem [type]="condition ? 'something' : myelem.type"></myElement>
Run Code Online (Sandbox Code Playgroud)
  • 为每个输入定义 set / get 以防止空设置
_type: string = 'default';
@Input()
set type(v: string) {if (v !== null) this._type = v;}
get type() { return this._type; }
Run Code Online (Sandbox Code Playgroud)

但很好奇,是否有其他人有类似的问题以及它是如何解决的。我也很感激任何其他可能更优雅的想法。

谢谢!

Pie*_*Duc 4

没有标准的角度方式,因为很多时候你会想要nullundefined作为值。你的想法并不是糟糕的解决方案。我还有几个

  1. 我想你也可以使用ngOnChanges这个钩子:
@Input()
type: string = 'defaultType';

ngOnChanges(changes: SimpleChanges): void {
 // == null to also match undefined
 if (this.type == null) {
    this.type = 'defaultType';
  }
}
Run Code Online (Sandbox Code Playgroud)
  1. 或者使用Observables
private readonly _type$ = new BehaviorSubject('defaultType');

readonly type$ = this._type$.pipe(
  map((type) => type == null ? 'defaultType' : type)
); 

@Input()
set type(type: string) {
  this._type$.next(type);
}
Run Code Online (Sandbox Code Playgroud)
  1. 或者创建您自己的装饰游乐场
function Default(value: any) {
  return function(target: any, key: string | symbol) {
    const valueAccessor = '__' + key.toString() + '__';

    Object.defineProperty(target, key, {
      get: function () {
        return this[valueAccessor] != null ? this[valueAccessor] : value
      },
      set: function (next) {
        if (!Object.prototype.hasOwnProperty.call(this, valueAccessor)) {
          Object.defineProperty(this, valueAccessor, {
            writable: true,
            enumerable: false
          });
        }

        this[valueAccessor] = next;
      },
      enumerable: true
    });
  };
}
Run Code Online (Sandbox Code Playgroud)

你可以这样使用:

@Input()
@Default('defaultType')
type!: string;
Run Code Online (Sandbox Code Playgroud)