【问题标题】:Angular: How to get default @Input value?Angular:如何获取默认的@Input 值?
【发布时间】:2020-12-04 20:34:12
【问题描述】:

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

<button [attr.disabled]="condition ? true : null"></button>

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

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

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

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

我试图找到一种方法来获取原始默认值,但没有找到。当在constructor 时间访问时,它存在于ngBaseDef 中,但这在生产中不起作用。我希望ngOnChanges 在完成的第一次更改中给我真正的(默认)值,因此能够防止设置null,但previousValueundefined

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

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

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

谢谢!

【问题讨论】:

标签: javascript angular


【解决方案1】:

没有标准的角度方式,因为很多时候您希望 nullundefined 作为值。你的想法不是坏的解决方案。我还有几个

  1. 我想您也可以为此使用 ngOnChanges 钩子:
@Input()
type: string = 'defaultType';

ngOnChanges(changes: SimpleChanges): void {
 // == null to also match undefined
 if (this.type == null) {
    this.type = 'defaultType';
  }
}
  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);
}
  1. 或创建自己的装饰器playground
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
    });
  };
}

你可以这样使用:

@Input()
@Default('defaultType')
type!: string;

【讨论】:

  • 第三种解决方案看起来很有希望。不幸的是,一旦您不止一次拥有一个组件,它就无法正常工作。所有组件都将从外部接收相同的类型集,即使某些或一个为 null,他也会从另一个组件获取类型。由于这看起来最有希望,我将进一步研究它,看看(我犯了)错误在哪里 :) 谢谢!
  • @Fabian 我不应该发布未经测试的代码 :) 无论如何,我已经更新了我的答案。我们显然需要使用值访问器属性,以便每个实例都不同。
  • 我自己已经有了一个工作版本,非常感谢更新。现在它就像一个魅力! ;) 感谢您创建自己的装饰器的想法。
  • @Fabian 不客气 :) 您是如何设法使其适用于多个类实例的?
  • @Fabian 我已经从装饰器更新了我的答案,因为我注意到在for .. in 循环中它也会显示值访问器属性。通过直接在 this.set 中声明它并将 enumerable 设置为 false 它将不再显示。
【解决方案2】:

基于 Poul Krujit 解决方案的另一种选择(如果您不想实现自己的自定义 @annotation 可能更简单):

const DEFAULT_VALUE = 'default';
export class MyElementComponent {
  typeWrapped = DEFAULT_VALUE;

  @Input()
  set type(selected: string) {
    // this makes sure only truthy values get assigned
    // so [type]="null" or [type]="undefined" still go to the default.
    if (selected) {
      this.typeWrapped = selected;
    } else {
      this.typeWrapped = DEFAULT_VALUE;
    }
  }
  get type() {
    return this.typeWrapped;
  }
}

【讨论】:

  • 这个问题,如果您首先在输入上有一个值,然后将此值设置为 nullundefined 它不会更改 typeWrapped 属性,并且您的默认值价值消失了。
  • 我已经更新了我的提案以包含该案例。
【解决方案3】:

如果您需要为多个输入执行此操作,您还可以使用自定义 pipe,而不是手动定义每个输入的 getter/setter 和默认值。如果输入为nullpipe 可以包含逻辑和 defaultArg 以返回 defaultArg。

// pipe
@Pipe({name: 'ifNotNullElse'})
export class IfNotNullElsePipe implements PipeTransform {
  transform(value: string, defaultVal?: string): string {
    return value !== null ? value : defaultVal;
  }
}
<!-- myElem template -->
<p>Type Input: {{ type | ifNotNullElse: 'default' }}</p>

<p>Another Input: {{ anotherType | ifNotNullElse: 'anotherDefault' }}</p>

【讨论】:

    猜你喜欢
    • 2023-02-02
    • 1970-01-01
    • 2016-06-08
    • 1970-01-01
    • 2012-07-31
    • 2012-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多