Discover how to clean up your Angular templates and make your UI logic reusable with just a few lines of code!
Why Custom structural directives in Angular? - Purpose & Use Cases
Start learning this pattern below
Jump into concepts and practice - no test required
Imagine you want to show or hide parts of your webpage based on complex rules, like user roles or feature flags, and you have to write the same logic everywhere in your HTML templates.
Manually repeating show/hide logic clutters your templates, makes them hard to read, and if you need to change the rule, you must update many places, risking mistakes and bugs.
Custom structural directives let you create reusable, clean, and easy-to-understand commands that control the structure of your page, so you write the logic once and use it everywhere effortlessly.
*ngIf="user.isAdmin && featureEnabled"<br> <!-- content -->*appShowIfAdminFeature<br> <!-- content -->
It enables you to build clear, reusable, and maintainable templates that adapt dynamically without repeating complex logic.
Showing special admin controls only to users with admin rights and when a feature is enabled, using a simple directive instead of repeating conditions everywhere.
Manual logic repetition makes templates messy and error-prone.
Custom structural directives encapsulate complex display rules.
They improve code clarity, reuse, and maintenance.
Practice
Solution
Step 1: Understand structural directives role
Structural directives change the structure of the DOM by adding or removing elements.Step 2: Identify the main use case
Custom structural directives let you control when parts of the page appear or disappear dynamically.Final Answer:
To add or remove HTML elements dynamically based on conditions -> Option DQuick Check:
Structural directives = dynamic HTML blocks [OK]
- Confusing structural directives with attribute directives
- Thinking they handle styling or events
- Assuming they fetch data
Solution
Step 1: Identify dependencies for structural directives
Structural directives need TemplateRef to access the template and ViewContainerRef to insert or remove views.Step 2: Match constructor parameters
constructor(private templateRef: TemplateRef<any>, private viewContainer: ViewContainerRef) {} correctly injects TemplateRef and ViewContainerRef, which are essential for custom structural directives.Final Answer:
constructor(private templateRef: TemplateRef<any>, private viewContainer: ViewContainerRef) {} -> Option CQuick Check:
TemplateRef + ViewContainerRef = constructor params [OK]
- Injecting ElementRef or Renderer2 which are for attribute directives
- Injecting unrelated services like HttpClient or Router
- Missing TemplateRef or ViewContainerRef
appShowIf input is false?@Directive({ selector: '[appShowIf]' })
export class ShowIfDirective {
constructor(private templateRef: TemplateRef<any>, private viewContainer: ViewContainerRef) {}
@Input() set appShowIf(condition: boolean) {
if (condition) {
this.viewContainer.createEmbeddedView(this.templateRef);
} else {
this.viewContainer.clear();
}
}
}Usage:
<div *appShowIf="false">Hello World</div>
Solution
Step 1: Analyze the directive behavior when condition is false
WhenappShowIfis false,viewContainer.clear()removes any embedded views, so nothing is rendered.Step 2: Understand the usage effect
The<div>with 'Hello World' is inside the template controlled by the directive, so it won't appear if condition is false.Final Answer:
Nothing will be rendered inside the div -> Option AQuick Check:
False condition = no content shown [OK]
- Thinking the div still renders empty
- Assuming an error occurs
- Confusing attribute directives with structural directives
@Directive({ selector: '[appIf]' })
export class IfDirective {
constructor(private templateRef: TemplateRef<any>) {}
@Input() set appIf(condition: boolean) {
if (condition) {
this.templateRef.createEmbeddedView();
}
}
}Solution
Step 1: Check constructor dependencies
The directive injects only TemplateRef but misses ViewContainerRef, which is needed to insert or clear views.Step 2: Analyze method usage
CallingcreateEmbeddedView()on TemplateRef alone is invalid; it should be called on ViewContainerRef with TemplateRef as argument.Final Answer:
Missing ViewContainerRef injection and usage to insert the view -> Option BQuick Check:
ViewContainerRef required to add views [OK]
- Trying to create views directly from TemplateRef
- Forgetting to inject ViewContainerRef
- Misnaming input properties
*appUnless that shows content only when a condition is false. Which implementation correctly achieves this behavior?Solution
Step 1: Understand the directive goal
*appUnlessshould show content only when the condition is false, so the view is created when!condition.Step 2: Match logic to code
Usingif (!condition)to create the embedded view and clearing it otherwise matches the requirement.Final Answer:
Useif (!condition)to create the embedded view, else clear it -> Option AQuick Check:
Show content when false = if (!condition) create view [OK]
- Using if (condition) instead of if (!condition)
- Not clearing the view when condition is true
- Creating view unconditionally
