Angular – CMARIX QandA https://www.cmarix.com/qanda Fri, 10 Oct 2025 11:10:42 +0000 en-US hourly 1 https://wordpress.org/?v=6.9 How Angular Managed Two-Way Binding with @Input() & @Output() Before model() https://www.cmarix.com/qanda/angular-two-way-binding-input-output-before-model/ https://www.cmarix.com/qanda/angular-two-way-binding-input-output-before-model/#respond Fri, 10 Oct 2025 11:10:39 +0000 https://www.cmarix.com/qanda/?p=2443 In the traditional Angular approach, creating two-way binding meant setting up both an @Input() to receive data and an @Output() to emit changes. You also needed to wire up event emitters manually. This pattern worked, but it added boilerplate and split the logic for incoming and outgoing data. What model() Signal Does Differently Introduced in […]

The post How Angular Managed Two-Way Binding with @Input() & @Output() Before model() appeared first on CMARIX QandA.

]]>
In the traditional Angular approach, creating two-way binding meant setting up both an @Input() to receive data and an @Output() to emit changes. You also needed to wire up event emitters manually. This pattern worked, but it added boilerplate and split the logic for incoming and outgoing data.

What model() Signal Does Differently

Introduced in Angular v17, the model() signal replaces the old binding setup with a single, writable signal. This signal acts both as an input and an output. When the parent updates the bound property, the signal gets updated. When the child sets a new value, that change automatically reflects back in the parent.

Comparing Old vs. New in a Real Example

Old Way Using @Input() and @Output()

@Component({
 selector: 'app-custom-input-old',
 template: `<input [value]="value" (input)="onValueChange($event)">`
})
export class CustomInputOldComponent {
 @Input() value: string = '';
 @Output() valueChange = new EventEmitter<string>();

 onValueChange(event: Event) {
   const target = event.target as HTMLInputElement;
   this.valueChange.emit(target.value);
 }
}

Usage:

<app-custom-input-old [(value)]="parentProperty"></app-custom-input-old>

New Way Using model()

@Component({
 selector: 'app-custom-input-new',
 standalone: true,
 template: `<input [value]="value()" (input)="onValueChange($event)">`
})
export class CustomInputNewComponent {
 value = model.required<string>();

 onValueChange(event: Event) {
   const target = event.target as HTMLInputElement;
   this.value.set(target.value);
 }
}

Usage:

<app-custom-input-new [(value)]="parentProperty"></app-custom-input-new>

Why model() Improves Component Design

  • Less Code, Fewer Mistakes
    You define the binding in one place. No need for extra decorators or emitters.
  • Cleaner State Management
    The writable signal makes it clear where state comes from and where it goes.
  • Reactive by Nature
    Since it’s a signal, you can hook into changes with computed() or effect() without extra wiring.

Conclusion

The model() signal simplifies two-way binding into a single, readable, and reactive property. It cuts boilerplate, unifies component state, and improves maintainability. If you’re serious about building modern Angular apps with cleaner architecture and fewer moving parts, it’s time to embrace signals. And if you want expert help modernizing your codebase, hire Angular developers who already work with signals and understand how to architect with model() at the core. It’ll save you time, money, and future headaches.

The post How Angular Managed Two-Way Binding with @Input() & @Output() Before model() appeared first on CMARIX QandA.

]]>
https://www.cmarix.com/qanda/angular-two-way-binding-input-output-before-model/feed/ 0
Angular inject() Advanced Use Cases Every Developer Should Know https://www.cmarix.com/qanda/angular-advanced-inject-function-use-cases/ https://www.cmarix.com/qanda/angular-advanced-inject-function-use-cases/#respond Fri, 10 Oct 2025 10:47:28 +0000 https://www.cmarix.com/qanda/?p=2437 The inject() function offers a more flexible way to access dependencies. While it can be used in component properties as an alternative to the constructor, its real power shines when used outside of the traditional class-based DI context. Why Use inject() in Advanced Scenarios? An advanced use case is creating reusable, higher-order functions (HoFs) that […]

The post Angular inject() Advanced Use Cases Every Developer Should Know appeared first on CMARIX QandA.

]]>
The inject() function offers a more flexible way to access dependencies. While it can be used in component properties as an alternative to the constructor, its real power shines when used outside of the traditional class-based DI context.

Why Use inject() in Advanced Scenarios?

An advanced use case is creating reusable, higher-order functions (HoFs) that are DI-aware. These are functions that can be exported and used across your application in a functional style, while still having access to Angular’s services. This is impossible with constructor injection, which is tied to a class instance.

Example: DI-Aware Route Guard with inject()

Traditionally, route guards are classes that implement an interface (CanActivate). With inject(), you can define a guard as a simple, reusable function, making your code more concise and functional.

Let’s create a feature flag guard function. It will use an injected FeatureFlagsService to check if a feature is enabled before allowing access to a route.

Feature Flag Service

// in feature-flags.service.ts
@Injectable({ providedIn: 'root' })
export class FeatureFlagsService {
  private featureFlags = new Map<string, boolean>([
	['newDashboard', true],
	['adminPanel', false]
  ]);
 
  isFeatureEnabled(featureName: string): boolean {
	return this.featureFlags.get(featureName) ?? false;
  }
}
 
// in auth.guards.ts (our DI-aware function)
import { inject } from '@angular/core';
import { Router } from '@angular/router';
import { FeatureFlagsService } from './feature-flags.service';
 
// This is just a function, not a class!
export const featureFlagGuard = (featureName: string) => {
  return () => { // The actual guard function returned
	const featureFlagsService = inject(FeatureFlagsService);
	const router = inject(Router);
 
	if (featureFlagsService.isFeatureEnabled(featureName)) {
  	return true;
	}
 
	// Redirect to a 'feature disabled' page or the home page
	return router.parseUrl('/feature-unavailable');
  };
};
 
// in app.routes.ts
import { Routes } from '@angular/router';
import { featureFlagGuard } from './auth.guards';
 
export const routes: Routes = [
  {
	path: 'new-dashboard',
	component: NewDashboardComponent,
	canActivate: [featureFlagGuard('newDashboard')] // -> Will allow access
  },
  {
	path: 'admin',
	component: AdminPanelComponent,
	canActivate: [featureFlagGuard('adminPanel')] // -> Will redirect
  }
];

This pattern is incredibly powerful. The featureFlagGuard is a factory for route guards. It’s clean, reusable, testable, and leverages DI without the boilerplate of a class, which is a perfect example of modern, functional Angular code.

Conclusion

Using inject() in functions lets you break free from class-only dependency injection. It enables cleaner, more flexible patterns like DI-aware route guards, without the boilerplate of classes. This is especially useful as Angular evolves toward a more functional, signal-driven approach. To take full advantage of these patterns, it’s smart to hire Angular developers who understand how to build with inject() beyond the basics. The result is code that’s easier to test, reuse, and scale.

The post Angular inject() Advanced Use Cases Every Developer Should Know appeared first on CMARIX QandA.

]]>
https://www.cmarix.com/qanda/angular-advanced-inject-function-use-cases/feed/ 0
What are the Practical Steps and Architectural Implications of Building a Fully Zoneless Angular Application? https://www.cmarix.com/qanda/build-a-zoneless-angular-app-steps-and-architecture/ https://www.cmarix.com/qanda/build-a-zoneless-angular-app-steps-and-architecture/#respond Fri, 26 Sep 2025 11:04:54 +0000 https://www.cmarix.com/qanda/?p=2372 A zoneless application is an Angular app that operates without the zone.js library. This is a major architectural decision that provides more granular control over change detection and improves performance by eliminating the overhead of Zone.js’s automatic change detection triggers. This is introduced with the introduction to Angular Signals. Architectural Implications: Practical Steps to Go […]

The post What are the Practical Steps and Architectural Implications of Building a Fully Zoneless Angular Application? appeared first on CMARIX QandA.

]]>
A zoneless application is an Angular app that operates without the zone.js library. This is a major architectural decision that provides more granular control over change detection and improves performance by eliminating the overhead of Zone.js’s automatic change detection triggers. This is introduced with the introduction to Angular Signals.

Architectural Implications:

  • Explicit Change Detection: You are now 100% responsible for telling Angular when to check for changes. Automatic updates from setTimeout, events, or Promise resolutions will no longer happen.
  • Primacy of Signals: Signals become the primary mechanism for state management. When a signal’s value changes, Angular knows precisely which components that consume that signal need to be re-rendered, without needing to check the entire component tree.
  •  Rethinking Asynchronous Code: Libraries or native browser APIs that rely on Zone.js to trigger UI updates will need to be handled manually. You’ll often use patterns like toSignal from @angular/core/rxjs-interop or manually call ChangeDetectorRef.detectChanges() in specific, controlled scenarios.

Practical Steps to Go Zoneless:

1. Bootstrap without zone.js

In your main.ts file, you configure the application bootstrap to be zoneless.

// in main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { provideRouter } from '@angular/router';
import { appRoutes } from './app/app.routes';
 
bootstrapApplication(AppComponent, {
  providers: [
	provideRouter(appRoutes),
	{ provide: 'ngZone', useValue: 'noop' } // The key step!
  ]
});

2. Convert State to Signals

All component states that can change and affect the view must be managed with signals (signal, computed, effect).

import { Component, signal, computed, effect } from '@angular/core';
 
@Component({
  selector: 'app-counter',
  standalone: true,
  template: `
	<p>Count: {{ count() }}</p>
	<p>Double: {{ double() }}</p>
	<button (click)="increment()">Increment</button>
  `
})
export class CounterComponent {
  count = signal(0);
  double = computed(() => this.count() * 2);
 
  constructor() {
	// Effects run automatically when their dependent signals change
	effect(() => {
     console.log(`The count is now: ${this.count()}`);
	});
  }
 
  increment() {
	this.count.update(c => c + 1);
	// NO ChangeDetectorRef.detectChanges() needed!
	// The template is bound to the signal, and Angular handles the update.
  }
}

3. Handle External Asynchronicity 

For things that aren’t signals (e.g., a third-party library’s event callback), you must manually integrate them.

import { Component, signal, ChangeDetectorRef, inject } from '@angular/core';
 
declare const thirdPartyLibrary: any; // Assume this library exists
 
@Component({...})
export class ThirdPartyComponent {
  data = signal<string>('Initial data');
  private cdr = inject(ChangeDetectorRef);
 
  ngOnInit() {
	// This callback is outside Angular's world
	thirdPartyLibrary.onDataReceived((newData) => {
  	this.data.set(newData);
  	// In a zoneless app with a non-signal binding, you might need this.
  	// However, the best practice is to have the template bind directly to the signal.
  	// If the template was `<div>{{ rawDataProperty }}</div>`, you would need:
  	// this.rawDataProperty = newData;
  	// this.cdr.detectChanges();
	});
  }
}

Final Words

Zoneless Angular apps give you more control and better performance by removing the overhead of zone.js. But this also means you’re fully in charge of when and how UI updates happen. That’s where Angular Signals come in. They manage the state precisely, it adopts this setup smoothly. It also helps to hire Angular developers who understand signal-based reactivity and manual change detection.

The post What are the Practical Steps and Architectural Implications of Building a Fully Zoneless Angular Application? appeared first on CMARIX QandA.

]]>
https://www.cmarix.com/qanda/build-a-zoneless-angular-app-steps-and-architecture/feed/ 0
How do Deferrable Views (@defer) improve lazy loading in Angular, and what’s an advanced use case? https://www.cmarix.com/qanda/deferrable-views-in-angular-improve-lazy-loading/ https://www.cmarix.com/qanda/deferrable-views-in-angular-improve-lazy-loading/#respond Fri, 26 Sep 2025 10:41:29 +0000 https://www.cmarix.com/qanda/?p=2365 Angular v17 introduced @defer blocks, a smarter way to lazy load content right inside templates. Instead of relying solely on route-level lazy loading, you can now delay rendering specific sections like charts, modals, or comment threads until they’re actually needed.  How @defer Works Instead of loading everything at once, Angular’s @defer lets you wait to […]

The post How do Deferrable Views (@defer) improve lazy loading in Angular, and what’s an advanced use case? appeared first on CMARIX QandA.

]]>
Angular v17 introduced @defer blocks, a smarter way to lazy load content right inside templates. Instead of relying solely on route-level lazy loading, you can now delay rendering specific sections like charts, modals, or comment threads until they’re actually needed. 

How @defer Works

Instead of loading everything at once, Angular’s @defer lets you wait to load certain elements such as charts or extra content, until users scroll or click.

Advanced Triggering Strategies:

The true power of @defer lies in its rich set of triggers, which go far beyond simple visibility.

  • on viewport: Triggers when the placeholder enters the viewport.
  • on interaction: Triggers on click or input events within the placeholder.
  • on hover: Triggers when the mouse hovers over the placeholder area.
  • on timer(x): Triggers after a specified duration.
  • when <expression>: The most powerful trigger, which loads the content when a boolean expression becomes true. This is perfect for programmatic control.

You can also combine triggers. For instance,setting up a component to load when it’s visible or when the browser is idle, whichever comes first.

Practical Example (Prefetching a Heavy Component on Hover):

Imagine a dashboard with several cards, one of which opens a complex and data-intensive “Reporting” modal. We want to load the ReportingComponent’s code as soon as the user hovers over the “Open Report” button. Doing so, gives the Angular app enough time to make the component ready. So when the user clicks the button, it is already loaded.

<!-- in dashboard.component.html -->
<h2>Quarterly Sales Overview</h2>
<p>Some summary data for the dashboard...</p>
 
<!-- The @defer block for the reporting component -->
@defer (on hover; on interaction) {
  <app-reporting-modal [data]="salesData"></app-reporting-modal>
} @placeholder {
  <!-- This is what's shown initially. We can style it to look like a disabled button -->
  <button class="btn btn-primary-outline">Open Report</button>
} @loading {
  <!-- Optional: show a spinner while the component chunk is being downloaded -->
  <button class="btn btn-primary-outline" disabled>
	<span class="spinner-border spinner-border-sm"></span>
	Loading Report...
  </button>
}

Deferrable Views in Angular – How it works:

  • Initially, only the placeholder button is rendered. The ReportingModalComponent and its dependencies are not loaded.
  • When the user’s mouse hovers over the button (on hover), @defer starts prefetching the JavaScript chunk for ReportingModalComponent in the background.
  • If the user clicks the button (on interaction), the block is triggered immediately.
  • By the time the click happens, the code is likely already prefetched, leading to a near-instantaneous rendering of the modal and a vastly improved user experience.

Conclusion

@defer is a smart way to speed up your Angular app by loading heavy components only when needed. It gives you control over what loads and when, directly in your templates. If you want to build fast, efficient apps without overcomplicating the code, it’s a smart move to hire Angular developers who already know how to use features like @defer effectively.

The post How do Deferrable Views (@defer) improve lazy loading in Angular, and what’s an advanced use case? appeared first on CMARIX QandA.

]]>
https://www.cmarix.com/qanda/deferrable-views-in-angular-improve-lazy-loading/feed/ 0
How can you Extend the Angular CLI’s Build Process with a Custom Webpack Configuration? https://www.cmarix.com/qanda/extend-angular-cli-build-with-custom-webpack-config/ https://www.cmarix.com/qanda/extend-angular-cli-build-with-custom-webpack-config/#respond Fri, 26 Sep 2025 10:14:34 +0000 https://www.cmarix.com/qanda/?p=2360 The Angular CLI is a great tool for abstracting away complex building steps. For some situations, abstraction can cause problems, especially when you need custom loaders, plugins, or advanced optimizations. In such situations it’s best to extend the build process with a custom Webpack configuration. Angular CLI uses Webpack, but it does not expose it […]

The post How can you Extend the Angular CLI’s Build Process with a Custom Webpack Configuration? appeared first on CMARIX QandA.

]]>
The Angular CLI is a great tool for abstracting away complex building steps. For some situations, abstraction can cause problems, especially when you need custom loaders, plugins, or advanced optimizations. In such situations it’s best to extend the build process with a custom Webpack configuration.

Angular CLI uses Webpack, but it does not expose it directly. You need to hire Angular developers to make the most out of Webpack without breaking your project structure. They would know how to use the @angular-builders/custom-webpack. 

Why Customize Webpack in Angular?

Sometimes, the default Angular setup doesn’t cover everything you need. Here’s why you might want to tweak Webpack:

  • Add support for new file types like Markdown or custom loaders
  • Set global variables or environment settings
  • Improve how your app is bundled or analyze the final output
  • Add tools for compression or split large files more efficiently

The good part? You don’t need to throw away Angular’s default settings. You just add your custom Webpack settings on top. 

Step-by-Step: Extending Angular Build with Custom Webpack

1. Install the Custom Webpack Builder

npm install --save-dev @angular-builders/custom-webpack

2. Create a Custom Webpack Config File

Create a file called extra-webpack.config.js in your project root. Add any standard Webpack settings here.

// extra-webpack.config.js
const webpack = require('webpack');

module.exports = {
  plugins: [
    new webpack.DefinePlugin({
      MY_ENV_FLAG: JSON.stringify(true)
    })
  ]
};

3. Update angular.json to Use the Custom Builder

Open your angular.json and find the build and serve targets. Replace the default Angular CLI builder with the custom one and point to your new config file.

Update the build section like this:

"architect": {
  "build": {
    "builder": "@angular-builders/custom-webpack:browser",
    "options": {
      "customWebpackConfig": {
        "path": "./extra-webpack.config.js"
      },
      "outputPath": "dist/your-project-name",
      ...
    },
Update the serve section similarly:
"serve": {
  "builder": "@angular-builders/custom-webpack:dev-server",
  "options": {
    "browserTarget": "your-project-name:build"
  }
}

4. Run the Build or Serve Command

Now just build or serve like usual:

ng serve
# or
ng build

When to Use This

This approach makes sense when you:

  • Need to extend your app’s build without ditching the CLI
  • Want to avoid setting up Webpack from scratch
  • Are integrating third-party tools that need specific build tweaks

And if it sounds too deep or time-consuming, it’s often faster to hire Angular developers who already know how to do this well. This helps you avoid unnecessary build headaches and get better performance without having too much trial and error.

Final Thoughts

Angular CLI keeps things simple but sometimes you need that extra bit of control. With @angular-builders/custom-webpack, you get the best of both worlds: a solid default setup and room for your advanced tweaks.

And if all this sounds like a rabbit hole, you don’t have to go it alone. It’s often faster and smarter to hire Angular developers who know exactly how to fine-tune your build for performance, flexibility, and long-term maintainability.

The post How can you Extend the Angular CLI’s Build Process with a Custom Webpack Configuration? appeared first on CMARIX QandA.

]]>
https://www.cmarix.com/qanda/extend-angular-cli-build-with-custom-webpack-config/feed/ 0
How do you Create a Custom Angular Schematic to Automate Boilerplate and Enforce Conventions? https://www.cmarix.com/qanda/create-custom-angular-schematics-to-automate-boilerplate/ https://www.cmarix.com/qanda/create-custom-angular-schematics-to-automate-boilerplate/#respond Thu, 25 Sep 2025 13:21:04 +0000 https://www.cmarix.com/qanda/?p=2354 Angular Schematics are powerful tools for transforming your codebase. They are the same technology that powers ng new, ng generate component, and ng add. By creating your own, you can eliminate repetitive tasks, enforce architectural patterns, and ensure your team builds features in a consistent and predictable way. This guide will walk you through building […]

The post How do you Create a Custom Angular Schematic to Automate Boilerplate and Enforce Conventions? appeared first on CMARIX QandA.

]]>
Angular Schematics are powerful tools for transforming your codebase. They are the same technology that powers ng new, ng generate component, and ng add. By creating your own, you can eliminate repetitive tasks, enforce architectural patterns, and ensure your team builds features in a consistent and predictable way.

This guide will walk you through building a custom schematic from scratch. Our goal is to create a schematic that generates a complete “feature” module, including:

  • An Angular Module (.module.ts)
  • A Component (.component.ts, .html, .scss, .spec.ts)
  • A Service (.service.ts, .spec.ts)
  • A routing configuration file (-routing.module.ts)
  • Automatic registration of the new feature route in the main app-routing.module.ts.

This automates significant boilerplate and enforces the convention of using feature modules with their own routing.

Core Concepts You Need to Understand

Tree

The most important concept. A Tree is a virtual representation of your filesystem. Schematics don’t write directly to your disk; they operate on this Tree. They can read, create, update, and delete files within it. Only when the schematic run is successful are the changes from the Tree applied to your real filesystem. This makes operations safe and atomic.

Rule

A Rule is a function that takes a Tree and returns a new Tree. This is the heart of a schematic’s logic. You chain together Rules to perform a series of transformations (e.g., a rule to create files from a template, a rule to modify an existing module, etc.).

SchematicContext

 An object that provides context and utilities for a Rule, such as logging and access to the schematic’s collection information.

collection.json

A manifest file that describes your set of schematics. It maps a schematic name (e.g., create-feature) to the factory function that executes it and points to a schema file for defining command-line options.

Templates

Schematics use special template files to generate dynamic output. You can use placeholders like <%= variableName %> that get replaced with the options provided by the user.

Step-by-Step Practical Example: ng generate feature

Step 1: Set Up the Schematics Project

First, you need the Schematics CLI.

npm install -g @angular-devkit/schematics-cli

Now, create a new blank schematics project.

schematics blank --name=custom-schematics
cd custom-schematics
npm install

Your project structure will look like this:

custom-schematics/
├── src/
│   ├── collection.json         # The manifest for your schematics
│   └── custom-schematics/      # A sample schematic
│       ├── index.js
│       └── index_spec.js
└── package.json

Let’s rename the sample schematic to feature and convert the files to TypeScript.

mv src/custom-schematics src/feature
mv src/feature/index.js src/feature/index.ts
mv src/feature/index_spec.js src/feature/index_spec.ts

Step 2: Define the Schematic in collection.json

This file is the entry point for the Angular CLI. Update src/collection.json to describe our new feature schematic.

{
  "$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
  "schematics": {
    "feature": {
      "description": "Generates a new feature module with a component, service, and routing.",
      "factory": "./feature/index#feature",
      "schema": "./feature/schema.json"
    }
  }
}
  • “feature”: The name of our schematic (ng generate feature …).
  • “factory”: Points to the main factory function (feature) inside index.ts.
  • “schema”: Points to a JSON schema file where we’ll define the available command-line options.

Step 3: Define the User Options in schema.json

Create a new file src/feature/schema.json. This file defines the parameters our schematic will accept, like –name.

{
  "$schema": "http://json-schema.org/schema",
  "id": "FeatureSchematic",
  "title": "Feature Schematic",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "description": "The name of the feature.",
      "$default": {
        "$source": "argv",
        "index": 0
      },
      "x-prompt": "What is the name of the feature?"
    },
    "path": {
      "type": "string",
      "description": "The path to create the feature in.",
      "default": "app/features"
    }
  },
  "required": [
    "name"
  ]
}
  • name: The feature’s name (e.g., “orders”, “profile”).
    • $source: “argv”, index: 0 means the first argument passed in the command line will be used as the name (e.g., ng g feature my-feature).
    • x-prompt provides a nice interactive prompt if the name isn’t supplied.
  • path: Where to place the new feature folder. We default it to app/features.

We also need a schema.d.ts file to get TypeScript typings for our options. Create src/feature/schema.d.ts:

export interface Schema {
  /**
   * The name of the feature.
   */
  name: string;
  /**
   * The path to create the feature in.
   */
  path: string;
}

Step 4: Create the Template Files

This is the boilerplate we want to generate. Create a files folder inside src/feature. The special __name@dasherize__ syntax will be replaced with the dasherized version of the name option (e.g., “my-feature”).

src/feature/files/
└── __name@dasherize__/
    ├── __name@dasherize__.component.html
    ├── __name@dasherize__.component.scss
    ├── __name@dasherize__.component.spec.ts
    ├── __name@dasherize__.component.ts
    ├── __name@dasherize__.module.ts
    ├── __name@dasherize__-routing.module.ts
└── __name@dasherize__.service.ts

Example Template File:

Notice the use of <%= … %> templating syntax. The classify and dasherize functions are helpers we’ll use in our logic.

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { <%= classify(name) %>RoutingModule } from './<%= dasherize(name) %>-routing.module';
import { <%= classify(name) %>Component } from './<%= dasherize(name) %>.component';
import { <%= classify(name) %>Service } from './<%= dasherize(name) %>.service';

@NgModule({
  declarations: [
    <%= classify(name) %>Component
  ],
  imports: [
    CommonModule,
    <%= classify(name) %>RoutingModule
  ],
  providers: [
    <%= classify(name) %>Service
  ]
})
export class <%= classify(name) %>Module { }

Example Template File:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { <%= classify(name) %>Component } from './<%= dasherize(name) %>.component';

const routes: Routes = [{ path: '', component: <%= classify(name) %>Component }];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class <%= classify(name) %>RoutingModule { }

Step 5: Write the Main Schematic Logic in index.ts

This is where everything comes together. Replace the content of src/feature/index.ts with the following:

import {
  Rule,
  SchematicContext,
  Tree,
  apply,
  url,
  template,
  move,
  chain,
  mergeWith,
} from '@angular-devkit/schematics';
import { strings } from '@angular-devkit/core';
import { Schema } from './schema';
import { addRouteDeclarationToNgModule } from '@schematics/angular/utility/ast-utils';
import { InsertChange } from '@schematics/angular/utility/change';
import * as ts from 'typescript';

// Function to add the new route to app-routing.module.ts
function addRouteToNgModule(options: Schema): Rule {
  return (tree: Tree, _context: SchematicContext) => {
    const appRoutingModulePath = 'src/app/app-routing.module.ts';
    const featureName = options.name;
    const featurePath = `${options.path}/${strings.dasherize(featureName)}/${strings.dasherize(featureName)}.module`;

    const text = tree.read(appRoutingModulePath);
    if (!text) {
      _context.logger.error(`Could not find ${appRoutingModulePath}.`);
      return tree;
    }

    const sourceText = text.toString('utf-8');
    const sourceFile = ts.createSourceFile(
      appRoutingModulePath,
      sourceText,
      ts.ScriptTarget.Latest,
      true
    );

    const route = `{
      path: '${strings.dasherize(featureName)}',
      loadChildren: () => import('./features/${strings.dasherize(featureName)}/${strings.dasherize(featureName)}.module').then(m => m.${strings.classify(featureName)}Module)
    }`;

    // Use AST utils to find the routes array and insert the new route
    const changes = addRouteDeclarationToNgModule(
      sourceFile,
      appRoutingModulePath,
      route
    );

    const recorder = tree.beginUpdate(appRoutingModulePath);
    for (const change of changes) {
      if (change instanceof InsertChange) {
        recorder.insertLeft(change.pos, change.toAdd);
      }
    }
    tree.commitUpdate(recorder);

    return tree;
  };
}

// Main factory function
export function feature(_options: Schema): Rule {
  return (_tree: Tree, _context: SchematicContext) => {

    const templateSource = apply(url('./files'), [
      template({
        ..._options,
        ...strings, // Provides classify, dasherize, etc. to templates
      }),
      move(_options.path),
    ]);

    // Chain the two rules together
    return chain([
      mergeWith(templateSource),
      addRouteToNgModule(_options)
    ]);
  };
}

Explanation of the logic:

Function / ConceptPurpose / Explanation
functionMain schematic factory where the rule chain is defined.
url(‘./files’)Reads template files from the ./files directory. These are the files to scaffold.
template({…})Replaces placeholders like <%= %> in the templates using user inputs and utility functions (classify, dasherize).
move(…)Moves generated files to the path specified by the user (typically project structure).
chain([…])Executes multiple Rules in order. Used here to generate files and then modify routing module.
Rule (custom)A custom rule to edit an existing file (app-routing.module.ts).
Reads app-routing.module.tsAccesses the routing module to inject new route information.
Uses TypeScript ASTUses the Abstract Syntax Tree to safely parse and modify code (more accurate than regex).
addRouteDeclarationToNgModuleUtility from @schematics/angular to help inject new routes into the NgModule.
InsertChangeA type of change object that represents text insertion. It’s applied to the file via the Tree.

Step 6: Build and Test the Schematic

1. Build the Schematic

npm run build

2. Link for Local Testing:

From inside your custom-schematics directory:

npm link

Then, in your test Angular project:

cd ../path/to/your/angular-app
# Link the global schematic to this project
npm link custom-schematics

3. Run the Schematic :

    Now you can run your custom schematic just like any other

    ng generate custom-schematics:feature orders

    Or, if you set it as the default collection in angular.json :

    ng generate feature profile --path=app/user

    After running, you will see a new orders folder inside app/features, fully populated with your component, service, and modules. More importantly, your app-routing.module.ts will have been automatically updated with the new lazy-loaded route, saving you time and preventing errors.

    Final Words

    With your custom Angular schematic ready, generating feature modules is quick and error-free. It includes routing, services, and components, streamlines development, enforces consistency, and saves time. This approach is especially useful for teams or businesses looking to hire Angular developers and maintain scalable, well-structured projects.

    The post How do you Create a Custom Angular Schematic to Automate Boilerplate and Enforce Conventions? appeared first on CMARIX QandA.

    ]]>
    https://www.cmarix.com/qanda/create-custom-angular-schematics-to-automate-boilerplate/feed/ 0
    How can you Use an InjectionToken to Provide type-safe, tree-shakable Configuration Objects? https://www.cmarix.com/qanda/angular-injectiontoken-type-safe-configuration-objects/ https://www.cmarix.com/qanda/angular-injectiontoken-type-safe-configuration-objects/#respond Thu, 25 Sep 2025 12:54:31 +0000 https://www.cmarix.com/qanda/?p=2347 InjectionToken is Angular’s way of creating a unique, type-safe key for non-class dependencies. It ensures that Angular knows exactly what you’re injecting, even if it’s a plain object or a configuration interface. This helps you overcome the fragility of strings which improves clarity across your codebase. The Problem with String-Based Providers If you’re using strings […]

    The post How can you Use an InjectionToken to Provide type-safe, tree-shakable Configuration Objects? appeared first on CMARIX QandA.

    ]]>
    InjectionToken is Angular’s way of creating a unique, type-safe key for non-class dependencies. It ensures that Angular knows exactly what you’re injecting, even if it’s a plain object or a configuration interface. This helps you overcome the fragility of strings which improves clarity across your codebase.

    The Problem with String-Based Providers

    If you’re using strings as keys to inject configurations, you’re setting yourself up for maintenance nightmares. One typo, and things silently break. That approach also makes it harder for TypeScript to validate anything at compile time.

    Meet InjectionToken: A Smarter Way to Inject Config

    InjectionToken is Angular’s way of creating a unique, type-safe key for non-class dependencies. It ensures that Angular knows exactly what you’re injecting, even if it’s a plain object or a configuration interface. This helps you overcome the fragility of strings which improves clarity across your codebase.

    How It Works in Practice

    Let’s say you want to inject an API configuration across multiple services. Instead of manually passing objects or importing shared constants, you define a typed token at one place, and Angular handles the rest via its DI system. Once set up, any service can inject this configuration using that token, without worrying about types or typos.

     Practical Example (Type-safe API configuration):

    Step 1: Create the Token

    // api-config.token.ts
    import { InjectionToken } from '@angular/core';
     
    export interface ApiConfig {
      baseUrl: string;
      apiKey: string;
    }
     
    export const API_CONFIG = new InjectionToken<ApiConfig>('api.config', {
      providedIn: 'root',
      factory: () => ({
    	// Default or environment-based configuration
    	baseUrl: 'https://api.default.com',
    	apiKey: 'default_key'
      })
    });

    Step 2: Inject Config into a Service

    Now, a service can inject this configuration in a type-safe way:

    // data.service.ts
    import { Injectable, inject } from '@angular/core';
    import { HttpClient } from '@angular/common/http';
    import { API_CONFIG, ApiConfig } from './api-config.token';
     
    @Injectable({ providedIn: 'root' })
    export class DataService {
      private http = inject(HttpClient);
      private config = inject(API_CONFIG);
     
      getData() {
    	return this.http.get(`${this.config.baseUrl}/items`, {
      	headers: { 'X-API-KEY': this.config.apiKey }
    	});
      }
    }

    This approach is superior to string providers because it’s not prone to typos and is fully supported by TypeScript’s type checking.

    Why This Approach Is Better

    • Type-safe: Interfaces enforce structure and reduce runtime surprises.
    • Tree-shakable: Unused config tokens won’t end up in your final bundle.
    • Refactor-friendly: No hard-coded strings or keys to update manually.
    • Globally injectable: Your config is available app-wide without tight coupling.

    Final Thoughts

    If you’re building scalable Angular apps, stop passing around config like it’s 2016. InjectionToken gives you a smarter, safer way to inject non-class dependencies. It’s lean, reliable, and just makes sense, especially for config. And if you’re short on time or want to avoid wiring everything yourself, consider hiring Angular developers who already know how to use InjectionToken and other best practices to build apps that scale cleanly. Let your config work for you and not against you.

    The post How can you Use an InjectionToken to Provide type-safe, tree-shakable Configuration Objects? appeared first on CMARIX QandA.

    ]]>
    https://www.cmarix.com/qanda/angular-injectiontoken-type-safe-configuration-objects/feed/ 0
    What is the role of ViewContainerRef and TemplateRef in creating Advanced Custom Structural Directives? https://www.cmarix.com/qanda/role-of-viewcontainerref-templateref-in-angular-directives/ https://www.cmarix.com/qanda/role-of-viewcontainerref-templateref-in-angular-directives/#respond Thu, 25 Sep 2025 12:29:59 +0000 https://www.cmarix.com/qanda/?p=2341 Structural directives in Angular like *ngIf and *ngFor aren’t just handy—they’re powerful tools for dynamic DOM manipulation. But what if you need custom logic that controls what shows up in the UI? That’s where ViewContainerRef and TemplateRef come in. Together, they let you build advanced structural directives that render content conditionally based on complex logic […]

    The post What is the role of ViewContainerRef and TemplateRef in creating Advanced Custom Structural Directives? appeared first on CMARIX QandA.

    ]]>
    Structural directives in Angular like *ngIf and *ngFor aren’t just handy—they’re powerful tools for dynamic DOM manipulation. But what if you need custom logic that controls what shows up in the UI? That’s 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.

    What Do ViewContainerRef and TemplateRef Actually Do?

    • TemplateRef is like a blueprint for the DOM. It represents the content inside an ng-template and allows you to reuse that content wherever needed.
    • ViewContainerRef is the placeholder where you inject or remove views. It controls when and how the template gets added to the DOM.

    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.

    Real Example: A Custom *appHasPermission Directive

    This directive only renders its content if a user has a specific permission.
    import { Directive, Input, TemplateRef, ViewContainerRef, OnDestroy } from '@angular/core';
    import { AuthService } from './auth.service';
    import { Subscription } from 'rxjs';
     
    @Directive({
      selector: '[appHasPermission]'
    })
    export class HasPermissionDirective implements OnDestroy {
      private subscription: Subscription;
      private hasView = false;
     
      constructor(
        private templateRef: TemplateRef<unknown>,
    	private viewContainer: ViewContainerRef,
    	private authService: AuthService
      ) {}
     
      @Input() set appHasPermission(permission: string) {
    	this.subscription = this.authService.hasPermission(permission).subscribe(canView => {
      	if (canView && !this.hasView) {
        	this.viewContainer.createEmbeddedView(this.templateRef);
        	this.hasView = true;
      	} else if (!canView && this.hasView) {
        	this.viewContainer.clear();
        	this.hasView = false;
      	}
    	});
      }
     
      ngOnDestroy() {
    	this.subscription?.unsubscribe();
      }
    }
     
    Usage in a template: <div *appHasPermission="'edit-article'">...</div>

    Final Thoughts

    When used right, structural directives can make your app leaner, faster, and easier to manage. ViewContainerRef and TemplateRef aren’t just for framework authors, they’re powerful tools every serious Angular dev should understand. If you’re aiming to build advanced features without reinventing the wheel, it’s a smart move to hire Angular developers who already know how to apply these patterns efficiently.

    The post What is the role of ViewContainerRef and TemplateRef in creating Advanced Custom Structural Directives? appeared first on CMARIX QandA.

    ]]>
    https://www.cmarix.com/qanda/role-of-viewcontainerref-templateref-in-angular-directives/feed/ 0
    How do Angular Signals differ from RxJS, and What is an advanced use case for them? https://www.cmarix.com/qanda/angular-signals-vs-rxjs-use-cases/ https://www.cmarix.com/qanda/angular-signals-vs-rxjs-use-cases/#respond Wed, 24 Sep 2025 13:50:12 +0000 https://www.cmarix.com/qanda/?p=2335 Signals and RxJS are both for handling reactivity, but they serve different primary purposes.  RxJS: Best for handling asynchronous events and complex event streams (e.g., HTTP requests, WebSockets, complex user input sequences). RxJS comes with a great set of operators to orchestrate these streams. Signals: Optimized for synchronous state management. They provide a simple, efficient […]

    The post How do Angular Signals differ from RxJS, and What is an advanced use case for them? appeared first on CMARIX QandA.

    ]]>
    Signals and RxJS are both for handling reactivity, but they serve different primary purposes.

     RxJS: Best for handling asynchronous events and complex event streams (e.g., HTTP requests, WebSockets, complex user input sequences). RxJS comes with a great set of operators to orchestrate these streams.

    Signals: Optimized for synchronous state management. They provide a simple, efficient way to represent state that can change over time and automatically notify dependents when it does, enabling fine-grained, zoneless change detection.

    Advanced Use Case (Combining Signals and RxJS):

    A common pattern is to use RxJS to handle the “event” and then feed the result into a signal to manage the “state.” This combines the benefits of RxJS for async operations and the performance of Signals for UI updates.

    import { Component, signal, inject } from '@angular/core';
    import { toSignal } from '@angular/core/rxjs-interop';
    import { DataService } from './data.service';
    import { catchError, of } from 'rxjs';
     
    @Component({
      selector: 'app-user-profile',
      template: `
    	<div *ngIf="user()">Welcome, {{ user().name }}</div>
    	<div *ngIf="error()">{{ error() }}</div>
      `
    })
    export class UserProfileComponent {
      private dataService = inject(DataService);
      private user$ = this.dataService.getUser().pipe(
    	catchError(err => of({ error: 'Failed to load user' }))
      );
     
      // Convert the Observable stream to a Signal
      private userData = toSignal(this.user$);
     
      // Use computed signals to derive state
      user = computed(() => this.userData()?.name ? this.userData() : null);
      error = computed(() => this.userData()?.error);
    }

    Final Words

    Signals are great for managing app state, while RxJS handles async data like API calls. When you combine both, you get smooth UI updates with powerful data control. To do this right, it helps to hire Angular developers who know when and how to use each one.

    The post How do Angular Signals differ from RxJS, and What is an advanced use case for them? appeared first on CMARIX QandA.

    ]]>
    https://www.cmarix.com/qanda/angular-signals-vs-rxjs-use-cases/feed/ 0
    What is NgZone, and When would you use runOutsideAngular for Performance Optimization https://www.cmarix.com/qanda/ngzone-angular-runoutsideangular/ https://www.cmarix.com/qanda/ngzone-angular-runoutsideangular/#respond Wed, 24 Sep 2025 13:39:15 +0000 https://www.cmarix.com/qanda/?p=2330 NgZone is Angular’s wrapper around Zone.js, a library that patches asynchronous browser APIs (like setTimeout, addEventListener) to automatically trigger change detection when they complete. However, for frequent, high-frequency events that don’t require immediate UI updates (e.g., mouse move tracking, real-time data streams from a WebSocket), running them inside the zone can cause excessive, unnecessary change […]

    The post What is NgZone, and When would you use runOutsideAngular for Performance Optimization appeared first on CMARIX QandA.

    ]]>
    NgZone is Angular’s wrapper around Zone.js, a library that patches asynchronous browser APIs (like setTimeout, addEventListener) to automatically trigger change detection when they complete.

    However, for frequent, high-frequency events that don’t require immediate UI updates (e.g., mouse move tracking, real-time data streams from a WebSocket), running them inside the zone can cause excessive, unnecessary change detection cycles.

    By using ngZone.runOutsideAngular(), you can execute code that won’t trigger change detection, significantly improving performance.

    Practical Example (Stock Ticker):

    import { Component, NgZone, OnInit } from '@angular/core';
     
    @Component({
      selector: 'app-stock-ticker',
      template: `Price: {{ price }}`
    })
    export class StockTickerComponent implements OnInit {
      price: number;
     
      constructor(private ngZone: NgZone) {}
     
      ngOnInit() {
    	this.ngZone.runOutsideAngular(() => {
      	// Connect to a high-frequency data stream
      	const stockPriceSocket = new WebSocket('wss://stock-prices.com');
     
      	stockPriceSocket.onmessage = (event) => {
        	// We are outside Angular's zone, so this doesn't trigger change detection
        	this.updatePrice(JSON.parse(event.data).price);
      	};
    	});
      }
     
      // Use a throttled function to update the view periodically
      updatePrice = throttle((price) => {
    	// Run back inside the zone to update the view
    	this.ngZone.run(() => {
      	this.price = price;
    	});
      }, 250);
    }

    Final Words

    NgZone lets Angular track async operations and trigger change detection. But for high-frequency tasks that don’t impact the UI immediately, like live data streams, you can skip change detection using runOutsideAngular() to boost performance. This is especially useful in real-time apps. To use it well, it’s smart to hire Angular developers with deep performance tuning experience.

    The post What is NgZone, and When would you use runOutsideAngular for Performance Optimization appeared first on CMARIX QandA.

    ]]>
    https://www.cmarix.com/qanda/ngzone-angular-runoutsideangular/feed/ 0