我正在编写一个使用Ionic的混合应用程序,带有独立的模块和 capacitor (请注意,我是个新手,所以并不是所有的东西都是完美的).我在浏览器中测试时不会出现复选框问题,但在真正的Android设备上会出现.

Background and code

我有一个名为"new-view"的页面组件,它允许创建新的医疗访问或更新现有的医疗访问.根据url参数,我可以使用默认值创建表单,也可以使用现有访问中的数据填充表单.

export class NewVisitPage implements OnInit {

  editMode: boolean = false;
  private existingVisit: VisitModel | undefined = undefined;
  private customers: CustomerDetails[] = [];
  public selectedCustomer: CustomerDetails | null = null;
  public customerSearchField: FormControl;
  public allowCustomerChange: boolean = true;

  constructor(
    private formBuilder: FormBuilder,
    private visitService: VisitsService,
    private route: ActivatedRoute,
    private customersService: CustomersService,
    private navCtrl: NavController,
    private toastCtrl: ToastController,
    private menuCtrl: MenuController) {
    this.customerSearchField = new FormControl('');
  }

  visitDataForm: FormGroup = this.formBuilder.group({
    customerId: ['', Validators.required],
    medicines: '',
    description: '',
    date: [moment().format('YYYY-MM-DD'), Validators.required],
    amount: 0,
    hasDebt: false,
    debtAmount: 0,
    debtPaidAmount: 0
  })

  ngOnInit() {
    addIcons(icons);

    this.visitDataForm.reset();

    this.route.queryParamMap.subscribe(params => {
      const customerId = params.get('customerId');
      if (customerId) {
        this.selectedCustomer = this.customersService.getCustomerById(customerId);
        this.customerId?.setValue(customerId);
        this.allowCustomerChange = false;
      }
    })

    this.route.paramMap.subscribe(params => {
      let date = params.get('date');
      if (date) {
        this.visitDataForm.get('date')!.setValue(date)
      }

      let id = params.get('id');
      if (id) {
        this.editMode = true;
        this.existingVisit = this.visitService.getById(id);
        if (!this.existingVisit)
          throw 'visit not found';

        this.visitDataForm.get('customerId')?.setValue(this.existingVisit.customerDetails.id);
        this.visitDataForm.get('medicines')?.setValue(this.existingVisit.medicines);
        this.visitDataForm.get('description')?.setValue(this.existingVisit.description);
        this.visitDataForm.get('date')?.setValue(moment(this.existingVisit.date).format('YYYY-MM-DD'));
        this.visitDataForm.get('amount')?.setValue(this.existingVisit.amount);
        this.visitDataForm.get('hasDebt')?.setValue(!!this.existingVisit.debt);
        this.visitDataForm.get('debtAmount')?.setValue(this.existingVisit.debt?.amount || 0);
        this.visitDataForm.get('debtPaidAmount')?.setValue(this.existingVisit.debt?.amountPaid || 0);

        this.selectedCustomer = this.customersService.getCustomerById(this.existingVisit.customerDetails.id);
      }
    });
  }

  get hasDebt() {
    return this.visitDataForm.get('hasDebt')!.value;
  }

  get customerId() {
    return this.visitDataForm.get('customerId')!;
  }

// ...

然后,在UI端的Form元素中,我有一个复选框允许 Select 客户是支付了整个访问的费用还是欠了一些债务.根据复选框的值,我要么显示用于编辑债务金额的文本框,要么不显示.

<ion-item lines="full">
  <ion-checkbox labelPlacement="end" formControlName="hasDebt">
    <div class="ion-text-wrap">Amount was not fully paid</div>
  </ion-checkbox>
</ion-item>

<ion-item *ngIf="hasDebt">
  <ion-label position="floating">Debt amount</ion-label>
  <ion-input type="number" step="0.01" min="0" formControlName="debtAmount"></ion-input>
</ion-item>
<ion-item *ngIf="hasDebt && editMode">
  <ion-label position="floating">Paid amount</ion-label>
  <ion-input type="number" step="0.01" min="0" formControlName="debtPaidAmount"></ion-input>
</ion-item>

The issue

当我在浏览器中运行ng serve的应用程序时,一切都运行正常.当我将复选框标记为选中时,字段可见,否则不可见.

然而,在Android上,它只有在创建新的访问时才起作用.当我try 编辑现有的复选框时,它会随机停止工作-我可以更改复选框值,并且我可以看到复选框本身的视觉效果,但在最小化应用程序之前,"ngIf"部分不起作用.它似乎只在最小化应用程序的时刻触发"ngif".

推荐答案

这看起来像是一个Angular Change Detection问题,但可能还有另一个潜在的问题.

1.Try production mode on

当运行ng serve时,应用程序很可能处于调试模式,因此更容易容忍一些运行时错误.你可以try 在prod模式下运行ng serve --configuration=production.根据您的构建,构建模式使用生产模式.您可能会发现发生的任何潜在错误,并可能复制错误.

2.Manually detect changes on checkbox value change

看看手动触发更改检测是否可以修复它.

    // add to constructor
    private changeDetector: ChangeDetectorRef


    // add inside your ngOnInit function
    this.visitDataForm.get('hasDebt').valueChanges.subscribe(()=> {
      this.changeDetector.detectChanges();
    })

3.ChangeDetectionStrategy

如果您的更改检测策略设置为OnPush,则组件中的getter可能无法按您预期的方式工作,将其设置回默认设置应该可以修复该问题.

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
...

4.Fixing underlying detection issue

这个吸入器可能不会像预期的那样工作.更改检测最适合基本值,而不是对象引用.即使该值已更改,在这种情况下,Angular 可能无法从对象的引用跟踪它.

  get hasDebt() {
    return this.visitDataForm.get('hasDebt')!.value;
  }

您可以创建自己的原语来代替这个getter,例如

import {
  startWith,
} from 'rxjs';

hasDebt$ = this.visitDataForm.get('hasDebt').valueChanges.pipe(startWith(this.visitDataForm.get('hasDebt').value))
<ion-item *ngIf="hasDebt">

变成:

<ion-item *ngIf="hasDebt$ | async">

这样,您就可以继续高效地进行更改检测

Android相关问答推荐

如何将文本相对于喷气背包中的图标垂直居中?

Jetpack编写:通过viewModels()vs viewModel View ModernName()'

Android可绘制边框删除底线

无法加载类';com.android.build.api.extension.AndroidComponentsExtension';

如何在使用带有底部导航组件的片段管理器时更改片段工具栏的标签

Android v31 及更低版本中 ImageView 中的圆角

Camera2 将图像从 ImageReader 传递到 MediaRecorder

可组合函数无限地从视图模型获取值

在本地通知中设置自定义声音

我的自定义小吃店不适合我的全宽屏幕尺寸

在 Jetpack Compose 的无状态 Compose 中管理条件逻辑

如何像 XML 一样在 Compose Android Studio 中折叠/展开小部件代码区域/区域

Android Transitions API - 在 24-48 小时后停止接收任何更新

MediumTopAppBar Material3 只更改大标题

Int 传递给 Intent 但Android工作室说我传递了一个字符串

我的 react native 项目的发布签名 apk 没有在设备中打开,而且它创建的尺寸非常小

为什么按钮没有拉伸到屏幕边缘?

如何删除 Ktor 客户端 2.0.0 的默认标头

升级到 android studio 花栗鼠后,应用程序未安装在模拟器中

使用 Android 字符串数组在 Room 中迁移