Angular组件库ng-zorro-antd实现radio单选框选择

 更新时间:2023年05月12日 10:17:06   作者:后青春期的诗  
这篇文章主要为大家介绍了Angular组件库ng-zorro-antd实现radio单选框取消选择实现问题解决,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

antd组件库升级之后代码不生效

项目业务之前的代码设计了类似radio单选框取消选择的相关逻辑,用的是下面类似的代码实现的。但近期对ng-zorro-antd组件库升级之后,下面的代码不生效了。

import { Component } from '@angular/core';
@Component({
  selector: 'nz-demo-radio-radiogroup',
  template: `
    <nz-radio-group [(ngModel)]="radioValue">
      <label nz-radio (click)="click('A')" nzValue="A">A</label>
      <label nz-radio nzValue="B">B</label>
      <label nz-radio nzValue="C">C</label>
      <label nz-radio nzValue="D">D</label>
    </nz-radio-group>
  `
})
export class NzDemoRadioRadiogroupComponent {
  radioValue = 'A';
  click(value: any) {
    if (this.radioValue === value) {
      this.radioValue = ''
    }
  }
}

于是我到组件库源码里去找原因,并写demo打断点调试

  • 将nz-radio-group绑定的radioValue值清空会首先走group组件下面的逻辑
writeValue(value: NzSafeAny): void {
    this.value = value;
    this.nzRadioService.select(value);
    this.cdr.markForCheck();
  }
  • nz-radio 和 nz-radio-group都是共用这个NzRadioService,且组件内init时都有对selected$这个流做监听
@Injectable()
export class NzRadioService {
  selected$ = new ReplaySubject<NzSafeAny>(1);
  touched$ = new Subject<void>();
  disabled$ = new ReplaySubject<boolean>(1);
  name$ = new ReplaySubject<string>(1);
  touch(): void {
    this.touched$.next();
  }
  select(value: NzSafeAny): void {
    this.selected$.next(value);
  }
  setDisabled(value: boolean): void {
    this.disabled$.next(value);
  }
  setName(value: string): void {
    this.name$.next(value);
  }
}
// radio.component.ts ====> ngOnInit
this.nzRadioService.selected$.pipe(takeUntil(this.destroy$)).subscribe(value => {
        const isChecked = this.isChecked;
        this.isChecked = this.nzValue === value;
        // We don't have to run `onChange()` on each `nz-radio` button whenever the `selected$` emits.
        // If we have 8 `nz-radio` buttons within the `nz-radio-group` and they're all connected with
        // `ngModel` or `formControl` then `onChange()` will be called 8 times for each `nz-radio` button.
        // We prevent this by checking if `isChecked` has been changed or not.
        if (
          this.isNgModel &&
          isChecked !== this.isChecked &&
          // We're only intereted if `isChecked` has been changed to `false` value to emit `false` to the ascendant form,
          // since we already emit `true` within the `setupClickListener`.
          this.isChecked === false
        ) {
          this.onChange(false);
        }
        this.cdr.markForCheck();
      });
  • 当监听完值改变后,后面又执行了radio的click事件,把点击哪个radio的value值传过去了,所以之前的清空值操作就被覆盖了。
private setupClickListener(): void {
    this.ngZone.runOutsideAngular(() => {
      fromEvent<MouseEvent>(this.elementRef.nativeElement, 'click')
        .pipe(takeUntil(this.destroy$))
        .subscribe(event => {
          /** prevent label click triggered twice. **/
          event.stopPropagation();
          event.preventDefault();
          if (this.nzDisabled || this.isChecked) {
            return;
          }
          this.ngZone.run(() => {
            // !!! again  
            this.nzRadioService?.select(this.nzValue);
            if (this.isNgModel) {
              this.isChecked = true;
              this.onChange(true);
            }
            this.cdr.markForCheck();
          });
        });
    });
  }

解决方法

清空值的操作加setTimeout 使组件库内部先执行完click后续再执行。

import { Component } from '@angular/core';
@Component({
selector: 'nz-demo-radio-radiogroup',
template: `
  <nz-radio-group [(ngModel)]="radioValue">
    <label nz-radio (click)="click('A')" nzValue="A">A</label>
    <label nz-radio nzValue="B">B</label>
    <label nz-radio nzValue="C">C</label>
    <label nz-radio nzValue="D">D</label>
  </nz-radio-group>
`
})
export class NzDemoRadioRadiogroupComponent {
radioValue = 'A';
click(value: any) {
  if (this.radioValue === value) {
    setTimeout(()=>{
      this.radioValue = ''
    })
  }
}
}

总结

其实组件库单选radio本身是不支持取消选择的,正解应该是用checkbox实现相关的业务逻辑才对,但很久之前的业务逻辑涉及到很多地方的修改,此时再换checkbox并且换样式的话,改动的还是比较大的,就先简单解决这个问题。

相关文章

  • Angular跨字段验证器中如何直接调用其它独立的验证器

    Angular跨字段验证器中如何直接调用其它独立的验证器

    我们在开发的时候都会用到表单,那么验证器就是必不可少的东西,这篇文章主要给大家介绍了关于在Angular跨字段验证器中如何直接调用其它独立的验证器的相关资料,需要的朋友可以参考下
    2022-03-03
  • Angularjs注入拦截器实现Loading效果

    Angularjs注入拦截器实现Loading效果

    angularjs作为一个全ajax的框架,对于请求,如果页面上不做任何操作的话,在结果反回来之前,页面是没有任何响应的,不像普通的HTTP请求,会有进度条之类
    2015-12-12
  • 详解AngularJS中的filter过滤器用法

    详解AngularJS中的filter过滤器用法

    这篇文章主要介绍了AngularJS中的filter过滤器用法,包括其在模版中和在controller以及service的常见应用场合,需要的朋友可以参考下
    2016-01-01
  • 简单谈谈Angular中的独立组件的使用

    简单谈谈Angular中的独立组件的使用

    这篇文章主要介绍了简单谈谈Angular中的独立组件的使用的相关资料,通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,需要的朋友可以参考下
    2022-08-08
  • AngularJS中使用three.js的实例详解

    AngularJS中使用three.js的实例详解

    这篇文章主要介绍了AngularJS中使用three.js的实例详解,我将之前自己做的demo放到了angularJS的一个component中,其实一开始是没有准备用框架的但是后面发现需要进行的双向绑定越来越多,后期表单数据的变化量也很大,最后还是选择用NG来做这些事情
    2017-07-07
  • AngularJS实现controller控制器间共享数据的方法示例

    AngularJS实现controller控制器间共享数据的方法示例

    这篇文章主要介绍了AngularJS实现controller控制器间共享数据的方法,结合简单实例形式分析了AngularJS控制器数据共享的实现方法,需要的朋友可以参考下
    2017-10-10
  • Angularjs实现分页和分页算法的示例代码

    Angularjs实现分页和分页算法的示例代码

    分页是很多web应用都会用到的,本篇文章主要介绍了Angularjs实现分页和分页算法的示例代码,具有一定的参考价值,有兴趣的可以了解一下。
    2016-12-12
  • angular实现商品筛选功能

    angular实现商品筛选功能

    这篇文章主要为大家详细介绍了angular实现商品筛选功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-02-02
  • Angular8 Http拦截器简单使用教程

    Angular8 Http拦截器简单使用教程

    这篇文章主要介绍了Angular8 Http拦截器简单使用教程,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-08-08
  • AngularJs concepts详解及示例代码

    AngularJs concepts详解及示例代码

    本文主要介绍AngularJs concepts,这里整理了详细资料及简单示例代码来讲解相关知识,有学习这部分知识的朋友可以参考下
    2016-09-09

最新评论