NGXS - how parent state can access child state

I am working with parent-child states:

@State({
     name: 'parent',
     default: { parentProp : 'foo' },
     children: [
        ChildState,
     ]
}) class ParentState {}

Additionally, I have:

@State({
     name: 'child',
     default: { childProp: 'bar' },
}) class ChildState {}

Now, within an action in the parent state, my goal is to access the state from the child. I am currently facing a challenge during this process as the action handler only has access to StateContext and action payload. Is there a method or approach that allows me to achieve this?

Answer №1

Perhaps one way to tackle this is by

const kid = <ChildStateModel>this.store.selectSnapshot(state => state.child);

alternatively, you could simply employ

@Action(context: StateContext<ChildStateModel>, action: any)

if your sole purpose is to interact with the child component.

Answer №2

If you want to include an optional property in your model interface or type, consider adding a substate name. By doing this, you won't need to specify default: in the @State decorator and still be able to access the substate from the parent component.

Here is an example of how it can be implemented:

/*
Please keep in mind that this is just an example ;)
A substate with only one property may not always be sufficient...

Also note that I am using types instead of interfaces 
(it's not called InterfaceScript, right? ;) ) - should work the same with interfaces
*/

// Define the name of the sub-state to maintain typing consistency in state models, contexts, etc.
export const selectedBookStateName = 'selectedBook';
export type Book = { title: string };

export type LibraryStateModel = { 
  books: Book[];
  loading: boolean;
  // This particular line is where the magic happens
  // `[variable]: type` means "use the value of the variable as the property name"
  // `foo?: type` means "the property foo is optional"
  // Together, we create an "optional property named after the value of selectedBookStateName"
  [selectedBookStateName]?: SelectedBookStateModel;
};
export type SelectedBookStateModel = { model: Book | null; };


// Helper state operator allows us to easily manage the selected book substate without worrying about its actual value
export function patchSelectedBookSubState(
  selectedRepository: Partial<SelectedBookStateModel>
): StateOperator<LibraryStateModel> {
  return patch({
    [selectedBookStateName]: patch<SelectedBookStateModel>(selectedRepository),
  });
}

@State<LibraryStateModel>({
  name: 'library',
  defaults: {
    books: [],
    loading: false,
    // Not specifying "selectedBook" here is optional; no need to do so
  },
  children: [SelectedBookState],
})
@Injectable()
export class LibraryState {

@Action(SelectBook)
selectBook(ctx: StateContext<LibraryStateModel>, action: SelectBook) {
  const state = ctx.getState();

  // The substate is expected to be undefined
  // It should never be, but we lose this information when making the substate optional in our library type.
  // I chose not to solve this issue (and it doesn't bother me)
  const current: SelectedBookState | undefined = state.selectedBook?.model;
  // Another way to access the substate
  const current2: SelectedBookState | undefined = state[selectedBookStateName]?.model;

  // The NGXS documentation advises against using setState as it would cause the context of the substate to be erased.
  // However, this is not applicable here since we returned `patch()` from our helper state operator.
  ctx.setState(patchSelectedBookSubState(action.payload));
}


@State<SelectedBookStateModel>({
  // Using the constant defined earlier
  name: selectedBookStateName, 
  defaults: {
    model: null
  },
})
@Injectable()
export class SelectedBookState {
  @Action(BorrowBookOrSomething)
  borrowBook(ctx: StateContext<SelectedBookStateModel>) {
    // Implementation goes here...
  }
}

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

Discovering the Latest Features with Top-Level Await in Node 17 and TypeScript Nightly Build

Exploring the usage of top-level await with Node and TypeScript has been my current experiment. import { readFile } from "fs/promises"; async function getNum(filename: string) { return parseInt(await readFile(filename, "utf8"), 10); ...

Exploring Angular 10: Managing Two Promises in ngOnInit

I am currently working on integrating the Strava API into my Angular app. To summarize briefly: When a user clicks on a button to connect to Strava They are redirected to Strava for authentication (using PKCE) Strava then redirects back to my app with a ...

Move the angular component to an external location

Is there a way to extract a component from my Angular application 'A' and store it separately in order to easily reload it into another Angular application 'B' with the same node_modules and run it? Essentially, I'm looking to crea ...

Can you explain how I can incorporate Angular's "banana in a box" two-way binding feature when using Custom Elements in my project?

I am currently in the process of creating a unique custom element that will be utilized by an Angular application. This custom element is designed to accept a property and potentially make modifications to it. Initially, I thought I could utilize the "ban ...

Incorporating quotes into a unified npm script

I'm trying to merge two npm scripts into one, but the result is incorrect and causes issues with passing flags. I can't use the dotenv package, and using ampersands isn't solving the problem. Here's what I have in my package.json file ...

Issue with updating view in React Native/Javascript after an asynchronous fetch operation. Execution order may be invalid

Below is the code I've written to fetch data using fetch() and display an output only after fetching it. However, the view fails to update after the asynchronous call. Since I'm new to react native async calls, I would appreciate some help on thi ...

Retrieve the value of an ng-select component upon submitting a form

As a newcomer to Angular, I'm seeking guidance on how to properly handle form submissions with NgSelect in my project. Within my new-team.component.html file, I have the following code structure: <app-header></app-header> <div class="c ...

React Router 6 action fails to subscribe to the isSubmitting state from React Hook Form and does not function properly with RTK Query Mutation as well

This React component simplifies forms: const itemSchema = z.object({ title: z.string().max(50), }); type ItemFormFields = z.infer<typeof itemSchema>; const { register, handleSubmit, reset, setError, formState: { isSubmitting, errors } } ...

The functionality of Angular Flex Layout's Static API for vertical or horizontal space-around with no alignment appears to be malfunctioning

Can someone explain why the spacing around alignment isn't functioning here? I'm getting the same result for space-between. What could I be overlooking? ...

Ways to send JWT in the request header to an Angular6 application

Managing users and sessions through an external application such as a Web Application Firewall (WAF) The external app sends a JWT with user information in the request header to the Angular6 app The Angular6 app needs to extract the information from the req ...

What is the reason for TypeScript's prioritization of arguments over assignment in generic inference?

When it comes to Typescript generics inference, the priority is given to arguments over assignment. This means that any param props are automatically converted into type unknown, even if they are assigned to a variable whose type param is set to an object ...

Extracting Date and Time Information from matDatepicker in Angular 6 Material

Below is the code snippet present in my html file: <mat-form-field> <input matInput [matDatepicker]="myDatepicker" placeholder="Choose a date" [(ngModel)]="model.value" name="value"> <mat-datepicker-toggle matSuffix [for]="myDatepic ...

Steps to integrate Framework7 with Ionic 2

Is there a way to incorporate framework7 into a ionic2 project? I have successfully installed framework7 in my ionic2 project using the following command: npm i framework7 --save My next step is to add the typescript definition to the project by downloa ...

What is preventing the CKEditor 4 Angular module from properly validating form fields?

Why is it that the form field validation for the CKEditor 4 Angular module does not seem to be functioning properly? You can find my code here. I have experimented with different combinations of .touched, .pristine, and .valid. Despite this, the CKEdito ...

The disappearance of the "Event" Twitter Widget in the HTML inspector occurs when customized styles are applied

Currently, I am customizing the default Twitter widget that can be embedded on a website. While successfully injecting styles and making it work perfectly, I recently discovered that after injecting my styles, clicking on a Tweet no longer opens it in a ne ...

What is the functionality of "classnames" in cases where there are multiple classes sharing the same name?

Currently, I am reviewing some code that utilizes the npm utility classnames found at https://www.npmjs.com/package/classnames. Within the scss file, there are various classes with identical names (small and large), as shown below: .buttonA { &.smal ...

Remove an item from the DOM instantly with React

Having trouble synchronously removing a child from the container? Here is a simplified code snippet demonstrating the current solution using the useState hook. type ChildProps = { index: number; id: string; remove: (index: number) => void; }; fun ...

Unconventional way of assigning class properties in Typescript (Javascript): '?='

Recently, I came across the ?= assignment expression within a class property declaration. Can anyone provide some insight into what this means? I am familiar with the new Optional Chaining feature (object?.prop), but this particular syntax is unfamiliar t ...

Angular 2 Mouseover Functionality

Can anyone share the correct method for creating a hover-like event in the latest Angular2 framework? In the previous Angular1 version, we used ng-Mouseover for this purpose, but it seems like it is no longer available in Angular2. I have searched throug ...

What is the process to activate a function within a component once a service method has been run?

I'm currently working on a chart configuration using amCharts, where an eventListener is registered for the bullets. This event listener then triggers another function in my chart service. My goal is to activate a method in my component as soon as th ...