Angular – 直到输出回调结束后,属性值的更改才会被忽略。

huangapple go评论63阅读模式
英文:

Angular - change of property value ignored until output callback ends

问题

我有一个组件,应该在操作进行时显示一些加载符号:

html:

<spinner *ngIf='isLoading'></spinner>
<xx-table
  (onSort)='onSort()'>
</xx-table>

Component.ts:

onSort(): void {
  this.isLoading = true;
  // 操作大约需要1秒
  this.isLoading = false;
}

我有一行代码明确将this.isLoading的值更改为true,但模板永远不会检测到这个更改。

似乎只有在onSort()方法完成后才会触发变更检测 - 如果我删除this.isLoading = false;这一行,加载符号会显示(并保持显示),但在约1秒后(操作的持续时间)才会消失。

如何在方法仍在执行时使此更改可见?这背后的确切机制是什么?

(我知道我可以手动触发变更检测,但为什么这不被识别为更改?)

英文:

I have component that should display some spinner while operation takes place:

html:

<spinner *ngIf='isLoading'></spinner>
<xx-table
  (onSort)='onSort()'>
</xx-table>

Component.ts:

onSort(): void {
  this.isLoading = true;
  // operation lasting around 1 second
  this.isLoading = false;
}

I have a line that explicitly changes value of this.isLoading to true however this change is never detected by the template.

Seems like change detection is triggered only after onSort() method is finished - if I remove line this.isLoading = false; spinner is shown (and stays there) but after the ~1 second (duration of the operation that takes place)

How to make this change visible while method is still executing? And what exact mechanism is behind this?

(I know I can trigger change detection manually, but why this is not recognized as change?)

答案1

得分: 1

这个isLoading = false; 需要放在promise/observable的subscribe结束部分:在你的示例中,this.isLoading = true 直接跟在 = false 后面,因为你没有等待promise结束才进行这个赋值。

// 大约持续1秒的操作
是异步代码。查看如何在JavaScript中处理promise/Observable以理解这个概念。

英文:
this.isLoading = false;

needs to be at the end of the promise/observable subscribe: In your example, this.isLoading = true is directly followed by = false because you are not waiting for the end of the promise to do that assigment.

// operation lasting around 1 second

is asynch code. Look how to handle promise/Observable in JS to understand the concept.

答案2

得分: 1

A block of javascript code will continue executing until it completes, there is only one execution path. It looks like your code is synchronous and there are no async operations, so control is never returned to angular to update the page while isLoading is true.

你的 JavaScript 代码块将一直执行,直到完成,只有一个执行路径。看起来你的代码是同步的,没有异步操作,因此在 isLoading 为 true 时,控制不会返回给 Angular 来更新页面。

You can use setTimeout to schedule code to run after a certain number of milliseconds, or with '0' when the current execution path and pending events are handled by the JavaScript runtime:

你可以使用 setTimeout 来安排代码在一定毫秒数之后运行,或者使用 '0',这时当前的执行路径和未处理的事件将由 JavaScript 运行时处理:

  doSomething(): void {
    this.isLoading = true  // never shows
    this.expensiveOperation() // completes executing before updating UI
    this.isLoading = false // when this function ends, isLoading is still false
  }
  
  doSomethingAsync(): void{
    this.isLoading = true
    setTimeout(() => { // let UI process changes, then do work
      this.expensiveOperation()
      this.isLoading = false
    }, 0)
  }
  doSomething(): void {
    this.isLoading = true  // 永远不会显示
    this.expensiveOperation() // 在更新 UI 之前完成执行
    this.isLoading = false // 当此函数结束时,isLoading 仍然为 false
  }
  
  doSomethingAsync(): void{
    this.isLoading = true
    setTimeout(() => { // 让 UI 处理变化,然后执行工作
      this.expensiveOperation()
      this.isLoading = false
    }, 0)
  }
英文:

A block of javascript code will continue executing until it completes, there is only one execution path. It looks like your code is synchronous and there are no async operations, so control is never returned to angular to update the page while isLoading is true.

You can use setTimeout to schedule code to run after a certain number of milliseconds, or with '0' when the current execution path and pending events are handled by the javascript runtime:

  doSomething(): void {
    this.isLoading = true  // never shows
    this.expensiveOperation() // completes executing before updating UI
    this.isLoading = false // when this function ends, isLoading is still false
  }
  
  doSomethingAsync(): void{
    this.isLoading = true
    setTimeout(() => { // let UI process changes, then do work
      this.expensiveOperation()
      this.isLoading = false
    }, 0)
  }

huangapple
  • 本文由 发表于 2023年5月24日 21:31:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76324103.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定