return FALSE; $r = well_tag_thread__update(array('id' => $id), $update); return $r; } function well_tag_thread_find($tagid, $page, $pagesize) { $arr = well_tag_thread__find(array('tagid' => $tagid), array('id' => -1), $page, $pagesize); return $arr; } function well_tag_thread_find_by_tid($tid, $page, $pagesize) { $arr = well_tag_thread__find(array('tid' => $tid), array(), $page, $pagesize); return $arr; } ?>javascript - Angular Reactive Form - setErrors not updating view for FormControls inside FormArray when OnPush is used - Stack O
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Angular Reactive Form - setErrors not updating view for FormControls inside FormArray when OnPush is used - Stack O

programmeradmin2浏览0评论

It is an interesting behaviour I tried in multiple projects and gave up using OnPush for FormArray, more specific it is an arry of row of FormGrop contains FormControl. However, I think it is time to raise a question here so that it maybe same issue for others (or just me too stupid that forget a simple tiny line of code, please point it out if so, thanks), I created a mockup here: stackblitz

For some reason my project using OnPush for all such dummy ponnents which needs manually call ChangeDetectionRef.markForCheck if a View Update is required. But this time wherever I put the mark it doesn't show any differece.

Generally, I created a save$ Subject to do a validation on the fly and save the whole Grid to somewhere if it is valid. Now, since save$ is a BehaviourSubject which means it is called once the form is built. You can see the whole FormGroup is invalid on the screen but all cells are valid, which is weird.

It is an interesting behaviour I tried in multiple projects and gave up using OnPush for FormArray, more specific it is an arry of row of FormGrop contains FormControl. However, I think it is time to raise a question here so that it maybe same issue for others (or just me too stupid that forget a simple tiny line of code, please point it out if so, thanks), I created a mockup here: stackblitz

For some reason my project using OnPush for all such dummy ponnents which needs manually call ChangeDetectionRef.markForCheck if a View Update is required. But this time wherever I put the mark it doesn't show any differece.

Generally, I created a save$ Subject to do a validation on the fly and save the whole Grid to somewhere if it is valid. Now, since save$ is a BehaviourSubject which means it is called once the form is built. You can see the whole FormGroup is invalid on the screen but all cells are valid, which is weird.

Share Improve this question asked Nov 25, 2022 at 1:02 VincentVincent 1,3321 gold badge15 silver badges29 bronze badges 9
  • I think it's from your code. Changing it back to Default will trigger ng100 error. And if you leave OnPush and trigger CD yourself (via a button), you will see it reset the whole state, error -> null -> form bee valid whenever CD run. – Jimmy Commented Nov 25, 2022 at 21:50
  • @Jimmy Any idea how it should be refactored? – Vincent Commented Dec 8, 2022 at 2:18
  • I could give you the simplest, also a hack for this: setTimeout. Use setTimeout when you call control.setError. setTimeout(() => { control.setErrors(Object.keys(errors).length ? errors : null); }) – Jimmy Commented Dec 8, 2022 at 18:13
  • If you want more details, just let me know, I will write the answer – Jimmy Commented Dec 8, 2022 at 18:14
  • @Jimmy many thanks for your ments, but the first time build grid still shows valid on each row and the grid bees valid, which is not right. – Vincent Commented Dec 9, 2022 at 23:00
 |  Show 4 more ments

1 Answer 1

Reset to default 6 +50

The reason I mentioned about "non onpush" is because with that mode, Angular runs CD for you. And if your code works as expected in default mode, it means, your "onpush" code just needed to trigger CD.
I didn't mean to tell you that you should switch to default mode.

For why it didn't work in your original question:
The form itself, by default run updateValueAndValidity after initialized, you don't declare any validators => the form status is valid; then you call setErrors which behind the scene, set the from status to false => this cause the inconsistency in the view, hence the ng100 error.

//Edit:
I debugged the flow again and found out that after each control gets added to the form, it will run the updateValueAndValidity function again. Which means, the setErrors will cause the form to be Invalid first, then updateValueAndValidity will make it all Valid again. The inconsistency is still there, just the other way around.
//End Edit

The dirty hack for this is using setTimeout, which I personally don't like and don't remend. But to give a properly solution, it will require to know the business logic in the code.

Here it is the code I posted in the ment.

setTimeout(() => {
        control.setErrors(Object.keys(errors).length ? errors : null);        
});

This helps to schedule the setError (which actually, the valid status) to run in the next CD round.
This code doesn't have any CD yet. So yes, the form is valid all the time => That's the reason I tell you to create a button to see the CD in action.

Now we wouldn't want a new button for users to click to see the form update. We need to run the CD in code. So where to put it?
We know the setError trigger the form status so we will schedule it later, and where does the setError get invoked? customValidator, we will schedule this function to run later so the final code to modify is here:

//instead of run setTimeout in a loop
//we make sure that all setError is scheduled in one run
setTimeout(() => {
      customValidator()(form);
      this.cd.markForCheck();
    })

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论