___식을 확인한 후 식이 변경되었습니다.
이 단순한 플랭크에 컴포넌트가 있는 이유는 무엇입니까?
@Component({
selector: 'my-app',
template: `<div>I'm {{message}} </div>`,
})
export class App {
message:string = 'loading :(';
ngAfterViewInit() {
this.updateMessage();
}
updateMessage(){
this.message = 'all done loading :)'
}
}
던지기:
예외: App@0:5의 'I'm {{message}}' 표현은 확인 후 변경되었습니다.이전 값 : [App@0:5]의 [I'm {{message}}]의 [I'm loading :(. 현재 값 :)]의 [I all done loading :)]의 [I'm {message}]의 [I'm loading : ('.
뷰가 시작되었을 때 간단한 바인딩을 업데이트하는 것 뿐인데?
와 같이 이 componentdrawmoore의 입니다.은 「」를 .detectChanges()
의 of의 ChangeDetectorRef
「」( 「」angular2/core
그 ).markForCheck()
method: 부모 컴포넌트도 갱신합니다.관련 예:
import { Component, ChangeDetectorRef, AfterViewInit } from 'angular2/core'
@Component({
selector: 'my-app',
template: `<div>I'm {{message}} </div>`,
})
export class App implements AfterViewInit {
message: string = 'loading :(';
constructor(private cdr: ChangeDetectorRef) {}
ngAfterViewInit() {
this.message = 'all done loading :)'
this.cdr.detectChanges();
}
}
여기에서는 만약을 위해 ngOnInit, setTimeout 및 enableProdMode 접근 방식을 보여주는 플런커도 보여 줍니다.
첫째, 이 예외는 앱을 개발 모드로 실행할 때만 발생한다는 점에 유의하십시오(베타 0의 경우 기본적으로 해당).앱을 부트스트랩할 때 호출하면 앱이 느려지지 않습니다(업데이트된 플랭크 참조).
둘째, 이 예외는 타당한 이유로 발생하므로 이 작업을 수행하지 마십시오.즉, dev 모드일 경우 모든 변경 검출 라운드에 즉시 이어 첫 번째 라운드가 종료된 이후 바인딩이 변경되지 않았음을 확인하는 두 번째 라운드가 실행됩니다.이것은 변경 검출 자체에 의해 변경이 발생하고 있음을 나타냅니다.
의 플랭크에서는 """ "" " " " " " " " " " " "{{message}}
'이러다'로 됩니다.setMessage()
에서 발생합니다.ngAfterViewInit
훅 - 초기 변경 감지 턴의 일부로 발생합니다.는 그 자체가 문제라는 이다.setMessage()
는 바인딩을 변경하지만 새로운 변경 검출을 트리거하지 않습니다.즉, 이 변경은 향후의 변경 검출이 다른 장소에서 트리거될 때까지 검출되지 않습니다.
요점:바인딩을 변경하는 경우 변경 시 변경 검출 라운드를 트리거해야 합니다.
그 방법의 예에 대한 모든 요구에 따라 갱신합니다.@Tycho의 솔루션은 @MarkRajcok이 지적한 답변의 3가지 방법과 마찬가지로 작동합니다.하지만 솔직히 말해서, 그들은 모두 못생기고 잘못되었다고 느껴요. 우리가 ng1에 의지하는 것에 익숙해진 해커들처럼요.
물론, 이러한 해킹이 적절한 경우도 있지만, 아주 가끔이 아닌 다른 방법으로 이러한 해킹을 사용하고 있다면, 이는 여러분이 프레임워크의 반응적 성격을 완전히 수용하기 보다는 프레임워크와 싸우고 있다는 신호입니다.
IMHO, 좀 더 관용적인 표현인 "Angular 2 way"는 다음과 같은 방식으로 접근합니다. (플랭크)
@Component({
selector: 'my-app',
template: `<div>I'm {{message | async}} </div>`
})
export class App {
message:Subject<string> = new BehaviorSubject('loading :(');
ngAfterViewInit() {
this.message.next('all done loading :)')
}
}
ngAfterViewChecked()
: 작업 완료:
import { Component, ChangeDetectorRef } from '@angular/core'; //import ChangeDetectorRef
constructor(private cdr: ChangeDetectorRef) { }
ngAfterViewChecked(){
//your code to update the model
this.cdr.detectChanges();
}
각도 코어에서 ChangeDetectionStrategy를 추가하여 수정하였습니다.
import { Component, ChangeDetectionStrategy } from '@angular/core';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'page1',
templateUrl: 'page1.html',
})
사용할 수 없습니까?ngOnInit
variable을 만 하면 .message
컴포넌트에 , 「」를 참조해 주세요.@ViewChild(ChildComponent)
''로 가 있어요ngAfterViewInit
.
는 '더티 픽스'를 호출하는 입니다.updateMessage()
set Timeout 음음음 。
ngAfterViewInit() {
setTimeout(() => {
this.updateMessage();
}, 1);
}
이 때문에, 상기의 답변을 시험해 보았습니다만, 최신 버전의 Angular(6 이상)에서는 동작하지 않는 경우가 많습니다.
처음 바인딩이 완료된 후 변경이 필요한 재료관리를 사용하고 있습니다.
export class AbcClass implements OnInit, AfterContentChecked{
constructor(private ref: ChangeDetectorRef) {}
ngOnInit(){
// your tasks
}
ngAfterContentChecked() {
this.ref.detectChanges();
}
}
제 답변에 덧붙여, 이것은 특정 문제를 해결하는 데 도움이 됩니다.
AfterView에서 전환했습니다.Init to After Content Checked로 전환하여 작동하였습니다.
이 과정은 다음과 같습니다.
생성자에 종속성 추가:
constructor (private cdr: ChangeDetectorRef) {}
구현된 메서드코드에 로그인해 주세요.
ngAfterContentChecked() { this.cdr.detectChanges(); // call or add here your code }
"Everything you need to knowled to the error" (오류에 대해 알아야 할 모든 것) 기사에서는 동작에 대해 자세히 설명합니다.
는 '''라는 것'''ngAfterViewInit
라이프 사이클 훅은 변경 검출 처리 후의 DOM 갱신 후에 실행됩니다.또한 이 후크에서 템플릿에 사용되는 속성을 효과적으로 변경할 수 있습니다. 즉, DOM을 다시 렌더링해야 합니다.
ngAfterViewInit() {
this.message = 'all done loading :)'; // needs to be rendered the DOM
}
이를 위해서는 또 다른 변경 감지 사이클이 필요하며 Angular는 기본적으로 하나의 다이제스트 사이클만 실행합니다.
기본적으로 다음 두 가지 방법으로 해결할 수 있습니다.
으로 속성을 갱신하다
setTimeout
,Promise.then
가능DOM 업데이트 전에 후크에서 속성 업데이트를 수행합니다(ngOnInit, ngDoCheck, ngAfterContent).Init, ng After Content Checked.
이 오류는 초기화 직후 기존 값이 업데이트되기 때문에 발생합니다.따라서 기존 값이 DOM에 렌더링된 후 새 값을 업데이트하면 정상적으로 작동합니다.이 문서에서 언급한 바와 같이 각도 디버깅 "체크된 후 식이 변경되었습니다."
예를 들어,
ngOnInit() {
setTimeout(() => {
//code for your new value.
});
}
또는
ngAfterViewInit() {
this.paginator.page
.pipe(
startWith(null),
delay(0),
tap(() => this.dataSource.loadLessons(...))
).subscribe();
}
보시다시피 set Timeout 메서드에서 시간을 언급하지 않았습니다.JavaScript API가 아닌 브라우저 제공 API이기 때문에 브라우저 스택에서 별도로 실행되며 콜 스택 항목이 완료될 때까지 기다립니다.
브라우저 API가 어떻게 컨셉을 부러워하는지는 필립 로버츠가 유튜브 동영상 중 하나(What the hack is event loop?)에서 설명하고 있습니다.
사이클훅에서 이 경우는, 「」입니다.ngAfterContentChecked
ngAfterViewInit
ngAfterViewngAfterView에서 되지 않았기 변수 메시지 검사가 시작되었지만 아직 종료되지 않았습니다.
참조: https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html#!#afterview
따라서 코드는 다음과 같습니다.
import { Component } from 'angular2/core'
@Component({
selector: 'my-app',
template: `<div>I'm {{message}} </div>`,
})
export class App {
message: string = 'loading :(';
ngAfterContentChecked() {
this.message = 'all done loading :)'
}
}
Plunker의 작업 데모를 참조하십시오.
ngOnInt()-Method에서 updateMessage()에 콜을 발신할 수도 있습니다.적어도 저는 이 방법이 유효합니다.
ngOnInit() {
this.updateMessage();
}
RC1에서는 예외가 트리거되지 않습니다.
rxjs 를 .Observable.timer
수행하고하십시오.
Observable.timer(1).subscribe(()=> this.updateMessage());
ngAfterViewInit()가 호출되면 코드가 갱신되기 때문에 오류가 발생합니다.ngAfterView에서 초기값이 변경되었음을 의미합니다.init이 실행됩니다.ngAfterContentInit()로 호출하면 오류가 발생하지 않습니다.
ngAfterContentInit() {
this.updateMessage();
}
심플: 컴포넌트 구성 시 변경 검출을 먼저 분리/제거한 후 활성화detectChanges()
ngAfterViewInit()
constructor(private cdr: ChangeDetectorRef) {
this.cdr.detach() // detach/remove the change detection here in constructor
}
ngAfterViewInit(): void {
// do load objects or other logics here
// at the end of this method, call detectChanges() method.
this.cdr.detectChanges(); // enable detectChanges here and you're done.
}
거의 비슷한 케이스가 있고, 여러 가지 제품이 있습니다.사용자의 선택에 따라 제품을 제거할 수 있도록 해야 합니다.결국 어레이에 제품이 없으면 페이지를 새로고침하지 않고 뒤로 버튼 대신 취소 버튼을 표시해야 합니다.
ng After View Checked() 라이프 사이클 훅에 빈 배열이 없는지 확인했습니다.이렇게 했습니다. 도움이 되었으면 합니다. :)
import { ChangeDetectorRef } from '@angular/core';
products: Product[];
someCondition: boolean;
constructor(private cdr: ChangeDetectorRef) {}
ngAfterViewChecked() {
if(!this.someCondition) {
this.emptyArray();
}
}
emptyArray() {
this.someCondition = this.products.length === 0 ? true : false;
// run change detection explicitly
this.cdr.detectChanges();
}
removeProduct(productId: number) {
// your logic for removing product.
}
써보시면 됩니다.this.updateMessage();
아래ngOnInit
이렇게요.
ngOnInit(): void {
this.updateMessage();
}
저 같은 경우에는 p-radio Button으로 발생했어요.문제는 formControlName 속성과 함께 name 속성(불필요)을 다음과 같이 사용하고 있다는 것입니다.
<p-radioButton formControlName="isApplicant" name="isapplicant" value="T" label="Yes"></p-radioButton>
<p-radioButton formControlName="isApplicant" name="isapplicant" value="T" label="No"></p-radioButton>
또한 다음과 같이 초기값 "T"를 isApplicant 폼 컨트롤에 바인딩했습니다.
isApplicant: ["T"]
라디오 버튼의 이름 속성을 삭제하여 문제를 해결했습니다.또, 2개의 라디오 버튼의 값(T)이 같기 때문에, 어느쪽인가를 다른 값(F라고 하는 것)으로 변경하는 것만으로 문제가 해결되었습니다.
에러가 , 이 에러로 할 수 요.AfterViewInit
★★★★★★★★★★★★★★★★★」ChangeDetectionStrategy.OnPush
여기 상세한 기사가 있습니다.https://medium.com/ @bencabanes / https://medium.com/ - change - --- - --- - --- - 819 ctionction4e7
평판이 좋지 않아 @Biranchi의 투고에 코멘트를 할 수 없었지만, 문제가 해결되었습니다.
한 가지 주의할 점이 있습니다!changeDetection을 추가하는 경우: Change Detection Strategy.컴포넌트의 OnPush가 동작하지 않고 하위 컴포넌트(dumb 컴포넌트)도 부모 컴포넌트에 추가합니다.
이것으로 버그는 해결되었습니다만, 어떤 부작용이 있을까요?
데이터 테이블을 사용하는 동안 유사한 오류가 발생했습니다.다른 *ngFor를 사용하는 경우 *ngFor를 데이터 테이블 내에서 사용하면 각도 변경 사이클이 방해되므로 이 오류가 발생합니다.따라서 데이터 테이블 내에서 데이터 테이블을 사용하는 대신 하나의 일반 테이블을 사용하거나 mf.data를 어레이 이름으로 바꿉니다.이거 잘 돼.
가장 간단한 해결책은 다음과 같습니다.
- 함수 또는 설정기를 통해 일부 변수에 값을 할당하는 한 가지 구현을 수행합니다.
- 변수 " " 를 만듭니다.
(static working: boolean)
이 함수가 존재하는 클래스에서 함수를 호출할 때마다 원하는 대로 실행하기만 하면 됩니다.원하는 그렇지 않으면 원하는 작업을 수행합니다.작업이 완료되면(예: 코드 줄 끝 또는 값 할당을 완료한 경우) 이 변수를 false로 변경하십시오.
좋은 답변입니다.다만, 사용하고 있는 경우는, 다음과 같습니다.ChangeDetectorRef 및 AfterViewInit, Angular는 몇 번의 추가 렌더링 사이클에 들어갑니다.HTML 코드가 매우 신중하게 설계되지 않았거나 새로 고침에 따라 TS 코드로 기능하기 위한 여러 호출이 필요할 경우 뷰 렌더링에 대한 추가 호출이 수신되므로 추가 처리가 필요합니다.
여기 제가 사용하고 싶은 솔루션이 있습니다.왜냐하면 이 솔루션은 프로그램적으로 매우 심플하고 저나 시스템에서 추가로 필요한 것도 거의 없기 때문입니다.Angular가 "Expression has checked after it"이라는 악명 높은 오류로 인해 힘들 때마다 문제없이 사용하고 있습니다.
저는 이 작은 공개/내보내기 기능을 가지고 있습니다.이 기능은 단순히 지연이 없는 Promise를 통해 제 값을 전달합니다.이렇게 하면 JavaScript/JS가 강제로 다른 백그라운드 사이클로 전환되어 값 갱신이 다음 처리 사이클로 분리되고 오류가 발생하지 않습니다(JS 사이클은 Angular HTML 뷰 렌더링 사이클과 동일하지 않고 처리 부하가 낮다는 점에 유의하십시오).
export async function delayValue(v: any, timeOutMs: number = 0): Promise<any> {
return new Promise((resolve) => {
setTimeout(() => {
resolve(v);
}, timeOutMs);
});
}
에러를 방지하려면 , 다음의 조작을 실시합니다.
this.myClassValue = await delayValue(newValue);
코드 한 줄에 불과합니다.시간의 가치 이후 주목할 만한 지연은 없다.OutMs = 0.
일반적인 시나리오는 다음과 같습니다.
myObservable$.subscribe(newValue = {
... // WHEN NEW VALUE ARRIVES FROM NOTIFIER(S)
this.handleSubscribedValues(newValue);
...
});
// THIS MAY GIVE YOU THE ERROR !
private handleSubscribedValues(newValue) {
this.myClassValue = newValue;
}
// SO, USE THIS INSTEAD TO AVOID THE ERROR
private async handleSubscribedValues(newValue) {
this.myClassValue = await delayValue(newValue);
}
delayValue() 함수는 예를 들어 사용자에게 몇 초를 주는 등 어떤 일이 발생할 때까지 기다려야 할 경우 지연/타임아웃 값과 함께 사용할 수도 있습니다.
이것이 여러분들에게 유용하기를 바랍니다.
공유 서비스 제목을 변경하는 컴포넌트의 컨스트럭터로 코드를 이동하기만 하면 됩니다.
언급URL : https://stackoverflow.com/questions/34364880/expression-has-changed-after-it-was-checked
'bestsource' 카테고리의 다른 글
GWT와 Flex의 비교 (0) | 2023.02.17 |
---|---|
Mongodb 집약 프레임워크 설명 (0) | 2023.02.17 |
WordPress 관리 섹션에 새 페이지 추가 (0) | 2023.02.17 |
JavaScript는 json에서 키와 값을 반복합니까? (0) | 2023.02.13 |
Simple에서 JSON 읽기HTTPServer Post 데이터 (0) | 2023.02.13 |