Getting Angular Up and Running (CODE LABS)

Getting Angular Up and Running (CODE LABS)

with Standalone components

In a nutshell

Communities

Social Developer

Recognitions

Principal Product Manager @Microsoft

GDE,MCT and MVP from SL

Top stackoverflow contributor

Top mentor @ adplist

 

I'm Sajeetharan Sinnathurai

@sajeetharan
@kokkisajee
@sajeetharan
@sajeetharan

DISCLAIMER

"Given the current AI trends, many sessions focus on AI, but this one is purely about Angular. Any expectation of AI content is your own.

 

 

The characters in this session are fictional, and while AI adoption is at 20%, there's still a long way to go. 80% of apps are still legacy, so let’s dive back into the fundamentals."

 

 

This is a hands-on session, so please make sure your laptops are open and connected to Wi-Fi.

Learning For the Day!

(DevFest  Podujana Peramuna)

Angular Module

Chamod Rajapaksha

Suresh Rajapaksha

Standalone component

Kubernetes

Podujana

Peramuna

Google Cloud

Podujana

Peramuna

Then

Now

29 Years of Javascript

AngularJS

2-way databinding

2009

React

Component based view library

2013

React Native

Native Mobile Apps using React

2014

Vue

Angular (v2)

2016

Future ready

$scope

ng-if

ng-app

ng-model

mobile

oriented

better

performance

x11

Angular 1.x vs Angular

2017

2020

Angular (v4)

Angular (v10)

Angular (v19)

2024

"HEROES DON'T ALWAYS WEAR CAPES

SOMETIMES THEY CODE ANGULAR"

  • A framework for web front-end app 

  • A platform for integrated development

  • An ecosystem for developers

World

1-1

x

1

  CLI. What is it?

ngular

Scaffold

Preview

Local build

Local Testing

Unit tests

E2E tests

  building blocks

ngular

Mathews Casually Pulls, Dhananjaya Misses, Shanaka Drops!

Module

Component

Pipes

Directives

Metadata

Services

Dependency Injection

Component

import { Component } from '@angular/core';

@Component({
  selector: 'world', // Name of the html tag
  providers: [], // Services
  styleUrls: [], // Url of the styles
  templateUrl: './world.component.html'
})
export class WorldComponent {

}

ngular

Basic building block of an UI in an Angular application

Module

Angular has at least one module, either root or functionality, it's a class with a decorator @ngModule

 

Highest level of abstraction

ngular

How are the components organized?

ngular

Module

Directive

Structure

Attribute

<li *ngFor="let enemy of enemies">
</li>
<enemy *ngIf="hasLife">
</enemy>

*ngFor

*ngIf

<div [ngClass]="['bold-text', 'green']"></div>
<div [ngClass]="'italic-text blue'"></div>
<div [ngClass]="{'small-text': true, 'red': true}"></div>

ngClass

ngStyle

You can create your own!

No more ng-show, ng-hide, ng-click but functionality is still available

...

...

ngular

ngular

Services

There is a single object of each service in the application (singleton)

 

That is, all the components share "the same" service

 

In this way the services maintain the status of the application

ngular

Services


You can make a service not shared among all the components of the application (not singleton)


You can create an exclusive service for a component and its children


Instead of declaring the service in @NgModule providers it is declared in the @Component


It can be shared by the parent component and by its children components (included in it)

import { Injectable } from '@angular/core';

@Injectable()
export class BlockService {

  getCoins() { 
    return 100; 
  }
}

ngular

Services

ngular

import { Pipe } from '@angular/core';
import { PipeTransform } from '@angular/core';
@Pipe({name: 'filterReviewByStatus'})
export class FilterReviewByStatusPipe implements PipeTransform {


}

Pipe 1

Data

Pipes

Pipe 2

Pipe 3

Pipe 4

Exclusive service for a component

import { Component } from '@angular/core';
import { BlockCoins } from './blockCoins.service';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    providers: 'BlockCoins'
})

export class AppComponent {
    constructor (private blockCoins: BlockCoins) {
    }

}

 ngular

Services

Exclusive service for a component

export class AppComponent {
    constructor (private blockCoins: BlockCoins) {
    }
}

 ngular

DI

Dependency Injection is a design pattern that passes an object as dependencies in different components across the application.​

 

It creates a new instance of class along with its required dependencies

Events

<button (click)="jump()"></button>

ngular

Data Binding

DOM

Component

{{ value }}

[property] = *value*

(event) = *handler*

[(event)] = *handler*

ngular

Comunication

ngular

Configuration of Properties (Father -> Son)

<world [name]="worldName"></world>
export class AppComponent {
    worldName = 'World 1-1';
}
import {Component, Input} from '@angular/core';

export class WorldComponent {
    @Input()
    private name: string;
}
<h1>{{name}}</h1>

app.component.ts

app.component.html

world.component.ts

world.component.html

Sending Events ( Son -> Father)

<world [name]="worldName" (changeName)='changeWorld($event)'></world>
export class AppComponent {
    worldName:string = 'World 1-1';

    changeWorld(name: string) {
        this.worldName = name;        
    }
}
import {Component, Input, Output, EventEmitter} from '@angular/core';

export class WorldComponent {
    @Input()
    private name: string;

    @Output()
    changeName = new EventEmitter<string>();

    click(level) {
        this.changeName.next(level);
    }
}
<h1>{{name}}</h1>
<button (click)='click("World 1-2")'>Next level</button>

app.component.ts

app.component.html

world.component.ts

world.component.html

Comunication

ngular

Router

ngular

<router-outlet></router-outlet>

<a [routerLink]="/world1"></a>

Set the Route

This is the container where the component or module indicated by the router will be loaded

World

2-1

x

2

Architecture

ngular

Application Source

Our application is divided in two parts. -Application itself & Application bootstrap

Angular App

Our modules, routes, components & services live here.

Angular Boostrap

We bootstrap our app depending on what platform were developing for, and add any required polyfills & vendors.

Configuration

Typescript config, npm packages, scripts, webpack config, express server, and so on...

World

3-1

x

3

Ready?

Download

Install

Run!

https://nodejs.org/en/download/
npm install -g @angular/cli@latest
ng new devfest2024 --routing --style=scss
cd devfest2024
npm start

We are going to create these elements in Angular

Let's make something awesome!

Chamod Rajapaksha

Suresh

Rajapaksha

Safnaj Kumara

Kaveesha

Premadasa

Sri lanka

Sri Lnaka

Home

Logo

Home

Game

What's the target?

Welcome to DevFest 2024

The first step to address in this application is to identity patterns, what things are reused and what is not

Service

Character

Enemies

Sri Lanka

Why Standalone Components?

No More Dependency on NgModules

 

Simplified Application Structure

 

Faster Learning Curve

 

Enhanced lazy loading

 

Improved Migration

ngular (Do Not do This)

We will start by creating a new Module

AngularHero inside the folder app/modules/

ng g m AngularHero

Before Angular 17

ngular

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


@NgModule({
  declarations: [],
  imports: [
    CommonModule
  ]
})

export class AngularHeroModule {
}

app/modules/angular-Hero/angularHero.module.ts

 

ngular

Lets start the first component

srilanka.component.ts

ng g c srilanka

Component SriLanka

import { Component } from '@angular/core';

@Component({
  selector: 'app-srilanka',
  imports: [],
  templateUrl: './srilanka.component.html',
  styleUrl: './srilanka.component.scss'
})
export class SrilankaComponent {

}

ngular

Component Home

ngular

What we get:

  • Template HTML, the component view
  • SCSS/CSS a style file
  • SPEC.TS unit test for the component
  • TS the main Typescript file*
ng g c home

ngular

Let's add some style

Open index.html and add the following css link in the head section:

<link rel="stylesheet" 
href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.1/css/materialize.min.css">

Component Safnaj

ngular

Now it's your turn, create a Safnaj component. Safnaj is an enemy of the SriLanka Mario game

ng g c Safnaj

Add a Safnaj to the Srilanka module

ngular

<h1>Sri Lanka</h1>
<app-safnaj></app-safnaj>

Add the component to the module AngularHeroModule.module.ts in the declarations section

Hope things go smoothly...

ngular

Exercise 1

<div class="card-panel blue lighten-2">
    <div class="row">
      <app-safnaj [id]="item" (removeGoomba)="removeGoomba($event)" *ngFor="let item of enemies">
      </app-safnaj>
    </div>
  </div

Add  all the components to Sri lanka Component and create 3 enemies ( Safnaj Kumara)

import { Component } from '@angular/core';

@Component({
  selector: 'app-srilanka',
  imports: [],
  templateUrl: './srilanka.component.html',
  styleUrl: './srilanka.component.scss'
})

export class SrilankaComponent {
  enemies: Array<string> = ['0', '1', '2', '3'];
  constructor() {

   }

  ngOnInit() {
  }

  removeGoomba(id: any) {
    const i = this.enemies.indexOf(id);
    if (i !== -1) {
      this.enemies.splice(i, 1);
    }
 
  }
}

srilanka.component.html

srilanka.component.ts

Create the character component

Exercise  2

*Note that Chamod  and  Suresh are 2 equally playable characters, so you'll have to make your component flexible to define the character's name

ng g c character

Add Chamod and Suresh to SriLanka

Exercise 3

 <app-character name="chamod" (removeGoomba)="removeGoomba($event)" name="chamod" style="background-color:lightblue;display:block"></app-character>
    <app-character name="suresh" (removeGoomba)="removeGoomba($event)" name="suresh" style="background-color:lightgreen;display:block"></app-character>

Add all elements to the App Component

<nav>
  <div class="nav-wrapper">
    <a href="#" class="brand-logo">Angular - Standalone</a>
    <ul id="nav-mobile" class="right hide-on-med-and-down">
      <li><a [routerLink]="['/home']">Home</a></li>
      <li><a [routerLink]="['/srilanka']">Lets Play</a></li>
    </ul>
  </div>
</nav>
<div class="container">
  <router-outlet></router-outlet>
</div>

app.component.html

Exercise 4

Set Routing

Tell Angular which component to load when navigating

Open app.routes.ts

import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { SrilankaComponent } from './srilanka/srilanka.component';

export const routes: Routes =[
    { path: 'home', component: HomeComponent },
    { path: 'srilanka', component: SrilankaComponent }
  ];
  
 

Tell to load HomeComponent when navigating in the browser domain.com/home

Suresh and Chamodcan jumb. Create a button when clicking click on the console that Chamod or Suresh has jumped

Exercise 5

We are going to get some coins.Lets create a service that will supply Suresh and Chamod with some Votes when they are hit. Make it to show the total votes on each character.

Exercise 6

Exercise 7

Create the Vote Service

ng g s vote
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class VoteService {
   votes = 0;
  constructor() { }

  getVotes() {
    return this.votes;
  }

  setVoters(vote : number){
     this.votes = +1;
  }
}

We're going to crush those Safnaj Kumaras. Create a button that allows the safnaj to be crushed with a click and as a consequence, the safnaj dissapears from Sri lanka.

Exercise 7

button

Character component

<ul class="collection"> 
    <li   class="collection-item avatar">   
      <img *ngIf="name == 'suresh'" src="assets/mario.png" alt="" class="circle">
      <img *ngIf="name == 'chamod'" src="assets/luigi.png" alt="" class="circle">
      <span class="title">it is me! {{name}}, votes: {{votes}}</span>   
    </li>
  </ul>
  <input type="number" #goombaId/>
  <button class="btn waves-effect waves-light green accent-3" (click)="crushGoomba(goombaId.value)">Jump over</button>
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { CommonModule } from '@angular/common';
import { VoteService } from '../vote.service';

@Component({
  selector: 'app-character',
  imports: [CommonModule],
  templateUrl: './character.component.html',
  styleUrl: './character.component.scss'
})
export class CharacterComponent {

  votes = 0;
  @Input() name!: string;

  @Output()
  removeGoomba = new EventEmitter<string>();

  constructor(private  voteService: VoteService) { }

  ngOnInit() {
  }

  jumpForCoins() {
    this.votes = this.voteService.getVotes();
  }
  jump() {
    alert(this.name + ' has jumped');
  }

  crushGoomba(goombaId: any) {
    this.removeGoomba.next(goombaId);
    this.votes = +1;
  }

}

character.component.html

character.component.ts

Safnaj Component

<ul class="collection">
    <li class="collection-item avatar">
      <img src="assets/goomba.png" alt="" class="circle">
      <span class="title">it is me! Safnaj Kumara {{id}} </span>
    </li>
  </ul>
  <button class="btn waves-effect waves-light light-blue accent-2" (click)="crushGoomba()">Kill me </button>
import { Component, EventEmitter, Input, Output } from '@angular/core';

@Component({
  selector: 'app-safnaj',
  imports: [],
  templateUrl: './safnaj.component.html',
  styleUrl: './safnaj.component.scss'
})
export class SafnajComponent {
  @Input() id!: string;
  @Output()
  removeGoomba = new EventEmitter<string>();
  constructor() { }

  ngOnInit() {
  }

  crushGoomba() {
    this.removeGoomba.emit(this.id);
    console.log("Goomba id", this.id)
  }
}

safnaj.component.html

safnaj.component.ts

Let's make the character be the one who crushed the Safnaj. As a benefit, each Safnaj that you crush will recieve 1 more vote

Exercise 8

  crushSafnaj(goombaId: any) {
    this.removeSafnaj.next(goombaId);
    this.votes = +1;
  }

ngular

All are solved

Otherwise

https://github.com/sajeetharan/ng-standalone-devfest-2024

Q&A

Where to go from here?

- Build Applications

- Send your queries @kokkisajee

- If you want to hear more , attend my talk tomorrow

 

 

Get angular app up and running standalone

By Sajeetharan Sinnathurai

Get angular app up and running standalone

  • 106