乐趣区

关于angular:异步验证器防抖的补充-以及-记录动态组件遇到的问题

补充

这里对上文的异步验证器防抖做一点补充。
https://segmentfault.com/a/11…

vehicleBrandNameNotExist(): AsyncValidatorFn {return (control: AbstractControl): Observable<ValidationErrors | null> => {if (control.value === '') {return of(null);
      }
      return timer(this.debounceTime).pipe(
        // 调用服务, 获取后果
        switchMap(() => this.vehicleBrandService.existByName(control.value)),
        // 对后果进行解决,null 示意正确,对象示意谬误
        map((exists: boolean) => (exists ? {vehicleBrandNameExist: true} : null)),
      )
    };
  }

上文的最初提到,发现这种写法能够。通过老师的判断后,发现几种写法的关键在于一个问题:

每次取得新值的时候,fromControl 是否会勾销对上一个数据源的订阅?

这种问题从源码中找比拟艰难,于是我搜寻了相干材料:

找到一篇同样介绍这种办法的文章。

如下图,同样用的是 time().pipe, 他的解释说,

当有新的 control 值时,fromControl 会勾销对上一个正在期待实现的 observable 的订阅,因而,旧的 observable 不会收回值。


我画了一张图来阐明:

看图就能够理解到,fromControl 勾销了对旧值的订阅,旧的 observable 并不会收回值。


简化

明确了这个情理之后,防抖就能够简化成这种写法:

vehicleTypeNameIsAvailable(VehicleTypeId?: number): AsyncValidatorFn {return (control: AbstractControl): Observable<ValidationErrors | null> => {if (control.value === '') {return of(null);
      }

      return of(null).pipe(delay(1000),
        // 调用服务, 获取后果
        switchMap(() => this.vehicleTypeService.nameIsAvailable(control.value, VehicleTypeId)),
        // 对后果进行解决,null 示意正确,对象示意谬误
        map((available: boolean) => (available ? null : {vehicleTypeNameNotAvailable: true})),
      )
    };
  }

间接返回 null 作为 observable, 如果 delay(1000), 通过了,那就调用 service 服务。

通过测试,执行得很好,合乎预期。

后盾遇到的问题

起因是这样的:
是这样的,我在 user 实体增加了 Ding 字段,作为推送所有客户端信息的钉钉。


然而在登录的时候发现,只有登录的用户里有这个字段,后盾就报错


报错如下:

报了 HTTP, 和栈溢出等方面的谬误。看不大懂,于是去谷歌:

搜了很多,大部分都是说因为增加了 many to One,many to many 等关系, Serializable 序列化或者反序列化导致栈溢出,

倡议是:增加 @JsonIgnore,尽管可行,没有报错,然而增加之后前台就承受不到这个字段了,问题是我须要这个字段。

起初解决无果,老师看之后,才发现,c 层的申请没有增加 @JsonView,这才导致出错。

增加之后才解决问题。

总结:先查看哪个申请报的错,看看相干代码有无问题,不行了再谷歌,因为有时候谷歌并不能很好地解决本人的问题。

动静组件遇到的问题

问题

v 层是这样:

<form [formGroup]="formGroup" *ngIf="task">
 <....> // 这里是 形容 <imput>
 <....> // 这里是 有无截止日期 <select>
 <....> // 这里是  截止日期 <input>

  <!--  动静表单项 -->
  <div class="ad-banner-example">
    <ng-template appFormItem></ng-template>
  </div>
</form>

按理来是这样:应该显示红框中的内容,即我上述代码写的动静表单
<ng-template appFormItem></ng-template>


然而后果是这样:动静表单并没有显示进去。


展现代码

这里展现一下代码配置:

c 层设置了一个这个属性,能够往其中增加动静表单项。

@ViewChild(FormItemDirective, {static: true})
appFormItem!: FormItemDirective;

这个是指令定义,用其中的 viewContainerRef 往里增加动静表单组件。

@Directive({selector: '[appFormItem]'
})
export class FormItemDirective {constructor(public viewContainerRef: ViewContainerRef) {}}

用图示意是这样:


剖析问题

我在控制台中失去了这样的报错:

也就是说,父组件通过 @viewChild 拜访到子组件的属性 是 undefined!

先来看看什么是 @ViewChild

@ViewChild 是一个属性装璜器。它提供了一个弱小的形式来拜访子元素和属性。当咱们想要拜访父组件中的子组件元素、表单属性脏查看、触发事件,以及父组件中的指令时,@ViewChild 是一种非常简单的拜访形式。@ViewChild 是一种非常简单的拜访子元素的办法。

为什么会呈现这种拜访子元素属性是 undefined 的状况呢?我查找了 @viewChild 的相干材料。

我失去了这么一个材料:

当父组件开始渲染时,ViewChild 装璜器不可用。它将不会在 ngOnInit()生命周期钩子中可用。它将在 ngAfterViewInit 生命周期钩子中可用。

看到这,明确了 报错起因

在 ngOnInit 的期间咱们拜访了 @viewChild , 然而它不可用,所有控制台报了错


新的问题

那么新的问题来了:
即便它在 ngOnInit 不可用,然而在 ngOnInit 后,angular 难道不会再渲染一次,使它可用吗?

我的意思是:当页面稳定下来后,咱们能看到它可用。

这里又波及到 @ViewChild 的另一个属性:static

@ViewChild(FormItemDirective, {static: true})

在我的代码中,设置它为 static。

static

staic 属性有什么用?我找了相干内容

Static stands for whether the ViewChild is“static”content e.g. Always available on the page, no matter page bindings, API calls, ngIfs etc. When set to true, we are telling Angular that the ViewChild will be available at anytime, so simply query for the ChildComponent at the earliest lifecycle hook available and then never query again.

简略来说就是:

Static 代表 ViewChild 是否是“动态”内容.

  • 设置为 true 时,咱们通知 Angular ViewChild 将随时可用,因而只需在可用的最早生命周期钩子查问并加载,而后再也不查问。
  • 设置为 false,咱们是说 ViewChild 将在当前可用,因而咱们必须查看每次运行时的 ViewChild,若不可用,则加载。显著,这会产生更高的性能负载,因为咱们必须始终查看在组件更改时它是否可用。

起源:
https://tutorialsforangular.c…

临时不晓得这个负载有多大。

会有两个后果:

  1. 设置为 true, 在 ngOnInit 时 ViewChild 可用,然而当前都不再查问和加载。
  2. 设置为 false, 在 ngOnInit 时不可用,在组件变更等拜访操作时,查问,若不可用,则加载。

了解了含意之后,来找找我本人代码的问题。

我发现了问题所在:

问题起因:在 static 为 true 时,应用了 *ngIf。

在 ngOnInit 时,task 实体没有值,所以不会加载上面的子组件。

然而 @ViewChild 又在 ngOnInit 时尝试加载,然而找不着 v 层的子组件在哪。于是加载失败,并且因为 static = true , 当前都不加载。

解决方案:

  • 删除 *ngif , 让 @ViewChild 在 ngOnInit 时就查问加载,并且之后都不查问。然而如果 ngOnInit 时呈现加载失败,那么咱们不会看到它被加载了。
  • 把 static 改为 false , 每次用之前查问一遍,若未加载则加载。然而对性能有肯定影响。

通过测试,两种办法都能很好的失效。我用了第一种。

总结倡议

  • 若想在 ngOnIni t 中使 @ViewChild 可用,并节约性能,或者在页面上始终可用,并且从不暗藏,static 设为 true , 但要留神是否能加载胜利。v 层须要立刻渲染,不能设置 *ngIf 等判断加载。
  • 若想以某种形式动静地调用,或者想每次都查问是否可用,static 设置 false,
退出移动版