Blog

5 Ways to Pass Data into Child Components in Angular

 Data Passing Blog Image

If you are new to Angular, or transitioning from AngularJS, the first question you are likely to ask is, “how do I pass data around?”

This article, along with the accompanying demo app will demonstrate the following five techniques:

  1. Reacting to changes from @Inputs
  2. Setting properties with @ViewChild
  3. Using BehaviorSubjects in services
  4. Using the Angular Router
  5. Using NgRx

I’ll start with the most basic, and end with the most complex. Each of these techniques fits various use-cases, but it’s up to you to decide which technique is the most appropriate for your app.

Let’s get started!

 

Inputs

Inputs are the simplest and most direct way of passing data to a child component. Simply adding the Input decorator to a property will allow it to be passed in. As you probably know by now, inputs accept data via properties.

@Input() price: number;
 

In markup, these look like attributes. You can use brackets to create a binding and evaluate the input as script, or leave them off to pass a static string value:

<my-component [price]="500"></my-component>

<my-component price="One kajillion dollars"></my-component> 

You can pass methods, constants, or any expression into an input. You can also async pipe observables to unwrap their value right in an input. Then in your component, the property will always reference the last emitted value.

<my-component [profile]="user$ | async"></my-component>

You can use ngOnChanges or getters and setters to react to any changes within your child component. Check out the demo to see code examples.

 

ViewChild

Using ViewChild, you can get and set properties of a child component, and also its methods. This could be handy for dynamically inserted components or elements because you can reference a view child by a component class or template reference variable. To use ViewChild, you pass it the class of the child component, or a template reference variable string (minus the #), and this will decorate a component property like so.

This declaration will find the first instance of PriceComponent in your template:

@ViewChild(PriceComponent) priceComponent;

And given this markup in your template:

<app-price-component #price></app-price-component 

This declaration will create a reference to it:

@ViewChild('price') priceComponent;

 

BehaviorSubjects in services

BehaviorSubjects in services are a simple, powerful way to share data throughout your app. They are as close to $broadcast and $emit in AngularJS as it gets in Angular. The Observable pattern allows you to react to changes whenever they occur in parent and child component alike, while maintaining a single instance. 

To use this pattern, create a BehaviorSubject in a service, and a method to update it. Then in any component you inject the service into, call the method to update data, and/or subscribe to the services BehaviorSubject to get changes. Simple!

 Your service:

JamieCode2

Inject your service in your component: 

constructor(public service: BitcoinService) {} 

Updating the value from your component:

changeAmount(val) {
  this.service.augmentValue(val);

} 

Displaying a value in your template:

<p>{{ service.bitcoinValueSubject | async | currency }}</p> 

 

 The Angular Router

The Angular router is a smart way to manage state in your app, as well as pass data to child components in a way that’s familiar to the user: clicking links that change the url. Routing to child components allows you to read the route params, which is helpful. But how do you turn a route param into something meaningful? With route resolvers.

Route resolvers might sound scary, but all they do is prevent navigation to a route until the Observable returned by the resolver emits a value.

In the example in the demo, our resolver simply returns an http.get. The resolver's resolve() method accepts 1 argument, the activated route; so that we can request data specific to the params passed in the route.

The resolver:

JamieCode1
Your route configuration:

{
 path: ':symbol',

component: PriceComponent,
resolve: { coinData: CryptoResolver }
}

Your component:

JamieCode3

 

NgRx

Should you be passing data into your child components at all? Or would it be better to centrally manage all data and app state in one place? 

NgRx is a robust and powerful state management system based on redux (Ng Rx - see what they did there?). It's a reactive, observable wrapper around your api service, but it also manages app state from one place in your app - "a single source of truth".

With NgRx, each of your components access data with selectors that look like this:

entities$ = this.store.pipe(select(getAllEntitiesAsArray)); 

Create, modify or delete data with actions that look like this:

this.store.dispatch(new EntityAction({ entity: this.myEntity }));

Requests are used efficiently because the data is cached, but still kept in sync with the server. Small apps won't require NgRx, but when you are asked to build an enterprise-grade app for a client, it's nice to know you have NgRx at your disposal!

NgRx requires quite a lot of files to setup, but thankfully we at BrieBug have built a schematic to help you gen-out those files quickly from the command line. We call it the ngrx-entity-schematic. It will create all the necessary actions, reducers, and effects for any name you provide it, and it even includes tests! All you need to do is customize the model and the service to your backend.


 

Companies like BrieBug focus solely on Angular to help our enterprise clients navigate training, architecture reviews, and implementation of their important web applications. BrieBug is one of the top web application development firms in Colorado. For more information, contact us.