-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(angular-table): Refactor Flex render implementation - Zoneless, Better type safety, allows reactive values into cell content, re-render when cell context changes, allow to pass signal inputs into custom components #5856
base: main
Are you sure you want to change the base?
feat(angular-table): Refactor Flex render implementation - Zoneless, Better type safety, allows reactive values into cell content, re-render when cell context changes, allow to pass signal inputs into custom components #5856
Conversation
View your CI Pipeline Execution ↗ for commit 1d9b642.
☁️ Nx Cloud last updated this comment at |
7bfea75
to
94bed11
Compare
144f0b7
to
ed5c89c
Compare
ed5c89c
to
db39511
Compare
test fix doc add flexRenderComponent util
5753653
to
2c1725b
Compare
@KevinVandy pr is now ready. I've also added a fix to proxy that was preventing to have 4f0149a#diff-a3500075d578d363191c8bc27e94c7f42a2426e4b6e5c582551cfafe9d2576b4R27 3b2f6fa#diff-31817a6cdcff3b5737ed13d14709201ade91cc98fd8524fd8898e0afc5ac9415R88 After that I'll have another ready PR to support angular outputs while using flexRender but I would prefer to separate it to make it shorter (example of usage) |
fbd4df0
to
f822645
Compare
…port-output-binding add support for angular outputs in flex-render-component
I refactored how the FlexRender directive applies updates internally during change detection. This will resolve issues like #5767 without necessarily waiting for v9 (so this is not a breaking change for users). It now should also work with zoneless and it's reactive if someone use signals into the cell content. Also there are some dx improvements that helps writing column custom content easily
tldr
For those who enjoy reading 😅:
Update vitest configuration
I've updated vitest test setup with latest version of @analog/vitest-angular and @analog/vite-plugin-angular in order to compile the angular components correctly.
We are now able to use angular signal inputs during test. I removed all workaround utils we had to use before. Now we could also opt for switching the FlexRenderDirective to signal inputs instead of old-based @input decorators, even if we cannot rely on effects, we should always use ngOnChanges).
Enhanced Type Safety for FlexRenderComponent
The FlexRenderComponent inputs are now typed based on the given component instance
I have also added a
flexRenderComponent
function util that can be used to enhance typesafety and which use an option object instead of multiple arguments to pass data. This allows us to add new arguments in the future without breaking that signature (e.g. in the future we will probably need to bind angular "outputs").In v9 we may want to have only one of the two available to avoid confusion?
Injection context for cell content
Cell content now runs within an injection context. This allows users to inject services and using signals into the cell definition, even outside angular components.
Refactor FlexRenderDirective rendering mechanism
tldr
This is the biggest part. With the previous implementation, we were only relying on
ngOnChanges
hook.ngOnChanges
is called by Angular when any data-bound property change, but it's not enough for some reasons:content
property is a reference of the cell/header definition, which could be a function. Doingcontent(props)
may return different values, but since we are passing a reference, Angular cannot evaluate it for us automatically.props
most of the time will be(cell|header).getContext()
, which is memoized for cell (but no headers). Then even in this case the reference may not changeWhen table data change, we are sure that at least both properties changes. Currently this is the only case were we are re-rendering the cell view.
With this PR, first I am introducing some logic to split some rendering-related code on separate classes (those are not exposed to the library consumers):
FlexRenderComponentRef
: a wrapper for Angular ComponentRef, which expose some internal utils to detect changes, set inputs via angularsetInput
api etc.FlexRenderComponentFactory
: an angular service that is responsible to create instances of FlexRenderComponentRef.FlexRenderView
: an abstract class that encapsulate the view state and some information, and defines some logic that we invoke in specific phases of the view checker. It has two implementations:FlexRenderTemplateView
: a class that define update methods for content rendered via EmbeddedViewRef (which we use to render primitives like string, number or even TemplateRef instances)FlexRenderComponentView
: a class that define update methods for content rendered via FlexRenderComponentRef (ComponentRef)I've then revisited the rendering business logic via
ngDoCheck
hook and implementing Bit fields to handle the rendering phases.Link: angular-table/src/flex-render/flags.ts
Regardless of the implementation, there are two new behaviors:
Initializing an effect during the first render
During the view first render, we initialize an
effect
that set theDirtySignal
flag every time thecontent(props)
changes, if signals are used into the cell definition. This allows to react to changes even without ngZone, and opens up some possibilities in v9 to further improve rendering, for example detecting also when thetable
state signals changesChecking changes in ngDoCheck
During the ngDoCheck lifecycle hook, we determine whether the view needs to be updated by evaluating a set of flags and comparing the result of content(props) with its previous value. At the moment, this check occurs during every doCheck cycle. However, in a future we could use store slices (v10?+) and signals (v9 with the reactivity feature i was working on) to improve this phase updating more efficently.
What changes for users
The new implementation is retrocompatible with previous versions, but improves dx of columns definition while using Angular since this let now to render content conditionally, using signals inside etc.
Most of the time the code I saw to render custom content was something like this, splitting how the table is rendered in both template and typescript
Now, we can do the same directly into the column definitions 😄