fix(ivy): ensure parent/sub-class components evaluate styling correctly (#29602)
The new styling algorithm in angular is designed to evaluate host bindings stylinh priority in order of directive evaluation order. This, however, does not work with respect to parent/sub-class directives because sub-class host bindings are run after the parent host bindings but still have priority. This patch ensures that the host styling bindings for parent and sub-class components/directives are executed with respect to the styling algorithm prioritization. Jira Issue: FW-1132 PR Close #29602
This commit is contained in:

committed by
Igor Minar

parent
5c13feebfd
commit
ec56354306
@ -309,6 +309,21 @@ export interface StylingContext extends
|
||||
*/
|
||||
[StylingIndex.CachedMultiStyles]: any|MapBasedOffsetValues;
|
||||
|
||||
/**
|
||||
* A queue of all hostStyling instructions.
|
||||
*
|
||||
* This array (queue) is populated only when host-level styling instructions
|
||||
* (e.g. `hostStylingMap` and `hostClassProp`) are used to apply style and
|
||||
* class values via host bindings to the host element. Despite these being
|
||||
* standard angular instructions, they are not designed to immediately apply
|
||||
* their values to the styling context when executed. What happens instead is
|
||||
* a queue is constructed and each instruction is populated into the queue.
|
||||
* Then, once the style/class values are set to flush (via `elementStylingApply` or
|
||||
* `hostStylingApply`), the queue is flushed and the values are rendered onto
|
||||
* the host element.
|
||||
*/
|
||||
[StylingIndex.HostInstructionsQueue]: HostInstructionsQueue|null;
|
||||
|
||||
/**
|
||||
* Location of animation context (which contains the active players) for this element styling
|
||||
* context.
|
||||
@ -316,6 +331,66 @@ export interface StylingContext extends
|
||||
[StylingIndex.PlayerContext]: PlayerContext|null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A queue of all host-related styling instructions (these are buffered and evaluated just before
|
||||
* the styling is applied).
|
||||
*
|
||||
* This queue is used when any `hostStyling` instructions are executed from the `hostBindings`
|
||||
* function. Template-level styling functions (e.g. `elementStylingMap` and `elementClassProp`)
|
||||
* do not make use of this queue (they are applied to the styling context immediately).
|
||||
*
|
||||
* Due to the nature of how components/directives are evaluated, directives (both parent and
|
||||
* subclass directives) may not apply their styling at the right time for the styling
|
||||
* algorithm code to prioritize them. Therefore, all host-styling instructions are queued up
|
||||
* (buffered) into the array below and are automatically sorted in terms of priority. The
|
||||
* priority for host-styling is as follows:
|
||||
*
|
||||
* 1. The template (this doesn't get queued, but gets evaluated immediately)
|
||||
* 2. Any directives present on the host
|
||||
* 2a) first child directive styling bindings are updated
|
||||
* 2b) then any parent directives
|
||||
* 3. Component host bindings
|
||||
*
|
||||
* Angular runs change detection for each of these cases in a different order. Because of this
|
||||
* the array below is populated with each of the host styling functions + their arguments.
|
||||
*
|
||||
* context[HostInstructionsQueue] = [
|
||||
* directiveIndex,
|
||||
* hostStylingFn,
|
||||
* [argumentsForFn],
|
||||
* ...
|
||||
* anotherDirectiveIndex, <-- this has a lower priority (a higher directive index)
|
||||
* anotherHostStylingFn,
|
||||
* [argumentsForFn],
|
||||
* ]
|
||||
*
|
||||
* When `renderStyling` is called (within `class_and_host_bindings.ts`) then the queue is
|
||||
* drained and each of the instructions are executed. Once complete the queue is empty then
|
||||
* the style/class binding code is rendered on the element (which is what happens normally
|
||||
* inside of `renderStyling`).
|
||||
*
|
||||
* Right now each directive's hostBindings function, as well the template function, both
|
||||
* call `elementStylingApply()` and `hostStylingApply()`. The fact that this is called
|
||||
* multiple times for the same element (b/c of change detection) causes some issues. To avoid
|
||||
* having styling code be rendered on an element multiple times, the `HostInstructionsQueue`
|
||||
* reserves a slot for a reference pointing to the very last directive that was registered and
|
||||
* only allows for styling to be applied once that directive is encountered (which will happen
|
||||
* as the last update for that element).
|
||||
*/
|
||||
export interface HostInstructionsQueue extends Array<number|Function|any[]> { [0]: number; }
|
||||
|
||||
/**
|
||||
* Used as a reference for any values contained within `HostInstructionsQueue`.
|
||||
*/
|
||||
export const enum HostInstructionsQueueIndex {
|
||||
LastRegisteredDirectiveIndexPosition = 0,
|
||||
ValuesStartPosition = 1,
|
||||
DirectiveIndexOffset = 0,
|
||||
InstructionFnOffset = 1,
|
||||
ParamsOffset = 2,
|
||||
Size = 3,
|
||||
}
|
||||
|
||||
/**
|
||||
* Used as a styling array to house static class and style values that were extracted
|
||||
* by the compiler and placed in the animation context via `elementStart` and
|
||||
@ -511,9 +586,7 @@ export const enum InitialStylingValuesIndex {
|
||||
* index value by the size of the array entries (so if DirA is at spot 8 then its index will be 2).
|
||||
*/
|
||||
export interface DirectiveRegistryValues extends Array<null|{}|boolean|number|StyleSanitizeFn> {
|
||||
[DirectiveRegistryValuesIndex.DirectiveValueOffset]: null;
|
||||
[DirectiveRegistryValuesIndex.SinglePropValuesIndexOffset]: number;
|
||||
[DirectiveRegistryValuesIndex.DirtyFlagOffset]: boolean;
|
||||
[DirectiveRegistryValuesIndex.StyleSanitizerOffset]: StyleSanitizeFn|null;
|
||||
}
|
||||
|
||||
@ -522,11 +595,9 @@ export interface DirectiveRegistryValues extends Array<null|{}|boolean|number|St
|
||||
* that are housed inside of [DirectiveRegistryValues].
|
||||
*/
|
||||
export const enum DirectiveRegistryValuesIndex {
|
||||
DirectiveValueOffset = 0,
|
||||
SinglePropValuesIndexOffset = 1,
|
||||
DirtyFlagOffset = 2,
|
||||
StyleSanitizerOffset = 3,
|
||||
Size = 4
|
||||
SinglePropValuesIndexOffset = 0,
|
||||
StyleSanitizerOffset = 1,
|
||||
Size = 2
|
||||
}
|
||||
|
||||
/**
|
||||
@ -678,9 +749,10 @@ export const enum StylingIndex {
|
||||
CachedMultiStyles = 7,
|
||||
// Multi and single entries are stored in `StylingContext` as: Flag; PropertyName; PropertyValue
|
||||
// Position of where the initial styles are stored in the styling context
|
||||
PlayerContext = 8,
|
||||
HostInstructionsQueue = 8,
|
||||
PlayerContext = 9,
|
||||
// Location of single (prop) value entries are stored within the context
|
||||
SingleStylesStartPosition = 9,
|
||||
SingleStylesStartPosition = 10,
|
||||
FlagsOffset = 0,
|
||||
PropertyOffset = 1,
|
||||
ValueOffset = 2,
|
||||
@ -705,3 +777,13 @@ export const enum DirectiveOwnerAndPlayerBuilderIndex {
|
||||
BitCountSize = 16,
|
||||
BitMask = 0b1111111111111111
|
||||
}
|
||||
|
||||
/**
|
||||
* The default directive styling index value for template-based bindings.
|
||||
*
|
||||
* All host-level bindings (e.g. `hostStyleProp` and `hostStylingMap`) are
|
||||
* assigned a directive styling index value based on the current directive
|
||||
* uniqueId and the directive super-class inheritance depth. But for template
|
||||
* bindings they always have the same directive styling index value.
|
||||
*/
|
||||
export const DEFAULT_TEMPLATE_DIRECTIVE_INDEX = 0;
|
||||
|
Reference in New Issue
Block a user