Exercise: Angular part 4 (Movies with Components interactions)


Idea: Introduction to Angular (Input&output - component interaction).
Background: The Ultimate Angular-cli Reference and Angular.io

Relateret billede

In this exercise you have to make communications between child-components (siblings) in 10 steps.
The Application you have to create should list some movies and display details of a selected movie.




 

 

Step 1 - Download an initial project - MovieInputOutput
Download and extract the MovieInputOutput.zip folder in your VSCode/Angular folder.
Navigate to the new folder: MovieInputOutput and create the initial project by running: npm install
(Notice: just ignore err/warnings)

Verify, that it works by running: ng serve -o.

Your initial project looks like this:

Step 1.b - Inspect the code
Take a tour around the code:


The next step is to update the MovieList component. The component have to use an EventEmitter to sendt the selected movie from the MovieList component to the parrent-component (App component). The parrent component can then sendt the selected movie to the child-components (MoviePoster and MoviePlot).


Step 2 - MovieList Component (movie-list.components.ts)
Import Output and EventEmitter from angular/core:

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

Create a new property selectedMovie of the type Movie (use | undefined to allow that the property can be uninitialized)

selectedMovie : Movie | undefined;


Create a new property movieSelected, initialize the new property with a new EventEmitter<Movie>-object and annotate with @Output('movie-selected'):

@Output('movie-selected') public movieSelected = new EventEmitter<Movie>();

Add a function onSelect, so it makes a call of the emit-function with the selected movie as argument:

public onSelect(movie : Movie){

this.selectedMovie = movie;
this.movieSelected.emit(movie);

}

 

Step 2a - MovieList Component (movie-list.components.html)
Update ngFor the <li> tag in the html page with:

<li *ngFor="let movie of movies" [class.selected]="movie === selectedMovie"(click)="onSelect(movie)" >

Why? - What is the purpose?

 

Step 2b - AppComponent (app.component.ts)
Update the AppComponent with a new property selectedMovie of the type Movie (use | undefined to allow that the property can be uninitialized)

public selectedMovie : Movie | undefined;

and a call-back funktion movieSelected(movie:Movie) to update the selectedMovie:

public movieSelected(movie: Movie) { this.selectedMovie = movie; }


Don't forget to import Movie:

import { Movie } from './Shared/Movie';

 

Step 2c - AppComponent (app.component.html)
Update the <app-movie-list> tag:

<app-movie-list (movie-selected)="movieSelected($event)"> </app-movie-list>

Why? - What is the purpose?

Verify, that the app is still working!

Ups - it dosen't work! - notice the error and change the accessibility of the property selectedMovie to public.

 

In the next 3 step you have to create the component that displays the Poster.



MoviePoster Component

Step 3.1 - MoviePoster Component
Stop the Server (ctrl C) and create a new component MoviePoster (ng g c MoviePoster).


Step 3.2 - MoviePoster Component
(movie-poster.component.ts)
The component must have a property with the name movie of the type Movie (the interface Movie is defined in the file Movie.ts in the folder Shared, so remember to import Movie from: '../Shared/Movie').
Annotate the property with the @Input( ) annotation (notice: import Input from angular/core):

@Input( ) public movie : Movie | undefined;


Step 3.3 - MoviePoster Template (movie-poster.component.html)

Replace the default html-code with a <h3> with the text: "Poster:" and an image with the poster-image to the selected movie. The property Poster in class Movie contains a reference to the poster-image in the folder image in the assets folder (src/assets/Image).
Use the string interpolation to bind the src to the Poster.property.

<h3>Poster:</h3>
<div> <img class="poster" src={{movie.Poster}}> </div>


Step 3.4 - MoviePoster Style (movie-poster.component.css)

Set the class-attribute to "poster" and set the width to 10em and the height to 13em in the CSS-file.

.poster{ width: 10em; height: 13em; }


Step 3.5 - AppModule (app.module.ts)
Verify that MoviePosterComponent is Imported in the AppModule and that the MoviePosterComponent is added to the Modules Declarations.


Step 3.6 - AppComponent (app.component.html)
Test the app - run: ng serve -o

Verify that you will see the Poster when you select a movie.

Yes your right! You don't see any Poster!!
Did you add the <app-movie-poster> tag in app.component.html? No, ok then do it and add a property-binding so we can pass the selected movie to the MoviePoster component:

<app-movie-poster [movie]="selectedMovie"> </app-movie-poster>


Step 3.7 - MoviePoster Template (movie-poster.component.html)
Notice: when the application starts up there is no selected movies. The result is an empty border and a error (since movie is undefined in MoviePoster).

To prevent that - add a div-tag with: a *ngIf dicrective:


 


 


MoviePlot Component

Step 4.1 MoviePlot Component
Create a new component MoviePlot.


Step 4.2 - MoviePlot Component
(movie-plot.component.ts)
The component must also have a property with the name movie of the type Movie.
Annotate the property with the @Input( ) annotation (notice: import Input from angular/core)


Step 4.3 - MoviePlot Template (movie-plot.component.html)

Insert a header with "Movie Plot" and display information about the movie plot and actors


Step 4.4 - MoviePlot Style (movie-plot.component.css)
No special styling needed.


Step 4.5-4.7 - AppModule
Like in step 3.5 - 3.7 - make a propper update of the AppModule!


Step 5 - Test/Verify
Verify that you got something like this:

 





Congratulation! - Angular is rocking a little more and now your components can interact (but your Angular App is still very small).


/ Henrik H