Creating a structured state declaration in NGXS for optimal organization

Currently, I'm delving into the world of NGXS alongside the Emitters plugin within Angular, and I find myself struggling to grasp how to organize my state files effectively.

So far, I've managed to define a basic .state file in the following manner:


export type PageStatusCases = 'LOADING' | 'IDLE' | 'ERROR' | 'INITIALIZING';

export interface AppStateModel {
  pageStatus: PageStatusCases;
}

@State<AppStateModel>({
  name:     'AppState',
  defaults: {
    pageStatus: 'INITIALIZING'
  }
})
export class AppState {

  @Selector()
  static pageStatus(state: AppStateModel): PageStatusCases {
    return state.pageStatus;
  }

  @Receiver({type: '[Global] Page status'})
  static setPageStatus({patchState}: StateContext<AppStateModel>, {payload}: EmitterAction<PageStatusCases>): void {
    patchState({pageStatus: payload});
  }

}

Now, I'm venturing into a more intricate example by transforming my Service into a State

Within my service, there are numerous BehaviorSubjects that monitor my UI's condition.

  title: BehaviorSubject<string> = new BehaviorSubject('');

  backClick$: EventEmitter<void> = new EventEmitter<void>();
  primaryClick$: EventEmitter<void> = new EventEmitter<void>();

  toolbarVisible$: BehaviorSubject<boolean> = new BehaviorSubject(true);
  primaryVisible$: BehaviorSubject<boolean> = new BehaviorSubject(false);
  primaryDisabled$: BehaviorSubject<boolean> = new BehaviorSubject(false);
  primaryAutoDisabled$: BehaviorSubject<boolean> = new BehaviorSubject(false);
  primaryIcon$: BehaviorSubject<ToolbarPrimaryIcon> = new BehaviorSubject(ToolbarPrimaryIcon.ADD);

I've initiated the process of converting these BehaviorSubjects into components of the state. However, I've realized that it necessitates an extensive amount of boilerplate code.

For each BehaviorSubject, I am obligated to:

  • Incorporate it in the state's model Interface
  • Specify its default state in the State
  • Define its @Selector within the state structure
  • Determine its @Receiver (Action) in the state
  • Add its @Select in every component requiring it
  • Integrate its @Emitter in every pertinent component for potential updates

The current scenario entails over 100 lines of code merely to manage 7 variables correctly, which indicates that I might be overlooking something crucial. The surplus visual clutter is also becoming a concern.

It's evident that an issue exists

I'm seeking insights on what fundamental element I might be disregarding and any alternative approaches for declaring states in such circumstances.

Recently, I adopted NGXS with the emitters plug-in under the assumption that it would streamline the process and mitigate the necessity for excessive boilerplate code. Yet, the anticipated benefits seem elusive at present.

Answer №1

There may be some boilerplate code, but the main issue you seem to be facing is creating multiple @Selector functions that only access a single state property. Components can simply subscribe directly to the state changes using a @Select binding Observable or by using store.select(). The image displays unnecessary @Select declarations with the state.

I do not have personal experience using the Emitters feature from NGXS Labs, so I cannot provide feedback on its usage.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Issue with Angular 7 cli failing to recognize a custom TypeScript file

While working on an Angular 7 component, I encountered an issue when trying to read a custom file. The problem arises when the server restarts, even though there are no errors in the component's TypeScript file. ERROR: app/zontify-components/zonti ...

Issue encountered: NullInjectorError - R3InjectorError has been caused by a problem within AppModule regarding InjectionToken HTTP_INTERCEPTORS linking to TransferState

Error Image:- Error Images I am encountering this error: ERROR NullInjectorError: R3InjectorError(AppModule)[InjectionToken HTTP_INTERCEPTORS -> [object Object] -> TransferState -> TransferState -> TransferState]: NullInjectorError: No provider ...

What is the best way to activate a submit button when at least one checkbox is selected?

I checked out Mark's solution on Stack Overflow regarding disabling a button if no checkboxes are selected in Angular2. However, I have more than one array to consider. How can I adjust the code provided in the link for my situation? Alternatively, d ...

A custom Typescript type for immutable values within an object

I am struggling with finding the right data type for my function, where I need to work with static types. I have experimented with Type, interface, class, Record, and others, but none seem to fit perfectly. GEOLOCATIONS is a constant record that maps cou ...

The recent transition to Angular 9 Subject has led to the emergence of the ExpressionChangedAfterItHasBeenCheckedError

Upon updating to Angular version 9, I encountered a series of errors stating: "Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value for 'hidden': 'true'. Current value: 'fa ...

Error encountered with TypeScript template literals strings type

There's a new feature in the latest version of Typescript that allows the use of template literal strings as types, like this: type Hey = 'Hey'; type HeyThere = `${Hey} There`; It works perfectly in the Typescript playground with version 4 ...

The ajv-based middy validator does not adhere to the specified date and time format

When it comes to validation, I rely on middy as my go-to package, which is powered by ajv. Below is an example of how I set up the JSON schema: serviceDate: { type: 'string', format: 'date-time' }, The structure o ...

Exploring how to utilize class properties within Angular templates

I am facing an issue with using a template property in Angular. Despite my attempts, it is not functioning as expected and I am unable to pinpoint the cause of the problem. To illustrate, I have set up a demonstration here: https://github.com/Fulkerson/an ...

Mastering the proper usage of the import statement - a guide to seamless integration

I'm excited to experiment with the npm package called camera-capture, which allows me to capture videos from my webcam. As someone who is new to both npm and typescript, I'm a bit unsure about how to properly test it. Here's what I've ...

After refreshing the page, RouterLinkActive in Angular 6 fails to work

Scenario In my application, there is a menu with various items. The selected item is distinguished by adding the selected class to it, which changes its appearance. Problem While navigating between routes works smoothly, the issue arises when the page ...

Create an instance of a class from a group of subclasses, all the while retaining the ability to access static members in Types

I seem to have encountered a dilemma where I am looking to have both the static and abstract keywords used for a member of an abstract class in TypeScript, but it appears that this combination is not supported. The nearest workaround I could come up with ...

The final value of a loop is consistently returned each time

Creating a loop to generate objects. Action.ts public campaing:any = { 'id': '', 'campaing_code': '', 'campaing_type': '', 'start_date': this.currentDate, 'end ...

Is it possible to derive a TypeScript interface from a Mongoose schema without including the 'Document' type?

Using ts-mongoose allows me to define interfaces and schemas for my data in one place. I then export them as a mongoose schema along with the actual interface. The challenge I'm facing is finding a simple way to extract that interface without includi ...

Maximizing Efficiency of Vendor Bundle in Angular 2 with Webpack

My MEAN application's client side is built in Angular2 with Webpack, but I'm facing slow loading times due to a large vendor modules JS file. Is there a way to optimize this situation? I want to separate the vendor's JS file. Below is my we ...

Child Route Handling Based on Conditions (Angular)

Can a child route be conditionally displayed as a default? I want users to land on a specific child route based on their past orders (e.g., go to the store page if they ordered from a physical store, online page for online orders, or social page otherwise ...

TailwindCSS applies CSS settings from tailwind.admin.config.js without overriding tailwind.config.js. The @config directive is utilized for this purpose

I'm currently working on a project using Vite and React. I have a tailwind.admin.css file that is similar to the example provided in the documentation. @config './configs/tailwind.admin.config.js'; @tailwind base; @tailwind components; @tai ...

Developing Angular 6 for dynamic HTML navigation tabs

Being new to Angular 6, I recently created tabs in HTML and now need to convert them into Angular 6 while also making them dynamic. Here is the original HTML code: <ul class="nav nav-tabs side_nav" role="tablist"> <li role="presentation" class= ...

What causes the presence of undefined elements within the ngOnInit function of Angular?

When I initialize a library in my ngOnInit method like this: ngOnInit() { this.$grid = jQuery('.grid').masonry({ // options itemSelector: '.grid-item',//, columnWidth: 384, gutter: 24 }); ...... } and then call the method from ...

Be cautious, warning.indexOf function is not supported in this version of rollup.js

Encountering the following error message when using the rollup.config.js file warning.indexOf is not a function rollup.config.js import nodeResolve from 'rollup-plugin-node-resolve' import commonjs from 'rollup-plugin-commonjs&apos ...

Dealing with numerous errors from various asynchronous pipes in angular - a comprehensive guide

I am facing an issue with 2 mat-select elements in my component, both of which utilize the async pipe: <div class="flex-col"> <mat-label>Issue Desc </mat-label> <mat-form-field> < ...