DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Cover image for Amplication & Angular: Create the App
Michael Solati for Amplication

Posted on • Updated on • Originally published at docs.amplication.com

Amplication & Angular: Create the App

Welcome to this tutorial on how to build a full-stack application with Amplication.

What we will do is go step by step to create a Todos application using Angular for your frontend and Amplication for your backend.

If you get stuck, have any questions, or just want to say hi to other Amplication developers like yourself, then you should join our Discord!


Table of Contents

  • Step 1 - Creating a new directory
  • Step 2 - Starting with a blank canvas
  • Step 3 - Adding our components
  • Step 4 - Putting it together
  • Step 5 - Wrap Up

Step 1 - Creating a new directory

@angular/cli will create a new directory for our frontend application as well as handle the heavy lifting of configuring all of our build tools.

Create a new folder to contain the frontend, and eventually the backend, application and then open a new terminal and run the commands:

npm i -g @angular/cli
ng new web -g -S --routing false --style css
Enter fullscreen mode Exit fullscreen mode

The above command creates a new Angular application with the following configuration:

  • Without initiating git (-g skips initiating git)
  • Without creating testing files (-S skips initiating test files)
  • Without setting up routing (--routing false tells the CLI not to setup the routing module)
  • With using CSS as the styling language (--style css tells the CLI to use CSS)

In the newly created folder that contains web/ create a package.json file and copy into it the following:

{
  "scripts": {
    "start": "npm --prefix web start",
    "postinstall": "npm ci --prefix web"
  }
}
Enter fullscreen mode Exit fullscreen mode

Then create a .gitignore file and copy into it the following:

/node_modules
Enter fullscreen mode Exit fullscreen mode

Finally return to the terminal and run the command:

npm run start
Enter fullscreen mode Exit fullscreen mode

You'll be greeted by the following screen:

@angular/cli result

Step 2 - Starting with a blank canvas

While the introductory application is nice, we'll want to start with a blank canvas.

Open up the root directory in the IDE of your choice.

Open web/src/styles.css and replace the content of this file with the following:

web/src/styles.css

:root {
  --spacing: 4px;
  --font-size: 20px;
  --on-primary: #ffffff;
  --on-secondary: #ffffff;
  --primary: #f44336;
  --secondary: #2196f3;
  --text: #212121;
}

app-task {
  display: contents;
}

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
    "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
    "Helvetica Neue", sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

button {
  border: none;
  background-color: var(--secondary);
  color: var(--on-secondary);
  font-size: var(--font-size);
  height: 60px;
  margin: var(--spacing) 0;
  max-width: 450px;
  width: 100%;
}

button[type="submit"] {
  background-color: var(--primary);
  color: var(--on-primary);
  text-transform: uppercase;
}

button:hover {
  filter: brightness(80%);
}

button:active {
  filter: brightness(120%);
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
    monospace;
}

form {
  align-items: center;
  display: flex;
  flex-direction: column;
  margin: var(--spacing) 0;
  padding: calc(4 * var(--spacing));
}

input {
  background: transparent;
  border: 1px solid var(--text);
  border-radius: 3px;
  line-height: 30px;
  font-size: var(--font-size);
  margin: var(--spacing) 0;
  max-width: 416px;
  padding: calc(4 * var(--spacing));
  width: 100%;
}

input[type="checkbox"] {
  height: 48px;
  margin: var(--spacing);
  width: 48px;
}

li {
  display: flex;
  height: calc(48px + calc(2 * var(--spacing)));
  max-width: 450px;
  width: 100%;
}

li.completed {
  text-decoration: line-through;
}

span {
  flex: 1;
  font-size: var(--font-size);
  line-height: calc(48px + calc(2 * var(--spacing)));
}

ul {
  align-items: center;
  display: flex;
  flex-direction: column;
  list-style-type: none;
  padding: calc(4 * var(--spacing));
}
Enter fullscreen mode Exit fullscreen mode

Then open web/src/app/app.component.html and delete all the content in this file.

Step 3 - Adding our components

To build this todo list app, we'll need a few components.

Task

Our first component will be used to render an individual task. We'll bind it to an @Input() element and an @Output() event:

  • @Input() task - The task object itself. It has the following properties:
    • text - A string of the task itself.
    • completed - A boolean property that tracks if a task is completed.
    • id - A unique number to identify a task.
  • @Output() completed - This event emitter will trigger a user taps on the checkbox, emitting the completed task id, and eventually toggling the state of the task.

In your terminal navigate to the web directory and run:

ng g c task
Enter fullscreen mode Exit fullscreen mode

For the logic, replace the content of the TypeScript file with the following:

web/src/app/task/task.component.ts

import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-task',
  templateUrl: './task.component.html',
  styleUrls: ['./task.component.css']
})
export class TaskComponent {
  @Input() task: any = {};
  @Output() completed = new EventEmitter<any>();
}
Enter fullscreen mode Exit fullscreen mode

For the template, add the following code into the HTML file:

web/src/app/task/task.component.html

<li [class.completed]="task.completed">
  <span>{{task.text}}</span>
  <input type="checkbox" [checked]="task.completed" (click)="completed.emit(task?.id)" readOnly />
</li>
Enter fullscreen mode Exit fullscreen mode

Tasks

Our second component will be used to render a list of tasks. We'll bind it to an @Input() element and an @Output() event:

  • @Input() tasks - An array of tasks.
  • @Output() completed - This event emitter will trigger a user taps on the checkbox in the Task component, bubbling the event up to the AppComponent, and eventually will toggle the state of the task.

In your terminal navigate to the web directory and run:

ng g c tasks
Enter fullscreen mode Exit fullscreen mode

For the logic, replace the content of the TypeScript file with the following:

web/src/app/tasks/tasks.component.ts

import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-tasks',
  templateUrl: './tasks.component.html',
  styleUrls: ['./tasks.component.css']
})
export class TasksComponent {
  @Input() tasks: any[] = [];
  @Output() completed = new EventEmitter<any>();
}
Enter fullscreen mode Exit fullscreen mode

For the template, add the following code into the HTML file:

web/src/app/tasks/tasks.component.html

<ul>
  <app-task *ngFor="let task of tasks" [task]="task" (completed)="completed.emit($event)"></app-task>
</ul>
Enter fullscreen mode Exit fullscreen mode

CreateTask

The final component will be a form to allow users to create a new task. We'll bind it to an @Output() event:

  • @Output() addTask - This event emitter will trigger on submission of the form and emits the new task they want to create.

Since we are working with a form element, we will need to add the ReactiveFormsModule to the AppModule. In web/src/app/app.module.ts make the following changes:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
+ import { ReactiveFormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { TaskComponent } from './task/task.component';
import { TasksComponent } from './tasks/tasks.component';

@NgModule({
  declarations: [
    AppComponent,
    TaskComponent,
    TasksComponent
  ],
  imports: [
-    BrowserModule
+    BrowserModule,
+    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
Enter fullscreen mode Exit fullscreen mode

In your terminal navigate to the web directory and run:

ng g c create-task
Enter fullscreen mode Exit fullscreen mode

For the logic, replace the content of the TypeScript file with the following:

web/src/app/create-task/create-task.component.ts

import { Component, Output, EventEmitter } from '@angular/core';
import { FormBuilder } from '@angular/forms';

@Component({
  selector: 'app-create-task',
  templateUrl: './create-task.component.html',
  styleUrls: ['./create-task.component.css']
})
export class CreateTaskComponent {
  @Output() addTask = new EventEmitter<string>();

  createTaskForm = this.fb.group({
    task: ''
  });

  constructor(private fb: FormBuilder) { }

  onSubmit() {
    if (!this.createTaskForm.valid) return;
    this.addTask.emit(this.createTaskForm.value.task);
    this.createTaskForm.reset();
  }
}
Enter fullscreen mode Exit fullscreen mode

For the template, add the following code into the HTML file:

web/src/app/create-task/create-task.component.html

<form [formGroup]="createTaskForm" (ngSubmit)="onSubmit()">
  <input
    type="text"
    placeholder="TODO"
    formControlName="task"
    required
  />
  <button type="submit">Add</button>
</form>
Enter fullscreen mode Exit fullscreen mode

Step 4 - Putting it together

With our different components created, we'll next put them together and see how they work!

Open up web/src/app/app.component.ts and in the AppComponent class we will want to create our tasks array and remove title.

export class AppComponent {
-  title = 'web';
+  tasks: any[] = [];
Enter fullscreen mode Exit fullscreen mode

We'll also want ways to add and toggle the state of tasks.

export class AppComponent {
   tasks: any[] = [];

+  createTask(text: string) {
+    return {
+      id: this.tasks.length,
+      text,
+      completed: false,
+    };
+  }
+
+  addTask(task: string) {
+    const newTask = this.createTask(task);
+    this.tasks.push(newTask);
+  };
+
+  completed(id: number) {
+    const i = this.tasks.findIndex((t) => t.id === id);
+    this.tasks[i].completed = !this.tasks[i].completed;
+  };
}
Enter fullscreen mode Exit fullscreen mode

With all of our logic and components in place, we'll finally render our components! Copy the following HTML into web/src/app/app.component.html so we can see our tasks list and add tasks to that list.

<app-create-task (addTask)="addTask($event)"></app-create-task>
<app-tasks [tasks]="tasks" (completed)="completed($event)"></app-tasks>
Enter fullscreen mode Exit fullscreen mode

Step 5 - Wrap Up

Go ahead and try adding tasks or marking them as complete.

a working todo list app

The only problem is that these tasks aren't being saved anywhere, so when you refresh the page poof they're gone. In our next step, we will create our backend with Amplication to be able to save our tasks to a database!

Check back next week for step two, or visit the Amplication docs site for the full guide now!

To view the changes for this step, visit here.

Top comments (0)

🌚 Browsing with dark mode makes you a better developer by a factor of exactly 40.

It's a scientific fact.