Search code examples
htmlangulartypescriptangular-signals

Best Practices for Nested Optional Checks in Angular Template with Signals


I have a setup in my Angular project where I need to conditionally render a component based on nested properties of an object. Here's a simplified version of the scenario:

projectSignal is a Signal<Project | undefined> where Project can contain an array of Task objects. Each Task object can contain a Permission object.

I'm using Angular's template syntax to conditionally check for the existence of these nested properties before rendering a component. Here’s the code snippet I have:

TS: projectSignal: Signal<Project | undefined> = toSignal(this.store.select(selectActiveProject));

and the corresponding HTML:

  @if(project.tasks[0]; as task){
    @if(task.permission; as permission){
      <app-permission [permissionsSelected]="permission"></app-permission>
    }
  }
}

While this works, the nested *ngIf directives feel cumbersome and not very elegant. Is there a cleaner or more efficient way to handle such nested optional checks in Angular templates and signals ?

Additional Information:

projectSignal is derived from a state management store using toSignal. The presence of project, tasks, and permission is optional and should be checked before accessing their properties. I'm looking for best practices or recommendations to simplify or improve this code. Any advice or suggestions would be greatly appreciated!


Solution

  • We can also use computed to get the inner permission and directly use it on the if condition. Compute will run when the source signal changes.

    TS:

    projectSignal: Signal<Project | undefined> = toSignal(this.store.select(selectActiveProject));
    permission: Signal<Permission | undefined> = computed(() => this.projectSignal()?.tasks?.[0]?.permission);
    

    HTML:

    @if(permission(); as permission){
      <app-permission [permissionsSelected]="permission"></app-permission>
    }
    

    We can use Typescript's type safe check ?. to perform the null checking on a single if condition and then show the component.

    @if(project?.tasks?.[0]?.permission; as permission){
      <app-permission [permissionsSelected]="permission"></app-permission>
    }