very simple hello world Angular 7.x tutorial. Where you create an angular app from scratch
very simple hello world Angular 7.x tutorial. Where you create an angular app from scratch
Updated 2021-10-11 for Angular 12.x (original post on 2016-06-01, then updated yearly)
We will create a simple angular application. It will be a simple "hello world"-style application so you can focus on the infrastructure and the absolute basics of the angular framework.
We will be using the result from the blog article on webpack. That result is also available from github
If you have not completed the webpack then go ahead and clone the solution of that tutorial:
$ git clone https://github.com/edc4it/webpack-intro-tutorial hellow
$ cd hellow
Next let's install the necessary libraries using npm.
$ npm install
This puts you right at the end of the aforementioned blog article.
Then remove all the contents** of the src
folder as we will be building a new application from scratch.
$ rm src/*
Let's first install the required angular libraries:
$ npm install @angular/core@^12 \
@angular/common@^12 \
@angular/compiler@^12 \
@angular/platform-browser@^12 \
@angular/platform-browser-dynamic@^12 \
@angular/router@ \
@angular/forms@^12 \
rxjs@6
Angular also requires a couple of shims in order to support older browsers, install those and we make sure and we create a separate chunk for them afterwards.
$ npm install zone.js@0.11.4
Create a new file named src/polyfills.ts
and add dependencies to our shims:
import 'zone.js';
Let's then add an webpack entry (polyfills
) for our webpack configuration (above the main
entry that is already there.):
entry: { // add as an object
polyfills: "./src/polyfills.ts", // add this
main: "./src/app.ts" //change this
},
Notice we also changed the name of the main entry to src/app.ts
.
Our HtmlWebpackPlugin
configuration from the previous post will include this on our page (as a
first entry)
With angular we use decorators (they provide component metadata). By default this is not enabled. We therefore need to adjust the tsconfig.json
together with some other configuration:
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"module": "es2020",
"importHelpers": true,
"target": "es2017",
"moduleResolution": "node",
"sourceMap": true,
"experimentalDecorators": true,
"lib": [
"es2018",
"dom"
]
}
}
While we are here let's add two more pieces of configuration (you can add this to the bottom of the webpack configuration)
devtool: "source-map",
devServer: {
historyApiFallback: true
}
The first option instructs webpack to generate source-maps, the second option is required when using the webpack-dev-server together with angular routing.
We will need to add some more configuration later, but we'll do that in context.
We need to place a component element to our html file so that angular can replace our component on the page (something like a placeholder). We will use a custom element (we could use any CSS3 selector to target the placement in the DOM).
Create a new file named src/index.html
with the following contents:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Angular Hellow</title>
</head>
<body>
<hellow-app>loading...</hellow-app>
</body>
</html>
The angular component we'll write later on is going to replace the contents of the hellow-app
element.
Notice we have placed some text inside it ("loading..."), this will be shown during application initialisation.
We don't need to include any javascript files for angular, polyfills or our application code, this is handled by webpack and in particular the HtmlWebpackPlugin. This means we are all done with this step!
Create a new file named src/app.ts
. In it declare an HelloComponent
class within:
class HelloComponent {
}
Next lets add the metadata using the @Component
decorator from "@angular/core" (don't forget the
import
if your IDE does not do it for you). Add a selector
(pointing to the hellow-app
element
in our index.html
, and the template text for this component:
import {Component} from "@angular/core";
@Component({
selector: "hellow-app",
template: "<h1>Hello Friend</h1>",
})
class HelloComponent {
}
Angular applications are structured using modules (not to be confused with webpack modules). A module consists of various related angular
resources (components, services etc). Angular modules can dependent on each other. In our case we need to "import" the built-in BrowserModule
. We will also need to register our component
and indicate it is used to bootstrap our application. We then finally need to register the module to be used as the bootstrap module
(using platformBrowserDynamic
)
You'll need at least one such module. Lets go ahead and declare an "application"-module inside the same app.ts
file"
import {Component, NgModule} from "@angular/core";
import {BrowserModule} from "@angular/platform-browser";
import {platformBrowserDynamic} from "@angular/platform-browser-dynamic";
…
// Your HelloComponent
…
@NgModule({
imports: [BrowserModule ], // import Angular's BrowserModule
bootstrap: [HelloComponent], // indicate the bootstrap component
declarations: [HelloComponent] // register our component with the module
})
export class AppModule {}
platformBrowserDynamic().bootstrapModule(AppModule); // bootstrap with our module
Start the webpack-dev-server:
$ npx webpack-dev-server --mode development
Open http://localhost:8080 and Bang! it shows "Hello friend"!
Great that we got it all working so fast in a single file, but we really should reorganise the files and resources better:
Eventually the structure needs to resemble:
src
├── app
│ ├── app.component.html
│ ├── app.component.scss
│ ├── app.component.ts
│ └── app.module.ts
├── index.html
├── app.ts
├── polyfills.ts
Create the src/app/app.component.ts
and cut/paste the component from app.ts
. Make sure you export as this needs to now
be accessed by another module:
import {Component} from "@angular/core";
@Component({
selector: "hellow-app",
template: "<h1>Hello Friend</h1>",
})
export class HelloComponent {
}
And let's move the AppModule
declaration to a file named src/app/app.module.ts
(again. don't forget the imports and export):
import {NgModule} from "@angular/core";
import {BrowserModule} from "@angular/platform-browser";
import {HelloComponent} from "./app.component";
@NgModule({
imports: [BrowserModule ], // import Angular's BrowserModule
bootstrap: [HelloComponent], // indicate the bootstrap component
declarations: [HelloComponent], // register our component with the module
})
export class AppModule {}
Fix the reference inside the app.ts
by using an import:
import {platformBrowserDynamic} from "@angular/platform-browser-dynamic";
import {AppModule} from "./app/app.module";
platformBrowserDynamic().bootstrapModule(AppModule); // bootstrap with our module
Your browser should again be showing "Hello Friend"
Let's now remove the html template from the component decorator and place it in its own file src/app/app.component.html
:
<h1>Hello Friend</h1>
Update the metadata and use node's require to obtain the html text:
@Component({
selector: "hellow-app",
template: require("./app.component.html"),
})
note: Without webpack you would have used the templateUrl
metadata property and point to the
html file using a string url: app/app.component.html
. But as we are using webpack we are really just
loading the html as a string using node's require
function.
But hold on: we are declaring a dependency to a "html-module". Recall from the previous article, that webpack only knows how to handle javascript modules. We therefore already added some module rules. We now need to add one for html modules
First install the loader:
$ npm install add html-loader@2 --save-dev
Then configure the rule:
{
test: /\.html$/,
loader: "html-loader",
options: {
esModule: false,
},
},
We need to specify esModule: false
so that the loader does not generate a ES module (it needs to be the raw html)
Add a scss file named src/app/app.component.scss
with the following contents
$color: #0086b3;
h1 {
font-size: 1.2em;
color: $color;
}
note: The $color
variable should ideally come from a global .scss
file which you would then
import using @import "../main";
. We are using it here just to use a specific non-css scss feature.
Update the metadata to include a styles
property and use again node's require
:
@Component({
selector: "hellow-app",
styles: [ require("./app.component.scss") ],
template: require("./app.component.html"),
})
But wait a minute, hold on again! How will webpack process this? We have an existing rule for scss. But in this case we don't want
to have the style on the page. We just want it to be made available to the styles
metadata property above. Change
the existing rule and only use the sass-loader followed by a raw-loader
(which we need to install):
{
test: /\.scss$/,
use: [
{
loader: "raw-loader",
options: {
esModule: false,
}
},
{
loader: "sass-loader",
options: {
sourceMap: true,
},
},
],
}
Don't forget to install the loader:
$ npm install add raw-loader@4 --save-dev
Restart your dev server and your browser should now be showing a styled "Hello World" ;)
In this step you will use interpolation using an expression which will be initialised to a static value. (Later we will use two-way binding).
Update our component's template (app/app.component.html
)
<h1>{{message}}</h1>
Notice your browser, you will notice the page no longer display any text. You are already seeing
angular in action. The reason you don't see any text is because the property message
value has no value (if
you wanted you could use '{{!message}}and the paye would display
true`).
Let's add a property and initialise it with a value inside our component:
export class HelloComponent {
message = "Hoo Ah!";
}
You should now see your message in the browser (and shout it out like Lt. Col. Frank Slade when you see it in your browser)
You will now bind the message
model using two-way data binding.
Add an input
element and use the ngModel
applying the two-way binding style: [(...)]
.
<h1>{{message}}</h1>
<input type="text" [(ngModel)]="message"/>
You will need to import the FormsModule
into your module:
…
import {FormsModule} from "@angular/forms";
@NgModule({
imports: [BrowserModule, FormsModule ],
…
})
export class AppModule {}
Try it out in the browser! You should notice the text input contains "Hoo Ah!", but now when you change the value, it instantly updates the header value.
This completes this introduction on Angular. The solution can be be found on github: github
The following courses may be of interest to you,
This article does not necessarily reflect the technical opinion of EDC4IT, but purely of the writer. If you want to discuss about this content, please send us an email at support@edc4it.com