{"id":2341,"date":"2025-09-25T12:29:59","date_gmt":"2025-09-25T12:29:59","guid":{"rendered":"https:\/\/www.cmarix.com\/qanda\/?p=2341"},"modified":"2026-02-05T11:59:06","modified_gmt":"2026-02-05T11:59:06","slug":"role-of-viewcontainerref-templateref-in-angular-directives","status":"publish","type":"post","link":"https:\/\/www.cmarix.com\/qanda\/role-of-viewcontainerref-templateref-in-angular-directives\/","title":{"rendered":"What is the role of ViewContainerRef and TemplateRef in creating Advanced Custom Structural Directives?"},"content":{"rendered":"\n<p>Structural directives in Angular like *ngIf and *ngFor aren\u2019t just handy\u2014they\u2019re powerful tools for dynamic DOM manipulation. But what if you need custom logic that controls what shows up in the UI? That\u2019s where ViewContainerRef and TemplateRef come in. Together, they let you build advanced structural directives that render content conditionally based on complex logic like user permissions, roles, or feature flags.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What Do ViewContainerRef and TemplateRef Actually Do?<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>TemplateRef<\/strong> is like a blueprint for the DOM. It represents the content inside an ng-template and allows you to reuse that content wherever needed.<\/li>\n\n\n\n<li><strong>ViewContainerRef<\/strong> is the placeholder where you inject or remove views. It controls when and how the template gets added to the DOM.<\/li>\n<\/ul>\n\n\n\n<p>These two are often used together in structural directives to decide whether certain parts of the UI should be created or destroyed based on logic you define.<\/p>\n\n\n\n<p><strong>Real Example: A Custom *appHasPermission Directive<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>This directive only renders its content if a user has a specific permission.\nimport { Directive, Input, TemplateRef, ViewContainerRef, OnDestroy } from '@angular\/core';\nimport { AuthService } from '.\/auth.service';\nimport { Subscription } from 'rxjs';\n \n@Directive({\n  selector: '&#91;appHasPermission]'\n})\nexport class HasPermissionDirective implements OnDestroy {\n  private subscription: Subscription;\n  private hasView = false;\n \n  constructor(\n    private templateRef: TemplateRef&lt;unknown>,\n\tprivate viewContainer: ViewContainerRef,\n\tprivate authService: AuthService\n  ) {}\n \n  @Input() set appHasPermission(permission: string) {\n\tthis.subscription = this.authService.hasPermission(permission).subscribe(canView => {\n  \tif (canView &amp;&amp; !this.hasView) {\n    \tthis.viewContainer.createEmbeddedView(this.templateRef);\n    \tthis.hasView = true;\n  \t} else if (!canView &amp;&amp; this.hasView) {\n    \tthis.viewContainer.clear();\n    \tthis.hasView = false;\n  \t}\n\t});\n  }\n \n  ngOnDestroy() {\n\tthis.subscription?.unsubscribe();\n  }\n}\n \nUsage in a template: &lt;div *appHasPermission=\"'edit-article'\">...&lt;\/div><\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Final Thoughts<\/h2>\n\n\n\n<p>When used right, structural directives can make your app leaner, faster, and easier to manage. ViewContainerRef and TemplateRef aren\u2019t just for framework authors, they\u2019re powerful tools every serious Angular dev should understand. If you&#8217;re aiming to build advanced features without reinventing the wheel, it\u2019s a smart move to <a href=\"https:\/\/www.cmarix.com\/hire-angular-developers.html\">hire Angular developers<\/a> who already know how to apply these patterns efficiently.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Structural directives in Angular like *ngIf and *ngFor aren\u2019t just handy\u2014they\u2019re powerful tools for dynamic DOM manipulation. But what if you need custom logic that controls what shows up in the UI? That\u2019s where ViewContainerRef and TemplateRef come in. Together, they let you build advanced structural directives that render content conditionally based on complex logic [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":2342,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[7,3],"tags":[],"class_list":["post-2341","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-angular","category-web"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/posts\/2341","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/comments?post=2341"}],"version-history":[{"count":3,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/posts\/2341\/revisions"}],"predecessor-version":[{"id":2346,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/posts\/2341\/revisions\/2346"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/media\/2342"}],"wp:attachment":[{"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/media?parent=2341"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/categories?post=2341"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/tags?post=2341"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}