-
src folder
Containes all the necessary TS, HTML and CSS/SCSS files for app modules and components.
-
Index file
All the content of the index file is added dynamically using xml tags for custom components using their selector attributes.
For ex:
<app-root></app-root>
This will inject code of a component with said selector value.
-
Exporting values for Template
For each component we have a tag, a template and list of css scripts. We can pass template variables by exporting a class with needed fields in the JS/TS file for the component.
-
Directives:
Directives let angular listen to HTML fields and store them in given variables for later use in the file.
For Ex. we want to read values from file and display in some other field. So first we add the ngModel directive to it and display it in desired tag:
<input type='text' [(ngModel)]='name'> <p>{{ name }}</p>
This wont actually do anything as we need to add a module for handling angular forms in the
app.module.ts
fileimport { FormsModule } from '@angular/forms';
Then we need to add it to the list of imported modules in the App NgModule part.
-
Adding Bootstrap to Angular Project
First install the bootstrap package from npm
npm i --save bootstrap@latest
Then we need to make the angular app aware about this styling module.
To do that we edit the angular.json config file:
{ "architect" : { "build" : { "styles":[ "node_modules/bootstrap/dist/css/bootstrap.min/css" ] } } }
-
On running the
ng serve
command our project is rebuild and JS bundle scripts are added to the index file that dynamically injects components in the web page. -
index.html
The actual HTML content that is single page being served by the angualr app
-
main.ts
This is the first file to be executed which maps together the single web page site to be displayed with necessary injections of further components.
In that file we import the module for our angular app
app.module.ts
and loads that module.platformBrowserDynamic().bootstrapModule(AppModule).catch(err => console.error(err));
When the main.ts file bootstraps the AppModule it searches for that NgModule and within it we provide information about the component that should be loaded.
@NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, AppRoutingModule, FormsModule ], providers: [], // This is where we tell the boostrap to find following component bootstrap: [AppComponent] })
Then it looks for the AppComponent where we have defined the @Component and exported template variables.
-
src/app
- app.component.html - The main content of the starting app
- app.component.ts - Describes the Typescript code for the component including the selector value which will mapped to the tag in the corresponding HTML tag in the index.html. The template for this component is the above document
We divide our entire web project into Components tath we add together in the app component
-
A root app component is loaded on satrtup (app-component) to which we will add other components.
-
All new components are to be stored in a subfolder of src/app directory with the name of the component for simplicity
For ex: server component:
-
To create a component create a file like
server.component.ts
-
A component is basically a class we need to export. so lets create a class
ServerComponent
-
But this class next requires a decorator
@Component()
to make it identified as a Component. -
This component decorator has to be imported first
import { Component } from @angular/core;
-
The component decorator next takes a JS object for specifying attributes.
-
selector - Maps the tag of string value to the component. Naming convention :
app-component-name
-
templateUrl - This is the external HTML file that acts as template for this component.
The template file has to be created in the same component subfolder as
server.component.html
Next we point his templateUrl to this file in TS syntax as
./serve.component.html
-
-
Before we start making use of this component we need to maake changes to
app.module.ts
. Components are building blocks for the web app but modules are used to bundle them together and export as packages.For smaller projects we use a single app module, but for larger ones we can split them into more modules.
Modules are basically bundles of fucntionalities and tells angular app of which features we can use.
Modulesare are also classes with a special decorator :
@NgModule
from@angular/core
library. Ex :@NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, AppRoutingModule, FormsModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
We can add multiple modules in the app module using the imports array
Now all that is left is to register the newly created component in the NgModule's declarations array after importing the TS file.
@NgModule({ declarations: [ AppComponent, ServerComponent ], ... })
-
Now to actually use this component we need to add its selctor tag in an HTML file. We cannot do that in the index file, as it already has the root component. So instead we can add the selector tag in the
app.component.html
file.<h1>Hello World!!!! This is the app component</h1> <app-server></app-server>
-
-
Now we can also create a component using the AngularCLI tools:
ng generate component servers OR ng g c servers
This will automatically create a new Component and required files for it and also will make necessary changes in the
app.module.ts
fileThe
servers.component.spec.ts
is a file generated and used for testing the components and can be removed.Now we can simple modify the templates and use the
app-server
selector in it and replicate it to give an idea of multiple server instances used in the servers used. -
Instead of creating template files for each component we can write inline HTML code using the
template
property of the Component.@Component({ selector: 'app-servers', template: ` <app-server></app-server> <app-server></app-server> <app-server></app-server> <app-server></app-server>`, styleUrls: ['./servers.component.css'] })
-
Also we can style to our component templates using mutliple styleshhets using inline code or external file by using the
styleUrls
or thestyles
array of theComponent
-
Selectors can be created as tag attributes rather than tags themselves using a very CSS like selector property.
For ex. in the selector tab we can use
@Component({ // tslint:disable-next-line:component-selector selector: '[app-servers]', })
And in the template file in place of tags we can use them as attributes
<div app-servers></div> <!-- instead of --> <app-servers></app-servers>
Other method method is to use them as class. For ex:
@Component({ // tslint:disable-next-line:component-selector selector: '.app-servers', })
And in the template file in place of tags we can use them as attributes
<div class=".app-servers"></div>
No other selector method such as by ID or 3rd party methods are allowed. Default is to use like Elements.
Data Binding is the communication of data between your business logic and the HTML templates.
Different types of communication :
- Output data - Use string interpolation : {{ }}, property-binding : [property] = "data"
- React to user events - Event binding : (event) = 'expression'
- Two-way binding : [(ngmodel)] = 'data'
We can pass data dynamically from the TS file of a component to the template and display it using the {{ }} syntax.
For ex :
Business logic
export class ServerComponent {
id = 123;
status = 'offline';
getServerStatus() {
return this.status;
}
}
Template
<h3>Server with ID {{ id }} is {{ getServerStatus() }}.</h3>
Instead of passing string values to diaplay on template we can pass data as attribute/property for template tag using [ ] notation
For ex:
Business logic
export class ServersComponent implements OnInit {
allowNewServer = false;
constructor() {
setTimeout(() => {
this.allowNewServer = true;
}, 2000);
}
}
HTML template
<button class="btn btn-primary" [disabled]="!allowNewServer" >Add Server</button>
We can call TS functions as reaction to user actions such as clicks on an element.
-
First we define the function we want to execute in the Component TS file
export class ServersComponent implements OnInit { serverCreationStatus = 'No servers created'; onCreateServer(){ this.serverCreationStatus = 'Server was created'; } }
We can also call this code inside the template, but its better in the component logic file.
-
Next we need to assign this function to handle the user generated events.
For that on the element we want to listen for events we use ( event_name ) to access the event and assign the function
<button [disabled]="!allowNewServer" class="btn btn-primary" (click)="onCreateServer()">Add Server</button> <p>{{ serverCreationStatus }}</p>
-
Another example
Take form input to generate dynamic output
<label>Server Name</label> <input type="text" class="form-control" (input)="onUpdateServerName($event)"><br>
The
onUpdateServerName
method is called upon whenever we make changes to the input field.All the information about this event can be passed onto the function using the implicit variable
event
Updating the backend TS code:
onUpdateServerName(event;: Event;) { this.serverName = (event.target as HTMLInputElement).value; }
For Two-Way-Binding (covered in the next lecture) to work, you need to enable the ngModel
directive. This is done by adding the FormsModule
to the imports [ ] array in the AppModule
.
You then also need to add the import from @angular/forms
in the app.module.ts
file:
import { FormsModule } from '@angular/forms';
The above example is not applicable as pure Two-wayBinding as it does not propagate changes from the angular backend tot the views.
To properly use two-way data binding we have to use NgModule
which binds data from and to the HTML pages and the TS code.
<input type="text" class="form-control" [(ngModel)]="serverName"><br>
<p>{{ serverName }}</p>
Whenever we make changes to either of the codes, the changes are reflected everywhere.
Directives are instructions in the DOM. For ex Components are actually directives with templates while there can also be directives without templates.
They can be configured to be select in similar fashion to css-selectors. Like class, attribute or element selector.
-
We can have conditional code executed in the HTML file depending upon our ngModule value. For Ex, we will use ngIf ( * - a structural directive, changes DOM) as an attribute selector:
<p *ngIf="serverCreated">Server was created, name is {{serverName}}</p>
The ngIf directive is conditional and it will print the corresponding element only if condition is true. This block of code inserted the HTML element using a ng-template. We can place hooks in the HTML doc using ng-templates and use them with ng-IF to create if else blocks. FOr ex:
<p *ngIf="serverCreated; else noServer" >Server was created, name is {{serverName}}</p> <ng-template #noServer> <p>No server was created</p></ng-template>
-
Whereas structural directives which start with a
*
and modify the document DOM, we have another type known as attribute directives which look like simple HTML code and dont need a*
to begin with.They dont add/remove elements but simply modify the elements they are placed in. For ex:
<h3 [ngStyle]="{ backgroundColor : getColor()}">Server with ID {{ id }} is {{ getServerStatus() }}.</h3>
The ngStyle uses property binding and expects a JS object with CSS attributes and their values. It dynamically assigns a style to the element
-
Another use of directives is to dynamically add classes to elements using
NgClass
attribute directive. It again likeNgStyle
uses property binding and expects a JS object with class name as key and attribute values as boolean, depending upon which the CSS class is applied<h3 [ngStyle]="{ backgroundColor : getColor()}" [ngClass]="{online : status === 'online'}">Server with ID {{ id }} is {{ getServerStatus() }}.</h3>
-
Another Structural directive is
ngFor
which is used for displaying lists of elements in the HTML page.<app-server *ngFor="let server of servers"></app-server>