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.
-
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>
-
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