refactor(ivy): move bindingIndex
from LView
to LFrame
(#33235)
`bindingIndex` stores the current location of the bindings in the template function. Because it used to be stored in `LView` that `LView` was not reentrant. This could happen if a binding was a getter and had a side-effect of calling `detectChanges()`. By moving the `bindingIndex` to `LFrame` where all of the global state is kept in reentrant way we correct the issue. PR Close #33235
This commit is contained in:

committed by
Andrew Kushnir

parent
c61f413477
commit
e16f75db56
@ -127,6 +127,53 @@ describe('change detection', () => {
|
||||
fixture.detectChanges(false);
|
||||
expect(fixture.nativeElement).toHaveText('1|dynamic');
|
||||
});
|
||||
|
||||
it('should support re-enterant change detection', () => {
|
||||
@Component({
|
||||
selector: 'has-host-binding',
|
||||
template: '..',
|
||||
host: {
|
||||
'[class.x]': 'x',
|
||||
}
|
||||
})
|
||||
class HasHostBinding {
|
||||
x = true;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'child',
|
||||
template: '<has-host-binding></has-host-binding>',
|
||||
inputs: ['input'],
|
||||
})
|
||||
class Child {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
private _input !: number;
|
||||
|
||||
constructor(private cdr: ChangeDetectorRef) {}
|
||||
|
||||
get input() { return this._input; }
|
||||
|
||||
set input(value: number) {
|
||||
this._input = value;
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'root',
|
||||
template: '<child [input]="3"></child>',
|
||||
})
|
||||
class Root {
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [Root, Child, HasHostBinding],
|
||||
});
|
||||
|
||||
TestBed.createComponent(Root).detectChanges();
|
||||
});
|
||||
});
|
||||
|
||||
describe('OnPush', () => {
|
||||
|
@ -2,9 +2,6 @@
|
||||
{
|
||||
"name": "ACTIVE_INDEX"
|
||||
},
|
||||
{
|
||||
"name": "BINDING_INDEX"
|
||||
},
|
||||
{
|
||||
"name": "BLOOM_MASK"
|
||||
},
|
||||
@ -608,6 +605,9 @@
|
||||
{
|
||||
"name": "setActiveHostElement"
|
||||
},
|
||||
{
|
||||
"name": "setBindingIndex"
|
||||
},
|
||||
{
|
||||
"name": "setBindingRoot"
|
||||
},
|
||||
|
@ -2,9 +2,6 @@
|
||||
{
|
||||
"name": "ACTIVE_INDEX"
|
||||
},
|
||||
{
|
||||
"name": "BINDING_INDEX"
|
||||
},
|
||||
{
|
||||
"name": "BLOOM_MASK"
|
||||
},
|
||||
@ -437,6 +434,9 @@
|
||||
{
|
||||
"name": "setActiveHostElement"
|
||||
},
|
||||
{
|
||||
"name": "setBindingIndex"
|
||||
},
|
||||
{
|
||||
"name": "setBindingRoot"
|
||||
},
|
||||
|
@ -2,9 +2,6 @@
|
||||
{
|
||||
"name": "ACTIVE_INDEX"
|
||||
},
|
||||
{
|
||||
"name": "BINDING_INDEX"
|
||||
},
|
||||
{
|
||||
"name": "BIT_MASK_START_VALUE"
|
||||
},
|
||||
@ -611,9 +608,6 @@
|
||||
{
|
||||
"name": "getActiveDirectiveId"
|
||||
},
|
||||
{
|
||||
"name": "getAndIncrementBindingIndex"
|
||||
},
|
||||
{
|
||||
"name": "getBeforeNodeForView"
|
||||
},
|
||||
@ -1073,6 +1067,9 @@
|
||||
{
|
||||
"name": "nativeRemoveNode"
|
||||
},
|
||||
{
|
||||
"name": "nextBindingIndex"
|
||||
},
|
||||
{
|
||||
"name": "nextContextImpl"
|
||||
},
|
||||
@ -1208,6 +1205,9 @@
|
||||
{
|
||||
"name": "setActiveHostElement"
|
||||
},
|
||||
{
|
||||
"name": "setBindingIndex"
|
||||
},
|
||||
{
|
||||
"name": "setBindingRoot"
|
||||
},
|
||||
|
Reference in New Issue
Block a user