Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Create application reducer and meta reducer.
Also like normal NgRX apps, add a reducer map to your app.state.ts file. We recommend creating this file in a root state directory, located at src/app/state.
In versions of NgRx Auto-Entity prior to v0.2, the developer was also responsible for including the autoEntityMetaReducer
in the app meta reducers collection. As of version 0.2 of the library, import of the NgrxAutoEntityModule
with the .forRoot()
call is all that is necessary to include the meta reducer.
If you are upgrading from a version prior to v0.2, you should remove the autoEntityMetaReducer
from your app meta reducers!
With NgRx 8 and up, runtime checks have replaced the need to use the storeFreeze meta reducer. As such, a standard state configuration no longer requires any meta reducers.
Create application state interface.
As with any NgRX application, we need to create a new app.state.ts file. We recommend creating is file in a root state directory, located at src/app/state. Import the IEntityState
interface from @briebug/ngrx-auto-entity as well, as we will be using it later.
Define the AppState
interface as normal. We will eventually define each entity state property here. For now, we've left it blank, and will fill it in later on in this quick start.
Remember to export the AppState
type so that it may be used throughout the rest of your app.
Create your entity models.
In a departure from classic @ngrx/entity models, each model in your application should be defined as a class (see note below). Here is an example of a Customer
model:
Next we need to import the Key
and Entity
decorators. The Key
decorator is used to specify the property in your model that is the unique identifier. Decorate the id
property, which is the unique identifier for Customer
model. Read more about entity keys in the advanced documentation.
The Entity
decorator is used to attach metadata to your entity model that the NgRx Auto-Entity library can use to perform many of its automated tasks. In version 0.5 of the library, only the modelName
must be specified. Read more about the entity decorator in the advanced documentation.
Note that the model must be a class and not an interface. This is because interfaces are a compile-time only feature of TypeScript, while classes are a native runtime construct in JavaScript. Further, the modelName
must be defined on the entity, as this is the name that the library will use at runtime for minified/uglified code (critical, read more in advanced documentation.)
Define the initial entity state
In our example we are building the state for the Customer
entity. As such, we've created a new customer.state.ts file located at src/app/state/customer.state.ts.
Import the buildState
function from the ngrx-auto-entity module. This function builds the initial state and selectors for each entity. Call the function by passing in the Customer entity class (note, the class must be passed in!) We use object destructuring on the return type access the initialState
, selectors
and facade
base class from the result of buildState
.
We can now further destructure the selectors object to map each type of standard selector to model-specific names for import into other modules:
selectAll
selects the Array
of entities
selectEntities
selects the Dictionary
of entities
selectIds
selects the Array
of entity identifiers (keys)
selectTotal
selects the number
of entities
Note that retrieving and exporting the selectors are optional if you extract the facade. The facade base class generated by buildState fully encapsulates all of the functionality you will need to interact with your entity state, and we generally recommend only using the facade. Demonstration of how to access selectors directly, such as in the event that you may need to create your own custom selectors, is simply for completeness here.
There are many additional selectors bundled as part of each custom entity state built by buildState
that may be mapped to state-specific names. Read more in the advanced documentation.
When the selectors object is destructured we alias the selectors with entity-friendly names to avoid naming conflicts with other exported names. This prevents the need to import entire files with an import * as fromBlah from 'blah'
syntax. Uniquely named exports are enough, and allow selective import into each area of the app.
Finally, we define the customerReducer
function. The reducer function accepts two arguments: state
, which defaults to the initialCustomerState
, and the action
.
A reducer function is necessary to configure the NgRX standard actionsReducer
we defined earlier. For most entities, you will not need to do anything other than return the state passed in, as the autoEntityMetaReducer
will handle reduction for you. If custom reduction is required for your apps, it may be handled in these reducers.
Adding NgRx & Auto-Entity to an App
If you have not used NgRx before, and need to start from scratch, this guide should get you going. Let's start by creating a state module. We recommend creating this module in a root state directory, located at src/app/state. In this directory, create a new state.module.ts file:
Import the NgRx StoreModule
and EffectsModule
as well as the Auto-Entity NgrxAutoEntityModule
. Make sure you call the .forRoot()
initializer on each of them to ensure they are properly imported. It is important that the NgrxAutoEntityModule be brought in after the EffectsModule, as this ensures all automatic effects will be properly registered.
The NgRx Auto Entity module is now imported in your application, giving you access to ready-made generic actions, automatic effects, pre-defined reducers and prefabricated facade classes to handle the bulk of your CRUD meeds.
Next, we need to set up the state of our application.
Create application state module.
Now that we have implemented our root state interface & reducer map, we need to update the state module we created in the first step:
Update the import of the StoreModule
. In the forRoot()
static method, specify the appReducer
and (if necessary) appMetaReducers
from your previously created app.reducer
as with any normal NgRX app.
If you have any custom effects you may have implemented, include those classes in the EffectsModule
import's forRoot()
call. Effects are optional with NgRx Auto-Entity, so if you have no effects just pass an empty array.
Update the application state interface.
Now that we have the standard initial implementation for NgRX and Auto-Entity in place, we need to wire our models into our state.
Note that we have added a new customer
property to the IAppState
interface of type IEntityState<Customer>
, which we imported from @briebug/ngrx-auto-entity
at the top of the file.
For most basic CRUD states, you will not need to implement any custom state interfaces, effects or reducers. This is the simplicity that NgRX Auto-Entity brings to the table!
After we create the entity reducer, we'll also need to update the appReducer
constant to include the customer
property (with the customer reducer function as the value). It's important that both properties have the same name.
Finally, in order for NgRx Auto-Entity to find the entity service you just created, you must provide it in your application state. Providing entity services is slightly different than a normal provider, which simply provides itself as the service class.
Here, we have provided the model type as the provider, and specified the EntityService
class as the actual service class via useClass
. This is the simplest model for using Auto-Entity, and for simple backend APIs that follow a common pattern, a single service like this may be reused for any number of entities.
provide: Model, useClass: EntityService
In the event that you have a more complex backend API, or even must integrate with many backend APIs, you may create custom entity services for each entity if necessary, and provide each model with its own unique service class following the same pattern as above.
Finally, import the StateModule
we created earlier into your root AppModule
to bring in all of your root state, including NgRx Auto-Entity.
And, with that, you are done! You can now start using your entity in your app.
Create service for handling data interactions with server
In our example we are creating a service for persisting entities via a simple REST API. As such, we've created a new entity.service.ts file and defined an injectable EntityService
class.
It's important that each entity service implement the IAutoEntity
interface. This interface supports the following methods:
load()
loadAll()
loadMany()
loadPage()
loadRange()
create()
createMany()
update()
updateMany()
replace()
replaceMany()
delete()
deleteMany()
These methods perform the CRUD operators for entity retrieval and persistence.
To create an entity service, we must import the IAutoEntityService
and IEntityInfo
interfaces. The entity service must implement the IAutoEntityService
interface. The IEntityInfo
object provides metadata about the entities, which can be used to help build urls if necessary.
Finally, we implement each of the necessary methods for retrieving and persisting an entities.
Your implementation may vary based on the method of persistence and the architecture of your API. Each method is optional, and may be implemented on an as-needed basis for each entity. We provide several options for loading data, as well as options for updating (PATCH) or replacing (PUT) entities. Each method of an entity service also provides additional input parameters such as custom criteria. Implement and use what you need.