Angular Basics Explained — Complete Beginner's Guide
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
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 serveLet’s break down what each command does:
npm install -g @angular/cli— Downloads and installs the Angular CLI so you can runngcommands from anywhere on your computer.ng new my-app— Creates a new project folder calledmy-appwith everything you need. The--standaloneflag uses the modern approach (no NgModules). The--routingflag adds route configuration.ng serve— Starts a local server athttp://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 configurationThink 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 marksnameas an input property, meaning a parent component can pass data into it like<app-hero [name]="'Iron Man'">.@Output() vote— This marksvoteas 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 thevoteoutput event and callsonVote().
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.
ngOnInitguarantees 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
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.When is
ngOnInitcalled? 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.What does
standalone: truemean? The component manages its own dependencies via theimportsarray instead of requiring an NgModule. This is the modern Angular approach.What happens if you omit
trackByin*ngFor? Angular will re-render the entire list whenever the array reference changes, which hurts performance on large lists.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
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
| Tutorial | Description |
|---|---|
| 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