DEV Community

oppy_sb
oppy_sb

Posted on • Edited on

Angular Beginner's guide - Passing data within an application

Introduction

I started developing in Angular four years ago with my team. There are several concepts I wish I knew at the beginning. And this one is probably the main subject. I hope this can be helpful to anybody that would start working with angular.

What is it and why use Behaviour Subject

Behaviour subject is a component from the RxJx library. You can check the documentation here :
RxJs Behaviour Subject Documentation

A behaviour subject is basically an object that emits the current value to new subscribers.

So If you have a data structure, object or variable you want to share all the way through your application, this will be very useful.

Our Application example

So I created a new Angular project, and i added three components to create our main page.
It is a very simple application. So our page will have a header with a save button, a metadata part with an input text and a content part with a textarea. Of course this could be way more complex but the goal here is to show the principle of the behaviour subject.

What we would like to do is to disable the save button in the header when the metadata field and the content field are not filled.
All the source code can be found at this repository :
Source code in GitHub

Application look

Scafolding the components

For our page, we create a main component create-article, and inside this component we create our three components : header, metadata and content.

Scafolding components

I created a common folder to put in the services and models and everything that could be common or shared between the different components.
We put a model Article and a service for the state of the article.

Article state service

The Article and Article state

Our article interface, with the data from the metadata and content.

export interface Article {  

    /**  
     * the medata Infos     
     */    
     metadata?: string;  

    /**  
     * content field     
     */    
     content?: string;  

}
Enter fullscreen mode Exit fullscreen mode

And our article state class will look like this :

import { Injectable } from '@angular/core';  
import { BehaviorSubject } from "rxjs";  
import { Article } from "../model/Article";  

@Injectable({  
    providedIn: 'root'  
})  
export class ArticleStateService {  

    public readonly selectedArticleState$ = new BehaviorSubject<Article>([] as Article);  
    private selectedArticleState: Article = {} as Article;  

    public constructor() {  
    }  

    /**  
     * set the current article     
     * @param value  
     */  
    public setSelectedArticleState(value: Article): void {  
        this.selectedArticleState = value;  
        this.selectedArticleState$.next(this.selectedArticleState);  
    }  

    /**  
     * Get the current article    
     */    
     public getSelectedArticleState(): Article {  
        return <Article>this.selectedArticleState;  
    }  
}
Enter fullscreen mode Exit fullscreen mode

By convention, we suffix the behaviour Subject with a $. This behaviour subject is used to send the data to its subscribers. We use the selectedArticleState for storing the current Article value inside the class.
We also have a setter and a getter.

Let use our article state

So in the main component create-article, in the create-article-component.html, we use our 3 sub-components :

<app-header></app-header>  
<app-metadata></app-metadata>  
<app-content></app-content>
Enter fullscreen mode Exit fullscreen mode

Our header component

import {Component, OnInit} from '@angular/core';  
import {ArticleStateService} from "../../common/service/article-state.service";  
import {Article} from "../../common/model/Article";  

@Component({  
    selector: 'app-header',  
    templateUrl: './header.component.html',  
    styleUrls: ['./header.component.scss']  
})  
export class HeaderComponent implements OnInit {  
    public disabled: boolean;  

    public constructor(public readonly articleStateService: ArticleStateService) {  
    }  

    public ngOnInit(): void {  
        this.disabled = true;  
        this.articleStateService.selectedArticleState$.subscribe((article: Article) => {  
            if (article.content && article.metadata) {  
                this.disabled = !(article.content.length > 0 && article.metadata.length > 0);  
            } else {  
                this.disabled = true;  
            }  
        });  
    }  
}
Enter fullscreen mode Exit fullscreen mode

When the component is initialized, we subscribe to the behaviour subject, so anytime the article change, we will get here the current article.
For our application, we can set the disabled variable to the right value, depending on the content and the metadata values.

The setting of the article state

For example, in the metadata component we create a formGroup for the metadata field and when the value changes we set the current article from the state with its value.

import {Component, OnInit} from '@angular/core';  
import {FormControl, FormGroup, Validators} from "@angular/forms";  
import {Article} from "../../common/model/Article";  
import {ArticleStateService} from "../../common/service/article-state.service";  

@Component({  
    selector: 'app-metadata',  
    templateUrl: './metadata.component.html',  
    styleUrls: ['./metadata.component.scss']  
})  
export class MetadataComponent implements OnInit {  
    public metadataForm: FormGroup;  

    constructor(public articleStateService: ArticleStateService) {  
        // We create a formGroup for the metadata field
        this.metadataForm = new FormGroup({  
            metadata: new FormControl(  
                '', [Validators.required])  
        });  
    }  

    public ngOnInit(): void {  
        this.metadataForm.valueChanges.subscribe(formGroup => {  
            // We get the current article with the article state service
            const article: Article = this.articleStateService.getSelectedArticleState();  
            // We set the metadata in the current article to the formGroup metadata value
            article.metadata = formGroup.metadata;  
            // We set it back in the state service as the current article
            this.articleStateService.setSelectedArticleState(article);  
        });  

    }  
}
Enter fullscreen mode Exit fullscreen mode

The end

I hope this post can be useful to anybody, beginner or not in Angular. You can find the unit tests for the components and service in the github repository.
Please let me know what you think.
Do you use the behaviour subjects that way in your applications?
Do you have other ways of doing it ?

Top comments (0)