Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Prefabricated facades in NgRx Auto-Entity expose all the necessary properties and methods to allow you to fully leverage all of the state, actions and selectors Auto-Entity manages. Once you have extended a class from the base facade class, you may leverage all of this functionality without any additional effort.
Each entity facade exposes a number of properties that wrap NgRx state selections
, exposing the streaming data within. Each of these properties returns and Observable of the appropriate type based on the state Auto-Entity tracks. We call these selections. The available properties on every entity facade include the following:
all$: Observable<TModel[]>; Array of entity objects in state entities$: Observable<IEntityDictionary<TModel>>; Map of ids to entity objects ids$: Observable<EntityIdentity[]>; Array of entity identities in state total$: Observable<number>; Total umber of entities in state
current$: Observable<TModel>; Selected single entity currentKey$: Observable<EntityIdentity>; Key of selected single entity
currentSet$: Observable<TModel[]>; Selected entities (New v0.2) currentSetKeys$: Observable<EntityIdentity[]>; Keys of selected entities (New v0.2)
currentPage$: Observable<Page>; Info about the current page of entities in state currentRange$: Observable<Range>; Info about the current range of entities in state totalPageable$: Observable<number>; Total number of entities that can be paged
edited$: Observable<Partial<TModel>>; The currently edited entity (partial) isDirty$: Observable<boolean>; Flag indicating if there have been changes to edited entity
isLoading$: Observable<boolean>; Flag indicating if entities are currently loading isSaving$: Observable<boolean>; Flag indicating if entities are currently saving isDeleting$: Observable<boolean>; Flag indicating if entities are currently deleting
loadedAt$: Observable<Date>; Timestamp of last load savedAt$: Observable<Date>; Timestamp of last save createdSt$: Observable<Date>; Timestamp of last creation deletedAt$: Observable<Date>; Timestamp of last delete
All of these properties are encapsulating functionality you may already be familiar with. In the past with plain old NgRx, you might have done something like the following:
This is in fact what all of the entity facade properties are doing for you. We simplify the above repetitive procedure so you may simply access a property rather than have to bring in the store, pipe and select yourself:
Since all of our entity facade properties are observables, you are still free to use .pipe()
on them as necessary, and leverage the full power of RxJs and reactive programming.
Ultimate power at your fingertips!
Prefabricated facades are one of NgRx Auto-Entities most powerful offerings. Not only can they greatly simplify your code, facades offer a way of organizing and encapsulating core business logic. You can pull a lot of behavior out of your components and move it into your facades. This simplifies your components, and can potentially improve code reuse.
When preparing your state with a call to the buildState
function, Auto-Entity will generate an entity facade class for you. These classes are best considered to be base classes, from which you should extend another class. See the instructions on how in the next section.
Prefabricated facades come complete with a core set of properties and methods that may be used "out of the box" without any additional work on your part beyond extending the base facade class. There is no explicit need to wrap every property or method provided by a facade base class in your own class in order to use it. You may, and are encouraged to, add your own custom properties and methods to encapsulate higher level behavior, though!
To use one of these properties in your component, simply inject your facade classes:
The classic use case is to expose observables on your component to represent the various streams you will use in your template. With NgRx Auto-Entity, this becomes a rather trivial exercise, as there is no real work that must be done in the component. (Continue to the next section to learn how to improve upon the classic approach when using facades.)
We highly recommend following NgRx best practices here to avoid subscribing directly to any observable on an entity facade. Instead, use the async
pipe from Angular in your templates, and follow container/presenter model for your component architecture:
Just a dash of boilerplate...
NgRx Auto-Entity will generate a new facade class for you dynamically whenever you call buildState
. You may optionally destructure this facade class from the response, along with destructuring other core aspects of your new state:
The above is the recommended and most minimal use case for the building states with Auto-Entity. For most use cases, nothing beyond the initialState
and facade
class should be required.
We also recommend renaming for export the name facade
into a more appropriate, unique name for a base facade class for your entity. In the example here, we have renamed the facade to CustomerFacadeBase
.
Once you have your base facade class, you will need to extend the proper facade class from it. Extension is required in order to provide the facade base class with the necessary services. Since our facades are dynamically generated classes created by a simple function, we are unable to leverage the Angular Injector directly.
The above is the most minimal use case for a facade. The only requirement is to call super()
from within your constructor, and pass in the entity model type as well as the store. From here, you may start using all of the ready-made functionality the base facade offers, without any additional work.
Prefabricated facades in NgRx Auto-Entity expose all the necessary properties and methods to allow you to fully leverage all of the state, actions and selectors Auto-Entity manages. Once you have extended a class from the base facade class, you may leverage all of this functionality without any additional effort.
In addition to properties for each selection, entity facades also expose a number of methods that wrap NgRx action
dispatch calls. Each of these methods handles creation and subsequent dispatch of the appropriate generic action, including handling all the type information. We call these activities. The available methods on every facade include:
select(entity: TModel): Selects a single entity selectByKey(key: EntityIdentity): Selects a single entity by the specified key selectMany(entities: TModel[]): Selects the specified entities selectMore(entities: TModel[]): Selects more entities and updates the current selection selectManyByKeys(keys: EntityIdentity[]): Selects entities by the specified keys selectMoreByKeys(keys: EntityIdentity[]): Selects more entities by the specified keys deselect(): Deselects any previously selected entity deselectMany(entities: TModel[]): Deselects the specified entities deselectManyByKeys(keys: EntityIdentity[]): Deselects the specified entities by keys deselectAll(): Deselects all selected entities
load(keys: any, criteria?: any, corrId?: string): Loads entity by the specified key loadMany(criteria: any, corrId?: string): Loads many entities by the specified criteria loadAll(criteria?: any, corrId?: string): Loads all entities loadPage(page: Page, criteria?: any, corrId?: string): Loads a page of entities loadRange(range: Range, criteria?: any, corrId?: string): Loads a range of entities create(entity: TModel, criteria?: any, corrId?: string): Creates a new entity createMany(entities: TModel[], criteria?: any, corrId?: string): Bulk creates entities update(entity: TModel, criteria?: any, corrId?: string): Updates an entity updateMany(entities: TModel[], criteria?: any, corrId?: string): Bulk updates entities
upsert(entity: TModel, criteria?: any, corrId?: string): Updates/inserts an entity upsertMany(entities: TModel[], criteria?: any, corrId?: string): Bulk upserts entities replace(entity: TModel, criteria?: any, corrId?: string): Replace an entity replaceMany(entities: TModel[], criteria?: any, corrId?: string): Bulk replace entities delete(entity: TModel, criteria?: any, corrId?: string): Delete an entity deleteMany(entities: TModel[], criteria?: any, corrId?: string): Bulk delete entities deleteByKey(key: EntityIdentity, criteria?: any, corrId?: string): Delete an entity by its key deleteManyByKeys(keys: EntityIdentity[], criteria?: any, corrId?: string): Delete many entities by their keys clear(): Clears all state for the entity type and resets it to empty
The last parameter of each activity is a correlation id. In the above descriptions, this has been shortened to the term corrId
to condense this documentation a bit, however the actual parameter is called correlationId
and is optional. This allows the end developer to control what the correlationId is for any given set of initiation/result actions dispatched with auto-entity. If this parameter is not provided, the correlationId will be a randomly generated uuid.
All of these methods, as with the properties, are encapsulating functionality you may already be familiar with. In the past with plain old NgRx, you might have done something like the following:
This is in fact what all of the entity facade methods are doing for you. We simplify the above repetitive procedure so you may simply call a method with just the bare bones required arguments, rather than have to bring in the store, dispatch and construct new actions yourself:
The model type is tracked when you extend the facade base class with your own concrete implementation:
In some cases, assigning facade properties to other properties on your component classes may itself be somewhat overly complex. There is not necessarily an explicit need to have observable properties on the component itself.
For container components such as the above Customers component, there is nothing of particular note in the component itself that isn't simply replicating functionality we already have in the facade. We could simply expose the facade to the template by making it public
in the constructor:
Then simply use the facade within the template, as it already provides all of the same exact functionality:
Note just how simple this container component is now that we have leveraged the full capabilities of a generated auto-entity facade! And note just how little code you really had to write.
To use one of these activities in your component, simply inject your facade class and call the method in the constructor, an ngOnInit
or similar handler, or a custom handler:
We highly recommend following NgRx best practices here to avoid subscribing directly to any observable on an entity facade. Instead, use the async
pipe from Angular in your templates, and follow container/presenter model for your component architecture:
Are you even a programmer anymore?
Here is the full excerpt of code that you had to write to implement our customers container component from the facade examples. We are assuming code module imports are handled by the IDE and are not something you would necessarily "write" yourself. Standard Angular decorator content excluded as it is usually generated for you.
There are also a couple additional lines of code you may need to add to your app.state.ts
file for the app state interface and app reducer map, as well as a provider mapping between the model and the entity service. See for more info.