Skip to content
Angular Basics Explained — Complete Beginner's Guide

Angular Basics Explained — Complete Beginner's Guide

DodaTech Updated Jun 6, 2026 12 min read

Angular basics teach you to build dynamic web apps with TypeScript. Learn components, data binding, directives, and pipes in this complete beginner’s guide — no prior Angular experience needed.

What You’ll Learn

  • Scaffold and run an Angular project using the CLI
  • Create and compose reusable components
  • Bind data between your JavaScript/TypeScript logic and HTML templates
  • Handle user events and build interactive UIs
  • Use built-in directives and pipes
  • Understand the component lifecycle

Why Angular Matters

Angular powers enterprise applications like Gmail, Upwork, and Microsoft Office. It gives you a complete platform — routing, forms, HTTP client, and dependency injection built in — so you don’t need to piece together separate libraries. DodaTech uses Angular to build secure, responsive UIs for Durga Antivirus Pro dashboard and Doda Browser settings panels, ensuring millions of users get fast, reliable interfaces.

Security note: Understanding Angular Basics helps build more secure applications — a core principle at DodaTech, where tools like Durga Antivirus Pro and Doda Browser rely on solid implementation practices.

    flowchart LR
    A["TypeScript & HTML Basics"] --> B["**Angular Basics**"]
    B --> C["Angular Forms & Routing"]
    style B fill:#f97316,stroke:#c2410c,color:#fff
  
Prerequisites: Basic HTML, CSS, and JavaScript knowledge. Familiarity with TypeScript helps but is not required — you’ll pick it up along the way.

What Is Angular?

Think of Angular as a toolbox for building web apps. Instead of writing raw HTML/JavaScript and manually managing every piece, Angular gives you organized drawers (components), labels (templates), and a delivery system (dependency injection) so your code stays clean and scalable.

Angular is a framework, not a library. That means it dictates how you structure your app — which sounds restrictive, but actually saves you from making bad architectural decisions.

Setting Up Your First Project

You need two things: Node.js installed on your machine, and the Angular CLI (command line interface).

# Install the Angular CLI globally
npm install -g @angular/cli

# Create a new Angular app with routing and standalone components
ng new my-app --standalone --routing

# Move into the project folder
cd my-app

# Start the development server
ng serve

Let’s break down what each command does:

  1. npm install -g @angular/cli — Downloads and installs the Angular CLI so you can run ng commands from anywhere on your computer.
  2. ng new my-app — Creates a new project folder called my-app with everything you need. The --standalone flag uses the modern approach (no NgModules). The --routing flag adds route configuration.
  3. ng serve — Starts a local server at http://localhost:4200. Any changes you make to files automatically reload the browser.

Project Structure Explained

When you open the project folder, here’s what you’ll see:

my-app/
├── src/
│   ├── app/
│   │   ├── app.component.ts      # Your root component (logic)
│   │   ├── app.component.html    # Your root component (template)
│   │   ├── app.component.css     # Your root component (styles)
│   │   └── app.routes.ts         # Route definitions
│   ├── index.html                # Main HTML page
│   └── main.ts                   # App entry point
├── angular.json                  # Angular configuration
├── package.json                  # Dependencies
└── tsconfig.json                 # TypeScript configuration

Think of src/app/ as your workshop. Every piece of your app lives here — components, services, and configuration files.

Components — The Building Blocks

Imagine you’re building a dashboard like Durga Antivirus Pro. The dashboard has a header, a sidebar, a main content area, and a footer. In Angular, each of these is a component — a self-contained unit with its own template, styles, and logic.

Components are like Lego bricks. Each brick has its own shape and color, and you snap them together to build something bigger.

// hero.component.ts
import { Component, Input, Output, EventEmitter } from "@angular/core";

@Component({
  selector: "app-hero",            // Custom HTML tag: <app-hero>
  standalone: true,                // Modern Angular — no NgModule needed
  templateUrl: "./hero.component.html",
  styleUrls: ["./hero.component.css"]
})
export class HeroComponent {
  @Input() name: string = "";      // Data received from parent
  @Output() vote = new EventEmitter<string>();  // Event sent to parent

  upvote() {
    this.vote.emit(this.name);
  }
}

Let’s walk through each piece:

  • @Component({...}) — This is a decorator. It tells Angular: “this class is a component.” The object inside configures the component.
  • selector: "app-hero" — This is the custom HTML tag you’ll use in templates. You’ll write <app-hero></app-hero> wherever you want this component to appear.
  • standalone: true — Modern Angular components don’t need NgModules. They declare their dependencies directly.
  • @Input() name — This marks name as an input property, meaning a parent component can pass data into it like <app-hero [name]="'Iron Man'">.
  • @Output() vote — This marks vote as an output event, meaning the component can send data back up to its parent.

The Component Template

<!-- hero.component.html -->
<div class="hero-card">
  <h3>{{ name }}</h3>
  <button (click)="upvote()">Vote</button>
</div>

The double curly braces {{ name }} are called interpolation. They tell Angular: “replace this with the value of the name property from the component class.” The (click)="upvote()" is event binding — it runs the upvote() method when the button is clicked.

Using a Component Inside Another Component

// app.component.ts
import { Component } from "@angular/core";
import { HeroComponent } from "./hero/hero.component";

@Component({
  selector: "app-root",
  standalone: true,
  imports: [HeroComponent],        // Import child component
  template: `
    <app-hero                     
      *ngFor="let hero of heroes"
      [name]="hero"              
      (vote)="onVote($event)"    
    />
  `
})
export class AppComponent {
  heroes = ["Iron Man", "Spider-Man", "Black Panther"];

  onVote(name: string) {
    console.log(`${name} received a vote!`);
  }
}

Here’s what’s happening:

  • imports: [HeroComponent] — Since HeroComponent is standalone, we import it here so Angular knows about it.
  • *ngFor="let hero of heroes" — This is a structural directive that repeats the <app-hero> element for each hero in the array.
  • [name]="hero"Property binding passes each hero name into the child component’s @Input().
  • (vote)="onVote($event)"Event binding listens for the vote output event and calls onVote().

Data Binding — Connecting Logic to Template

Data binding is the bridge between your TypeScript logic and your HTML template. Angular provides four types:

    flowchart LR
    A[Data Binding] --> B["Interpolation {{ }}"]
    A --> C["Property Binding [...]"]
    A --> D["Event Binding (...)"]
    A --> E["Two-Way [(ngModel)]"]
    B --> F["Component → Template (one-way)"]
    C --> F
    D --> G["Template → Component (one-way)"]
    E --> H["Both directions"]
  

Interpolation — Displaying Values

<h1>{{ title }}</h1>
<p>{{ 2 + 2 }}</p>
<p>{{ user.name | uppercase }}</p>

Angular evaluates whatever is inside {{ }} as an expression and converts it to a string. You can do math, call functions, or use pipes (the | symbol) to transform data.

Property Binding — Setting HTML Properties

<img [src]="imageUrl" />
<button [disabled]="isSaving">Save</button>
<div [class.active]="isActive">Active</div>
<div [style.color]="textColor">Colored text</div>

Property binding uses square brackets [ ]. It sets an HTML element’s property to the value of a component property. When isSaving is true, the button becomes disabled automatically.

Why not just use src="{{ imageUrl }}"? Property binding preserves the value type (boolean, number, object). Interpolation always converts to a string.

Event Binding — Responding to User Actions

<button (click)="handleClick($event)">Click</button>
<input (input)="search($event.target.value)" />
<form (ngSubmit)="onSubmit()">...</form>

Event binding uses parentheses ( ). The left side is the DOM event name, the right side is the handler method in your component. $event is a special variable that holds the event data.

Two-Way Binding — Keeping Data in Sync

<input [(ngModel)]="username" placeholder="Username" />
<p>Hello, {{ username }}!</p>

Two-way binding uses [( )] — sometimes called “banana in a box.” When the user types in the input, username updates automatically. When username changes in the component, the input updates too. Both directions stay in sync.

For [(ngModel)] to work, import FormsModule in your component:

import { FormsModule } from "@angular/forms";
// in component: imports: [FormsModule]

Directives — Extending HTML

Directives are like instructions you attach to HTML elements. Angular has two categories:

Structural Directives — Change DOM Structure

These add, remove, or rearrange elements in the DOM:

<!-- *ngIf: Show or hide -->
<p *ngIf="isLoggedIn">Welcome back!</p>
<p *ngIf="age >= 18; else minor">Adult</p>
<ng-template #minor><p>Too young</p></ng-template>

<!-- *ngFor: Loop through lists -->
<ul>
  <li *ngFor="let item of items; let i = index; trackBy: trackById">
    {{ i + 1 }}. {{ item.name }}
  </li>
</ul>

<!-- *ngSwitch: Choose one of many -->
<div [ngSwitch]="role">
  <p *ngSwitchCase="'admin'">Admin Panel</p>
  <p *ngSwitchCase="'user'">User Profile</p>
  <p *ngSwitchDefault>Guest View</p>
</div>

The * prefix tells Angular to treat this as a structural directive. *ngIf removes the element from the DOM when the condition is false (it doesn’t just hide it with CSS).

Modern Control Flow (Angular 17+)

Angular 17 introduced a new, more readable syntax:

@if (isLoggedIn) {
  <p>Welcome back!</p>
} @else {
  <p>Please log in</p>
}

@for (item of items; track item.id) {
  <li>{{ item.name }}</li>
} @empty {
  <li>No items found</li>
}

@switch (role) {
  @case ('admin') { <p>Admin</p> }
  @case ('user') { <p>User</p> }
  @default { <p>Guest</p> }
}

This syntax is preferred for new projects — it’s more intuitive and has better type-checking.

Attribute Directives — Change Appearance or Behavior

<div [ngClass]="{ active: isActive, error: hasError }">Content</div>
<div [ngStyle]="{ color: textColor, fontSize: fontSize + 'px' }">Styled</div>

ngClass adds or removes CSS classes based on conditions. ngStyle sets inline styles dynamically.

Pipes — Transforming Data in Templates

Pipes take data as input and transform it for display. They don’t change the underlying data — just how it appears:

<p>{{ birthday | date:'longDate' }}</p>       <!-- June 6, 2026 -->
<p>{{ price | currency:'USD':'symbol':'1.2-2' }}</p>  <!-- $19.99 -->
<p>{{ message | uppercase }}</p>              <!-- HELLO -->
<p>{{ text | slice:0:100 }}...</p>             <!-- First 100 chars -->
<p>{{ obj | json }}</p>                        <!-- { "key": "value" } -->
<p>{{ 0.95 | percent }}</p>                    <!-- 95% -->

<!-- Chaining pipes -->
<p>{{ birthday | date | uppercase }}</p>

Think of pipes like filters — raw data goes in, formatted data comes out. You can chain multiple pipes with |.

Component Lifecycle Hooks

Angular components go through a predictable lifecycle. You can tap into specific moments using hooks:

    flowchart LR
    A[constructor] --> B[ngOnChanges]
    B --> C[ngOnInit]
    C --> D[ngDoCheck]
    D --> E[ngAfterContentInit]
    E --> F[ngAfterContentChecked]
    F --> G[ngAfterViewInit]
    G --> H[ngAfterViewChecked]
    H --> D
    H --> I[ngOnDestroy]
  
import { Component, OnInit, OnDestroy, OnChanges, Input, SimpleChanges } from "@angular/core";

@Component({
  selector: "app-lifecycle",
  standalone: true,
  template: `<p>{{ data }}</p>`
})
export class LifecycleDemo implements OnInit, OnDestroy, OnChanges {
  @Input() data: string = "";

  constructor() { console.log("1. constructor — class is created"); }

  ngOnChanges(changes: SimpleChanges) {
    console.log("2. ngOnChanges — input properties changed", changes);
  }

  ngOnInit() {
    console.log("3. ngOnInit — component ready, fetch data here");
  }

  ngOnDestroy() {
    console.log("9. ngOnDestroy — cleanup subscriptions here");
  }
}

The two most important hooks are:

  • ngOnInit — Runs once after the component is set up. This is where you fetch data from an API.
  • ngOnDestroy — Runs when the component is removed. Clean up subscriptions and timers here to prevent memory leaks.

You might be wondering: “Why not put API calls in the constructor?” The constructor runs before inputs are set. ngOnInit guarantees all @Input() properties are available.

Common Mistakes

1. Forgetting to import required modules

[(ngModel)] needs FormsModule. *ngFor needs CommonModule (though it’s available by default in standalone components). Always check your imports when something doesn’t work.

2. Property binding without brackets

src="url" sets the literal string “url”. [src]="url" binds to the component property url. The brackets make all the difference.

3. Mutating arrays instead of creating new references

Angular’s change detection may not pick up array.push() or array[i] = value. Instead, create a new array:

this.items = [...this.items, newItem];  // ✅ new reference

4. Forgetting the trackBy function in *ngFor

Without trackBy, Angular destroys and recreates every DOM element when the array changes. Provide a tracking function:

trackById(index: number, item: any) { return item.id; }

5. Doing heavy work in the constructor

The constructor runs during class instantiation, before inputs are set. Use ngOnInit for initialization logic like API calls.

6. Confusing *ngIf with [hidden]

*ngIf="false" removes the element from DOM entirely. [hidden]="true" just hides it with CSS. Use *ngIf for conditional rendering, [hidden] for simple show/hide.

Practice Questions

  1. What is the difference between interpolation {{ }} and property binding [ ]? Interpolation converts the value to a string and inserts it into the template. Property binding sets a DOM property directly, preserving the data type.

  2. When is ngOnInit called? After Angular has set the component’s input properties and the constructor has run. This is the safe point to fetch data or initialize state.

  3. What does standalone: true mean? The component manages its own dependencies via the imports array instead of requiring an NgModule. This is the modern Angular approach.

  4. What happens if you omit trackBy in *ngFor? Angular will re-render the entire list whenever the array reference changes, which hurts performance on large lists.

  5. How do you make a component receive data from its parent? Use the @Input() decorator on a class property. The parent passes data via property binding: <child [propName]="value">.

Challenge

Create a component called app-counter with an @Input() startValue (default 0), a button that increments, and a button that resets. Display the current count using interpolation. The parent should display “Counter started at X” above the counter.

FAQ

What is a standalone component?
Standalone components declare their own dependencies via imports instead of needing an NgModule. This is the standard approach since Angular 14.
What is the difference between interpolation and property binding?
Interpolation ({{ value }}) converts to a string. Property binding ([src]="value") binds to any property and preserves the value type.
What lifecycle hook should I use for API calls?
Use ngOnInit. The component is fully initialized, inputs are set, and it’s safe to fetch data and update state.
What is view encapsulation?
Angular emulates Shadow DOM to scope component styles to that component’s template. Styles don’t leak out or get affected by global styles by default.
How does the async pipe work?
{{ observable$ | async }} subscribes to an observable and returns the latest value. It automatically handles unsubscription when the component is destroyed.

Try It Yourself

Create a new Angular project and build a simple team member card component:

<!-- Run this in a new Angular project's app.component.html -->
<h1>My Team</h1>
<div style="display: flex; gap: 16px; flex-wrap: wrap;">
  <app-member-card
    *ngFor="let member of team"
    [name]="member.name"
    [role]="member.role"
    (selected)="onSelect($event)"
  />
</div>

<hr />
<p *ngIf="selectedMember">Selected: {{ selectedMember }}</p>
// app.component.ts
import { Component } from "@angular/core";
import { MemberCardComponent } from "./member-card/member-card.component";

@Component({
  selector: "app-root",
  standalone: true,
  imports: [MemberCardComponent],
  templateUrl: "./app.component.html"
})
export class AppComponent {
  team = [
    { name: "Alice", role: "Developer" },
    { name: "Bob", role: "Designer" },
    { name: "Charlie", role: "Manager" }
  ];
  selectedMember: string | null = null;

  onSelect(name: string) {
    this.selectedMember = name;
  }
}

What’s Next

TutorialDescription
https://tutorials.dodatech.com/frameworks/angular/angular-forms/Build forms with validation using template-driven and reactive approaches
https://tutorials.dodatech.com/frameworks/angular/angular-routing/Add navigation and multi-page views with the Angular Router
https://tutorials.dodatech.com/frameworks/angular/cli/Master all Angular CLI commands for scaffold, build, and test

Master related topics: TypeScript, JavaScript, HTML & CSS.

What’s Next

Congratulations on completing this Angular Basics tutorial! Here’s where to go from here:

  • Practice daily — Consistency is more important than long study sessions
  • Build a project — Apply what you learned by building something real
  • Explore related topics — Check out other tutorials in the same category
  • Join the community — Discuss with other learners and share your progress

Remember: every expert was once a beginner. Keep coding!

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro