开发者问题收集

如何在以编程方式检查 HTML 复选框元素之前正确等待其加载?

2020-04-22
346

我想在用户进入页面时动态激活一些复选框。为此,我将 HTML 复选框元素的 ID 保存在服务中。当用户进入页面时,将访问此服务并返回包含这些 ID 的数组。在每个循环中检查活动元素。

this.platform.ready().then(() => {
    let checboxState = this.service.checboxState;
    if (checboxState !== undefined && checboxState.length > 0) {
        checboxState.forEach(checbox => {
            let element = document.getElementById(checbox.id) as HTMLInputElement;
            element.checked = true;
        });
    }
});

但我收到此错误:

Uncaught (in promise): TypeError: Cannot set property 'checked' of null

这可能表明 Javascript 函数在加载 DOM 之前触发。如果是这样,为什么 platform.ready() 不起作用?我也尝试过: - document.addEventListener("DOMContentLoaded",() => {} - window.onload = () => {}>

但没有成功。


我设法通过在函数前添加 setTimeout() 来使该函数正常工作,那么如何在触发 JS 函数之前正确等待 HTML 元素加载?


页面中的复选框由 *ngFor 函数加载。

2个回答

当复选框通过 *ngFor 循环添加到 DOM 时,为了得到通知:

  1. 为复选框元素分配一个模板引用变量(例如 #chk
  2. 借助 ViewChildren 将复选框元素关联到 QueryList >
  3. ngAfterViewInit 中订阅 QueryList.changes 可观察对象,并在回调中处理复选框列表。您还可以直接在 ngAfterViewInit 中检查,以解决复选框元素已呈现的情况
<input type="checkbox" #chk *ngFor="let id of idList" [id]="id">
@ViewChildren("chk") private checkboxList: QueryList<ElementRef<HTMLInputElement>>;

...

ngAfterViewInit() {
  // Check if the checkbox is already in the DOM
  this.findCheckBoxWithId("chk36");            

  // Find the checkbox if rendered after a delay
  this.checkboxList.changes.subscribe(() => {
    this.findCheckBoxWithId("chk36");          
  });
}

findCheckBoxWithId(id) {
  const checkbox = this.checkboxList.find(x => x.nativeElement.id === id);
  ...
}

请参阅 此 stackblitz 以获取演示

ConnorsFan
2020-04-22

或者,在 ConnorsFan 的答案 的基础上,使用可观察对象:

@ViewChildren('chk') private checkboxQueryList: QueryList<ElementRef<HTMLInputElement>>;
checkbox$: Observable<HTMLInputElement>;

...

ngAfterViewInit(): void {
  this.checkbox$ = this.observableFromQueryListFind(
    this.checkboxQueryList,
    x => x.nativeElement.id === 'chk36',
  );
}

...

observableFromQueryListFind<T>(
  queryList: QueryList<T>,
  fn: (item: T, index: number, array: T[]) => boolean,
): Observable<T> {
  const item = queryList.find(fn);
  if (item) {
    return concat(
      of(item),
      queryList.changes
        .pipe(
          map((queryList: QueryList<T>) => queryList.find(fn)),
        ),
    );
  } else {
    return queryList.changes
      .pipe(
        map((queryList: QueryList<T>) => queryList.find(fn)),
      );
  }
}

此答案代码未经测试,但基于工作代码库中 80-90% 相似的代码。

hlovdal
2023-03-31