At the end of the first mission planner studio, multiple components display data about the mission. Your job is to allow the user to update the mission plan by adding user interaction.
For this studio and the next, you will clone some starter code from GitHub.
Fork the Angular Mission Planner repository.
In the terminal, navigate out of the project folder you used for part 1 and
into your root angular_practice
directory.
Clone your fork to your computer.
Warning
Initializing a new Angular project inside of another one creates version control complications that are best avoided.
Before running the git clone
command in the terminal, make sure you
are NOT inside a current Angular project!
Use git status
to verify that you are on branch studio-2
. If not,
use git checkout
to switch to it.
Run npm install
to download dependencies.
Run ng serve
to build and serve the project.
The starter code for this studio is similar to the solution for the first mission planner studio, but with a few notable changes.
The mission name can now be edited by clicking on the text, changing the text
in the input box, and then updated by clicking save or pressing the enter key.
Review the code in src/app/header/header.component.html
and
src/app/header/header.component.ts
to see how this feature was implemented.
Open src/app/crew/crew.component.ts
in VSCode. Notice on line 10 that a
crew array is defined. This array of objects will be used to display the crew.
Each crew member has a name
and firstMission
property. If
firstMission
is true
, it means this is the first mission for that
person.
1import { Component, OnInit } from '@angular/core';
2
3@Component({
4 selector: 'app-crew',
5 templateUrl: './crew.component.html',
6 styleUrls: ['./crew.component.css']
7})
8export class CrewComponent implements OnInit {
9
10 crew: object[] = [
11 {name: "Eileen Collins", firstMission: false},
12 {name: "Mae Jemison", firstMission: false},
13 {name: "Ellen Ochoa", firstMission: true}
14 ];
15
16 constructor() { }
17
18 ngOnInit() {
19 }
20
21}
Note
All of these features only temporarily alter the data. If you refresh the page, the original data will reappear.
The rocket name should be clickable and editable like the mission name. Alter
src/app/header/header.component.html
and
src/app/header/header.component.ts
to allow the user to edit the rocket
name.
*ngFor
to Display Crew¶Replace the static list of <li>
tags in
src/app/crew/crew.component.html
with an *ngFor
that loops over the
crew
array.
Add this code to src/app/crew/crew.component.html
.
1<li *ngFor="let member of crew">{{member.name}}</li>
If a crew member's firstMission
property is true
, then display the text
"- 1st" next to their name.
Add this code right after the member name in
src/app/crew/crew.component.html
.
1<span *ngIf="member.firstMission">- 1st</span>
Allow crew members to be added to the list. To create a new crew member, two pieces of information are required:
We will use an input box and a checkbox to collect the data.
Add this code to the bottom of src/app/crew/crew.component.html
.
1<input #name type="text"/>
2<label>First mission<input #firstMission type="checkbox"/></label>
3<button (click)="add(name.value, firstMission.checked)">Add</button>
Line 1 creates an input that declares the local variable name
. Line 2
defines a checkbox that declares the firstMission
variable. Line 3 creates
a button that, when clicked, sends the new name
and checkbox
value to
the add
function. This function adds the new crew member to the roster!
In the src/app/crew/crew.component.ts
file, include this code for the
add
function:
1add(memberName: string, isFirst: boolean) {
2 this.crew.push({name: memberName, firstMission: isFirst});
3}
Allow removing of crew members by adding a button next to each person in the
crew list. When the remove button is clicked, the remove
function in the
crew component will be called, which deletes that person from the crew array.
Add line 4 to file src/app/crew/crew.component.html
. Be sure to put it
before the closing </li>
, so that the button appears next to each item in
the crew list.
1<li *ngFor="let member of crew">
2 {{member.name}}
3 <span *ngIf="member.firstMission">- 1st</span>
4 <button (click)="remove(member)">remove</button>
5</li>
Add the remove
function shown below to the crew component in the
src/app/crew/crew.component.ts
file.
1remove(member: object) {
2 let index = this.crew.indexOf(member);
3 this.crew.splice(index, 1);
4}
Finally we are going to allow the user to edit crew members who have already been added.
If the crew member name is clicked, then their name should be replaced with a text input and a save button.
When save is clicked, the input and save button are replaced by the text-only version of the name.
Only one crew member can be edited at a time.
We need to add a click event to the member name.
Put {{member.name}}
inside of a <span>
that has a (click)
handler.
Make the <li>
in src/app/crew/crew.component.html
look like the
code below.
1<li *ngFor="let member of crew">
2 <span (click)="edit(member)" class="editable-text">{{member.name}}</span>
3 <span *ngIf="member.firstMission">- 1st</span>
4 <button (click)="remove(member)">remove</button>
5</li>
We need a way of knowing which crew is being edited.
Add this property to the crew component in file
src/app/crew/crew.component.ts
. The property memberBeingEdited
represents the crew member who is currently being edited.
memberBeingEdited: object = null;
Next add a edit
function to the crew component file
src/app/crew/crew.component.ts
. This function will set a
memberBeingEdited
variable to be equal to the crew member who was
clicked.
edit(member: object) {
this.memberBeingEdited = member;
}
Now we need to add an *ngIf
that will show the two versions of the member,
the display state or the edit state.
In the edit state, an input box with a save button will appear, but for now
the input and save won't have any functionality. Make your
src/app/crew/crew.component.html
file look like the below code.
1<h3>Crew</h3>
2<ul>
3 <li *ngFor="let member of crew">
4
5 <span *ngIf="memberBeingEdited !== member; else elseBlock">
6 <!-- display state of member -->
7 <span (click)="edit(member)" class="editable-text">{{member.name}}</span>
8 <span *ngIf="member.firstMission">
9 - 1st
10 </span>
11 <button (click)="remove(member)">remove</button>
12 </span>
13
14 <ng-template #elseBlock>
15 <!-- edit state of member -->
16 <input />
17 <button>save</button>
18 </ng-template>
19
20 </li>
21</ul>
22<input #name type="text"/>
23<label>First mission<input #firstMission type="checkbox"/></label>
24<button (click)="add(name.value, firstMission.checked)">Add</button>
Finally, we are going to make the edit state update the member name when save is clicked.
Update the <input>
and <button>
tags to look like:
1<ng-template #elseBlock>
2 <!-- edit state of member -->
3 <input #updatedName (keyup.enter)="save(updatedName.value, member)" value="{{member.name}}"/>
4 <button (click)="save(updatedName.value, member)">save</button>
5</ng-template>
The last step is to add the save
function to the crew component. This
function will be called when the <button>
is clicked or when the enter key
is pressed and the <input>
has focus.
Add the below save
function to the crew component.
1save(name: string, member: object) {
2member['name'] = name;
3this.memberBeingEdited = null;
4}
Before starting on any of these bonus features, be sure to commit and push your work.
Complete code for this studio (without the bonus content) can be found in the
studio-2-solution
branch of the repository.