角度:如何获取默认的@Input值?

时间:2019-11-04 15:00:44

标签: javascript angular

我们正在开发组件,并且在使用它们时,我们希望使用与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'值。

我试图找到一种方法来获取原始默认值,但没有找到它。在ngBaseDef时间访问时,它存在于constructor中,但是在生产环境中不起作用。我希望ngOnChanges在完成的第一个更改中为我提供真实的(默认)值,因此能够防止设置null,但是previousValue是{{1} }。

我们想出了一些解决方法:

  • 定义undefined对象,并为每个输入设置default时的默认值
  • 再次寻址模板中的DOM元素,而不是设置null
null
  • 为每个输入定义设置/获取以防止设置为空
<myElement #myelem [type]="condition ? 'something' : myelem.type"></myElement>

但是很好奇,如果还有其他人也有类似的问题以及如何解决。我也将不胜感激任何其他更优雅的想法。

谢谢!

4 个答案:

答案 0 :(得分: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;

答案 1 :(得分:0)

您可以在父组件中使用三元运算符,如下所示:

<myElment [attr.type]="condition ? 'something' : null"></myElement>

只有在满足条件的情况下,这才会将值传递给子组件,否则初始化值将不会被覆盖

子组件中不需要任何其他代码

问题是您可能会掉毛能力

答案 2 :(得分:0)

如果需要对多个输入执行此操作,则还可以使用自定义score3来代替手动定义每个输入的getter / setter和默认值。如果输入为pipe,则pipe可以包含逻辑和defaultArg以返回defaultArg。

null
// pipe
@Pipe({name: 'ifNotNullElse'})
export class IfNotNullElsePipe implements PipeTransform {
  transform(value: string, defaultVal?: string): string {
    return value !== null ? value : defaultVal;
  }
}

答案 3 :(得分:0)

基于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;
  }
}