Angular: How to share Components data

Łukasz Flak

Introduction

One of the key features of Angular is its ability to easily share data between components. Sharing data between components is crucial for building complex applications, as it allows components to communicate and exchange information. In this article, we will explore various methods to share data between Angular components.

Input-Output

Angular provides a simple way to share data between parent and child components using input and output properties. The parent component can pass data to the child component through input properties, while the child component can emit events through output properties to communicate with the parent component.

Let’s consider a simple example where we have a parent component and a child component. The parent component has a variable called parentData, which we want to pass to the child component.

// parent.component.html
<app-child [childData]="parentData" (dataChanged)="handleDataChanged($event)"></app-child>

// parent.component.ts
export class ParentComponent {
  parentData: string = "Hello from parent";

  handleDataChanged(data: string) {
    console.log(data);
  }
}

// child.component.ts
export class ChildComponent {
  @Input() childData: string;
  @Output() dataChanged: EventEmitter<string> = new EventEmitter<string>();

  handleChange() {
    this.dataChanged.emit("Data changed in child");
  }
}

In this example, the parent component passes the value of parentData to the child component using the childData input property. The child component emits an event through the dataChanged output property when the data is changed. The parent component listens to this event and handles it in the handleDataChanged method.

Sharing Data by Subject from Service

Another way to share data between components is by using a shared service. The shared service can expose a subject or an observable that components can subscribe to and receive data updates.

Let’s consider an example where we have a shared service called DataService. The service has a subject called dataSubject, which components can subscribe to in order to receive data updates.

// data.service.ts
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable()
export class DataService {
  private dataSubject: Subject<string> = new Subject<string>();

  setData(data: string) {
    this.dataSubject.next(data);
  }

  getData() {
    return this.dataSubject.asObservable();
  }
}

// component1.component.ts
export class Component1 {
  constructor(private dataService: DataService) {}

  sendDataToService() {
    this.dataService.setData("Data from Component1");
  }
}

// component2.component.ts
export class Component2 {
  data: string;

  constructor(private dataService: DataService) {
    this.dataService.getData().subscribe((data) => {
      this.data = data;
    });
  }
}

In this example, Component1 sends data to the DataService by calling the setData method. Component2 subscribes to the data updates by calling the getData method and receives the updated data in the subscription callback.

Sharing Data by NgRx Store

NgRx is a state management library for Angular applications. It provides a centralized store where components can read and write data. Sharing data between components becomes easier with NgRx, as it follows a unidirectional data flow.

Let’s consider an example where we have a store that manages a data state.

// app.state.ts
import { createAction, createReducer, on, props } from '@ngrx/store';

export const setData = createAction('[Data] Set Data', props<{ data: string }>());

export interface AppState {
  data: string;
}

export const initialState: AppState = {
  data: '',
};

export const dataReducer = createReducer(
  initialState,
  on(setData, (state, { data }) => ({ ...state, data }))
);

// app.module.ts
import { StoreModule } from '@ngrx/store';
import { dataReducer } from './app.state';

@NgModule({
  imports: [
    StoreModule.forRoot({ data: dataReducer })
  ],
})
export class AppModule { }

// component1.component.ts
export class Component1 {
  constructor(private store: Store<{ data: string }>) {}

  sendDataToStore() {
    this.store.dispatch(setData({ data: "Data from Component1" }));
  }
}

// component2.component.ts
export class Component2 {
  data: Observable<string>;

  constructor(private store: Store<{ data: string }>) {
    this.data = this.store.select('data');
  }
}

In this example, Component1 dispatches a setData action with the desired data to the store using the store.dispatch method. Component2 selects the data property from the store using the store.select method and subscribes to it using the async pipe.

Other Data Share Possibilities

Apart from the methods mentioned above, Angular offers several other possibilities for sharing data between components. Some of them include:

Route parameters: Components can share data through route parameters by configuring the router to pass data between components using route parameters. Local storage: Components can store and retrieve data from the local storage of the browser. Session storage: Components can store and retrieve data from the session storage of the browser. Cookies: Components can read and write data to cookies to share data.

Conclusion

In this article, we explored various methods to share data between Angular components. We started with the basic input and output mechanism, which allows parent and child components to exchange data. We then moved on to more advanced techniques such as sharing data through services and using the NgRx store for state management. Additionally, we briefly mentioned other possibilities for sharing data, including route parameters, local storage, session storage, and cookies. By leveraging these data-sharing techniques, you can create more robust and interactive Angular applications that efficiently exchange data between components.

References

Meet the geek-tastic people, and allow us to amaze you with what it's like to work with j‑labs!

Contact us