[Fixed] Angular best practise where to place strings changing on state

Issue

Let’s imagine I have an Angular component which proceed an API call and react to the response appropriately. The component contains four states:

  • init
  • pulling
  • success
  • error

Depending on its state the component displays the current state as string to the frontend in html.

So is it better to have a variable (myStateText) that changes the displaying text…

enum State {
    INIT, PULLING, SUCCESS, ERROR
}

@Component({
    selector: 'app-test',
    templateUrl: './test.component.html',
    styleUrls: ['./test.component.scss'],
})
export class TestComponent implements OnInit {

    public myState: State;
    public myStateText: string;

    ngOnInit(): void {
        this.myState = State.INIT;
        this.myStateText = 'I am ready';
    }

    public startProcess(): void {
        this.myState = State.PULLING;
        this.myStateText = 'Please wait';

        apiCall.subscribe(response => {
            this.myState = State.SUCCESS;
            this.myStateText = 'Hurray';
        }, error => {
            this.myState = State.ERROR;
            this.myStateText = 'Not hurray';
        });
    }
}

… or should I switch case the states in html:

<ng-container [ngSwitch]="myState">
    <h2 *ngSwitchCase="state.INIT">I am ready</h2>
    <h2 *ngSwitchCase="state.PULLING">Please wait</h2>
    <h2 *ngSwitchCase="state.SUCCESS">Hurray</h2>
    <h2 *ngSwitchCase="state.ERROR">Not hurray</h2>
</ng-container>

Is there a definite decision or it depends on how many states I have or how many html content changes for each state?

Solution

It completely depends on how well you want to manage your code which makes refactoring & organising easier.

  1. In the above scenario you could keep your states as an exported constant of key value pairs and keep in a central config. Import the constant into which ever components you want to, say component A & B. This way you could easily change the message string without touching any of the components ts & html file when in need.

    export const myState = {
     INIT: "I am ready",
     PULLING: "Please wait",
     SUCCESS: "Hurray",
     ERROR: "Not hurray",
     COMPLETE: "Im done",
     CLEAR: ""
    };
    
    this.myStateText = myState.SUCCESS;
    
    <h2>{{myStateText}}</h2>
    
  2. If you have to send your states to more that one component at the same time you can consider BehaviorSubject.

    // Component A
    public subject = new BehaviorSubject(myState.INIT);
    public myStateText: string;
    
    ngOnInit(): void {
     this.subject.subscribe(newState => (this.myStateText = newState));
    }
    
    //You can change the values as below.
    this.subject.next(myState.PULLING);
    
    {{myStateText}} // OUTPUT:- 'I am ready' & then 'Please wait'
    

In component B also you would do ‘this.subject.subscribe’ to get the new values.

Stackblitz – https://stackblitz.com/edit/behaviorsubject-example-eue4v5?file=app/app.component.ts

More on behaviour subject – https://www.learnrxjs.io/learn-rxjs/subjects/behaviorsubject

Leave a Reply

(*) Required, Your email will not be published