1 of 83

Architecture of Web User Interfaces

SWEN-261

Introduction to Software Engineering

Department of Software Engineering

Rochester Institute of Technology

2 of 83

Chapters of this Lecture

  1. View Basics: essential aspects of build UI components in Angular
  2. Routing: apps contain multiple pages and how to navigate between them
  3. Services: introduction to simple, data providers
  4. Forms: build data-entry View components
  5. Services (reprised): that provide CRUD operations
  6. View Composition: decompose complex views into smaller, easier to maintain subviews
  7. Global Layout: add UI elements that are common across all pages
  8. Security: users, authentication, and authorization
  • Dev Tools: debug your View and Service components on the browser
  • Asynchronicity: the main types of Observer pattern tools

2

3 of 83

1) View Basics: essential aspects of build UI components in Angular

  1. What is Angular?
  2. The structure of an Angular View component.
  3. Binding data into the view.
  4. HTML elements are the basic building blocks of view structure.
  5. CSS rules are the basic building blocks of view styles.
  6. Parameterize data passed from View components to raw HTML elements.
  7. Event handlers are the basic building blocks of view interactions.
  8. Building small, reusable View components (aka widgets).
  9. Using control logic (conditionals and iteration) in Views.

3

4 of 83

What is Angular?

  • Angular is a Web GUI framework.
  • Your GUI runs as a single page within your browser.*
  • Lots of bells and whistles:
    • View templates (data binding, Observer pattern, view composition)
    • Routing (guards, data injection)
    • Supports data-entry forms
    • Dependency Injection (of Services into Views and other Services)
    • Supports asynchronous practices (Signals and RxJS, and others)

4

  • Resources:

5 of 83

A View component has structure, style and behavior

5

The MyPage View component gets rendered in a web browser.

The MyPage View component is composed of three elements: HTML, CSS and TypeScript.

6 of 83

You can use a browser’s Dev Tools to inspect the DOM structure of your View components.

To use Dev Tools: Right-click to pop-up context menu, then select Inspect item.

6

Use mouse to hover over DOM elements in the Elements tab tree display to find where that element is rendered.

Use the box-pointer icon and then select an element in the rendered view to “open up” the DOM element in the tree display,

7 of 83

Views can display more than simple strings and numbers; they can display complex objects (Entities) like this.

export class App implements OnInit {

// VM data for basic view binding

readonly swen261 = new Course({

code: 'SWEN-261',

title: 'Introduction to Software Engineering',

});�}

<h2>Display of Complex Objects</h2>

<div class="courseCard" [class]="swen261.curriculum">

<h3>{{swen261.code}}:&nbsp;</h3>

<p><em>{{swen261.title}}</em></p>

</div>

export class Course {

readonly code: string;

readonly title: string;

constructor(

json: CourseJSON,

) {

this.code = json.code;

this.title = json.title;

}

// extract the curriculum code from the course code

get curriculum(): string {

return this.code.substring(0, 4);

}

}

7

8 of 83

Data to populate views can be static, but also dynamic using the Observer pattern via Angular Signals.

8

<p>

Using an asynchronous signal: <br>

{{ message() }}

</p>

export class App implements OnInit {

readonly message = signal('Initializing...');

ngOnInit() {

setTimeout(() => this.message.set(

'Delayed message. Was it worth the wait?'

),

2000 // after two seconds

);

}

}

Source: Angular Signals (Medium article)

after a two second delay

9 of 83

HTML provides hundreds of content elements.

  • Layout: main, article, section, h1-h6, div (generic) and so on
  • Text: p (paragraph), ul (unordered list), ol (ordered list), li (list item)
  • Media: img (image), video, audio, and canvas (dynamic graphics)
  • Interaction: a (links), button, nav (navigation group) and so on
  • Forms: form, input (many types), select/option, and textarea
  • Tables: table, tr (row), th (column heading), td (cell), and so on
  • Inline: em (italics), strong (bold), code, span (generic), and so on
  • And many more…

References:

  • HTML Reference (W3C Schools)
  • HTML Cheat Sheet (freeCodeCamp)

9

10 of 83

CSS provides very flexible rules to style the view structure.

  • Properties: fonts, colors, box (div) dimensions, layout structures, and many many more
  • Rules: define a set of properties associated with DOM elements that match the rule selector
  • Selectors: pattern to match DOM elements based upon: (a) element type, (b) id, (c) element class, (d) element attributes, and so on

References:

10

11 of 83

Let’s look at an example of CSS styling for the LMS system.

div.courseCard {

border: 2px solid rgb(0 0 0);

border-radius: 7px;

background-color: rgba(0 0 0 / 0.25);

padding: 5px;

margin-top: 5px;

width: fit-content;

}

/* other courseCard styles not shown */

div.courseCard.SWEN {

border-color: rgb(var(--swenColor));

background-color: rgba(var(--swenColor) / 0.25);

}

div.courseCard.CSCI {

border-color: rgb(var(--csciColor));

background-color: rgba(var(--csciColor) / 0.25);

}

<div class="courseCard" [class]="swen261.curriculum">

<h4>{{swen261.code}}:&nbsp;</h4>

<p><em>{{swen261.title}}</em></p>

</div>

<div class="courseCard" [class]="csci141.curriculum">

<h4>{{csci141.code}}:&nbsp;</h4>

<p><em>{{csci141.title}}</em></p>

</div>

h1, h2, h3, h4, h5, h6 {

font-family: 'Montserrat', sans-serif;

color: var(--primaryColor);

}

/*

* CSS variables/constants

*/

:root {

--redColor: 255 0 0;

--blackColor: 0 0 0;

--primaryColor: rgb(255, 165, 0);

/* Curriculum colors */

--swenColor: 255 165 0; /* orange */

--csciColor: 200 200 255; /* light blue */

--physColor: 90 90 255; /* purple */

}

11

Global styles defined in src/styles.css

Component-specific styles.

12 of 83

You can influence DOM elements via attribute binding.

  • DOM elements have many attributes that set its state.
    • Example: <div class=”courseCard”>...</div>
  • Angular provides dynamic binding to pull state from the controller object.
    • Example: <div [class]=”curriculum”>...</div>
  • These can also be Signals so the DOM element is updated whenever the Signal changes.
    • Example: <div [class]=”curriculum()”>...</div>

12

13 of 83

You can also perform dynamic operations when the user interacts with a DOM element.

  • Angular provides the syntax, (action)=“myHandler($event)”,
    • Where action is a type of user interaction, such as click or keypress.
    • And myHandler is a method in the Controller class.
    • And $event is the DOM Event object supplied by the browser.
  • Example:

<h3>Dynamic Element Attributes and Event Handlers</h3>

<button (click)="toggleAction($event)"

[innerText]="buttonText()"

[disabled]="buttonState()"

></button>

13

User clicks on the button…

14 of 83

DOM Attributes and Interaction (Part 2)

Controller code:

// VM data for element attributes and interactions

buttonText = signal('Click me!');

buttonState = signal<Nullable<string>>(null);

// VM event handlers for element interaction

toggleAction($event: Event) {

console.log($event);

this.buttonText.set('Click on me again, I dare you!');

this.buttonState.set('disabled');

}

14

CSS Style code:

button:not(:disabled) {

cursor: pointer;

border-color: rgb(var(--blueColor));

background-color: unset;

color: rgb(var(--blueColor));

}

button:disabled {

cursor: not-allowed;

border-color: rgb(var(--redColor));

color: unset;

}

You would think the DOM disabled attribute would hold a boolean value; true for disabled or false for enabled. NOPE!

A null value means “I’m enabled” and the value disabled is means “I’m disabled.”

These are truly ugly styles. Please don’t replicate these in your project. 😉

15 of 83

Let’s create a simple Angular widget.

Case Study: Create a simple, numeric slider widget.

15

A widget is a View component. View components can come in many “sizes”.

A parent View communicates with a child View using input signals.

The child uses output signals to communicate with the parent.

16 of 83

Let’s design the slider Angular widget.

16

17 of 83

And now the HTML template code used in App and for the Slider.

App component template code:

<h3>Simple Angular Widget</h3>

<app-slider-widget [initialValue]="5"

(valueChanged)="handleSlider($event)"

></app-slider-widget>

<p>Value: <span [innerText]="currentSliderValue()"></span></p>

Slider template code:

<input type="range"

class="slider"

[min]="minValue()"

[max]="maxValue()"

[value]="initialValue()"

(change)="updateValue($event)"

>

17

18 of 83

You can also use control flows in Angular Views.

18

Conditional Logic

Iteration Logic

<h2>Conditional Logic: Launch Countdown</h2>

@if (countDown() > 5) {

<p>Count down: {{countDown()}}</p>

} @else if (countDown() > 0) {

<h4 class="final countDown">{{countDown()}}</h4>

} @else {

<h4 class="final">Blast off!</h4>

}

<h2>Iteration Logic: Course List</h2>

@for (course of courseList(); track course.code) {

<div class="courseCard" [class]="course.curriculum">

<h4>{{course.code}}:&nbsp;</h4>

<p><em>{{course.title}}</em></p>

</div>

} @empty {

<p>Wait for it...</p>

}

19 of 83

1) View Basics: essential aspects of build UI components in Angular

  • What is Angular?
  • The structure of an Angular View component.
  • Binding data into the view.
  • HTML elements are the basic building blocks of view structure.
  • CSS rules are the basic building blocks of view styles.
  • Parameterize data passed from View components to raw HTML elements.
  • Event handlers are the basic building blocks of view interactions.
  • Building small, reusable View components (aka widgets).
  • Using control logic (conditionals and iteration) in Views.

STOP HERE

Take a break before proceeding to the next chapter.�Walk around for 5 minutes and get glass of water.

DEMO

Let’s take this moment to look at the working increment we built in this chapter.

19

20 of 83

2) Routing: apps contain multiple pages and how to navigate between them.

  • What are pages and what is routing?
  • User Cases lead to Analysis Models lead to Pages and Routing decisions.
  • Configuring the UI routes.
  • Links in Views to route between pages
  • Programmatic routing

20

21 of 83

An application is composed of pages.

  • A Page is a distinct UI view that the actor can navigate to.
  • Navigation is controlled by either HTML links or buttons or the result of some event in the current page.
  • Every UI should have a default page upon entering the UI.
  • Just like in a static web site, each page has a distinct URL.
  • Page navigation forms a graph of connections much like a state machine.
  • The design of UI pages can be a subtle activity so we will focus on standard CRUD operations that is a common pattern of Enterprise systems.
  • Another UI pattern is Master -> Detail pages.
  • We provide you with a sample solution that you can use as a template for the UI of your term project.

21

22 of 83

Let’s consider a relatively simple GUI for a Learning Management System

22

Use Cases

Page State Machine

23 of 83

There is only one App component. Pages are displayed within it. Routing is the process of switching between pages.

23

export const routes: Routes = [

{path: 'courses/view-all', component: ViewAllCourses}

];

<main>

<router-outlet/>

</main>

app.html

app.routes.ts

24 of 83

The Router Config file maps URL patterns to the Page components.

24

export const routes: Routes = [

{path: 'courses/view-all', component: ViewAllCourses},

{path: 'courses/view-detail/:courseId', component: ViewCourseDetail},

{path: 'courses/create-course', component: EditCourse},

{path: 'courses/update-course/:courseId', component: EditCourse},

];

Each path in the state machine has a corresponding URL in the router configuration.

The route path is then mapped to a specific View component to render.

Some routes can share the same View component, like Create and Update routes with EditCourse.

25 of 83

The Analysis model of the View all Courses user story.

25

26 of 83

The Design model of the View all Courses user story.

26

27 of 83

2) Routing: apps contain multiple pages and how to navigate between them.

  • What are pages and what is routing?
  • User Cases lead to Analysis Models lead to Pages and Routing decisions.
  • Configuring the UI routes.
  • Links in Views to route between pages
  • Programmatic routing

STOP HERE

Take a break before proceeding to the next chapter.�Walk around for 5 minutes and get glass of water.

DEMO

Let’s take this moment to look at the working increment we built in this chapter.

27

28 of 83

3) Services: introduction to simple, data providers

  • What is a Service?
  • How to use Angular’s dependency injection mechanism.
  • How to use RxJS Observables to deliver asynchronous data to Views.
  • How to convert Observables into Angular Signal for use in Views.

28

29 of 83

What is a Service (in the frontend)?

A Service is any OO object that can be injected into other components, such as View components, to perform logic that is View-independent.

  • Services can supply data, especially Entities from backend services.
  • Services can manipulate data, specifically for specialized Views.
    • Some views need customized data crafted from “raw” data from the backend.
  • Services can be used to coordinate communication between multiple views (or other services).
    • This is commonly known as the Mediator design pattern.
  • Services are usually singular objects.
    • Attributes of the Service is shared across multiple clients of the Service.
    • This (single, shared) instance is managed by Angular in a process called Dependency Injection.

29

30 of 83

Angular has a built-in dependency injection mechanism.

30

@Injectable({

providedIn: 'root'

})

export class CourseService {

findAllByCurriculum(curriculum: Curriculum):

Observable<ReadonlyArray<CourseSummary>> {

// TODO logic to retrieve a collection of Course summaries

}

}

import {inject /* and others */} from '@angular/core';

import {CourseService} from '../../../services/course-service';

export class ViewAllCourses {

private readonly courseService = inject(CourseService);

readonly courseList: WritableSignal<ReadonlyArray<CourseSummary>> = signal([]);

selectCurriculum(curriculum: Curriculum) {

this.courseService.findAllByCurriculum(curriculum)

.subscribe({

next: (courses: ReadonlyArray<CourseSummary>) => {

// display the Course list in the UI

this.courseList.set(courses);

},

});

}

view-all-courses.ts

course-service.ts

The @Injectable annotation tells Angular that this class can be injected into other components. This is what the inject function does in the ViewAllCourses class (below).

31 of 83

Let’s take another look at the Observer pattern in this design.

  • A Signal is an “observable” that integrates tightly with Angular’s view rendering mechanism.
    • The view “observes” changes in the Signal and re-renders the portion of the view that invokes that Signal as a function call.
    • A WritableSignal can be set or updated programmatically.
    • Signals replaced other –more complex– rendering mechanisms that used to use RxJS Observables.
  • An Observable is an “observable” from the RxJS library.
    • An Observer is an interface that can subscribe to an “observable”
    • Observables also support a rich set of “pipe” operations; more to come
  • Many other Angular features (HttpClient, Routing data, Routing guards, etc) use RxJS, so you will need to understand how to convert from these to signals.

31

32 of 83

Converting from RxJS Observable to Angular Signals.

  • Option 1:
    • Create a WritableSignal with a default value (null or empty array)
    • Subscribe to the source RxJS Observable and when the data arrives use the Signal’s set method to copy the data to the Signal, thus triggering the view re-rendering.
  • Option 2:
    • Declare a Signal variable that isn’t initialized.
    • In the View constructor or ngOnInit method use our custom buildSignal function to create a Signal object from the Observable, like this:

32

import {buildSignal} from '../../utils/signal-utils';

// other code not shown�readonly courseList!: Signal<ReadonlyArray<CourseSummary>>;

ngOnInit() {

// use a Service for the list creation

this.courseList = buildSignal(this.courseService.findAllByCurriculum(Curriculum.SWEN), [], this.injector);

}

33 of 83

The Analysis model of the View a Course Details user story.

33

  • Navigate from ViewAllCourses to ViewCourseDetail by clicking on Course card.
  • The Route includes the Course id from the Summary object to lookup the full Course.
  • The ViewCourseDetail provides a “Course card” for the pre-req, which is also clickable.
  • The VCD page should update when it routes to the pre-requisite course.

34 of 83

The Design model of the View a Course Details user story.

34

35 of 83

The Angular Router can pass data to the View.

  • The route path shows the name of the parameter in the route config:

{path: 'courses/view-detail/:courseId', component: ViewCourseDetail},

  • The ActivatedRoute service provides access to these parameters:

export class ViewCourseDetail implements OnInit {

private readonly activatedRoute = inject(ActivatedRoute);

private readonly courseService = inject(CourseService);

readonly course: WritableSignal<Nullable<Course>> = signal(null);

ngOnInit() {

this.activatedRoute.params.subscribe(params => {

const id: UUID = params['courseId'];

this.courseService.findById(id).subscribe(course => {

this.course.set(course);

});

});

}

}

35

36 of 83

Use a Data Resolver component in your routes.

  • The route path shows the name of the parameter in the route config:

{path: 'courses/view-detail/:courseId', component: ViewCourseDetail,

resolve: {course: CourseResolver},

},

@Injectable({providedIn: 'root'})

export class CourseResolver implements Resolve<Nullable<Course>> {

private readonly courseService = inject(CourseService);

private readonly router = inject(Router);

resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): MaybeAsync<Nullable<Course> | RedirectCommand> {

const courseId = route.params['courseId'] as UUID;

if (isUUID(courseId)) {

// return the Observable returned by the 'find' command

return this.courseService.findById(courseId);

} else {

// return a redirect command that issues a 404 page

return new RedirectCommand(this.router.parseUrl('/page-not-found'))

}

}

}

36

37 of 83

Update the View component to use this resolver:

export class ViewCourseDetail implements OnInit {

readonly course: WritableSignal<Nullable<Course>> = signal(null);

// more code not shown

ngOnInit() {

this.activatedRoute.data

.pipe(

// extract the 'course' data object from the resolver

map((data:Data) => data['course'] as Course),

)

.subscribe({

next: (c: Course) => {

this.course.set(c);

}

});

}

}

37

38 of 83

Let’s look at a visual model of the Router operation.

38

39 of 83

3) Services: introduction to simple, data providers

  • What is a Service?
  • How to use Angular’s dependency injection mechanism.
  • How to use RxJS Observables to deliver asynchronous data to Views.
  • How to convert Observables into Angular Signal for use in Views.

STOP HERE

Take a break before proceeding to the next chapter.�Walk around for 5 minutes and get glass of water.

DEMO

Let’s take this moment to look at the working increment we built in this chapter.

39

40 of 83

4) Forms: build data-entry View components

  1. Simple forms: Template-driven
  2. Complex forms (aka data entry): Reactive forms
  3. The HTML elements that support data entry.
  4. Field validation: simple and complex/custom
  5. Validation error messages
  6. Asynchronous field validation

40

41 of 83

Template-driven forms is good for simple UI interactions.

Curriculum selection in View All Courses page.

41

42 of 83

Use ngModel and ngModelChange to select a Curriculum to display.

Use <select> HTML control in the View template:

<label for="curriculum">Change curricula: </label>

<select id="curriculum" [(ngModel)]="selectedCurriculum" (ngModelChange)="selectCurriculum($event)">

@for (curr of curricula; track curr) {

<option [ngValue]="curr">{{curr}}</option>

}

</select>

View Controller uses ngModelChanges to update the list:

selectCurriculum(curriculum: Curriculum) {

this.courseService.findAllByCurriculum(curriculum).subscribe({

next: (summaries) => this.courseList.set(summaries),

});

}

42

43 of 83

Reactive Forms is good for more complex data-entry views.

  • FormGroup config => HTML form controls
  • Simple text fields
  • Field validation
  • Error messages
  • Custom validators
  • Rich fields: numeric, checkboxes, “reference” field
  • Button state (form state machine)
  • Using Entity Services and QCRS to save the entity

43

44 of 83

The Analysis model and UX design of the Create a Course user story.

44

This is only half of the Create a Course data-entry View. The whole thing wouldn’t fit.

45 of 83

The Design model for the Create a Course user story.

45

46 of 83

Let’s see how this maps to the UX design.

46

47 of 83

HTML provides a fairly rich set of basic form control widgets.

  • Single selection
  • Multiple selection
  • Lots of text field options:
    • numeric, email, date (month, week), url, file, image, color
    • textarea
    • password

47

48 of 83

Reactive Forms handle automated field validation and error messages.

48

The Submit button is disabled as long as any form field is invalid. Again Angular forms API provides the necessary hooks to make this easy.

49 of 83

4) Forms: build data-entry View components

  • Simple forms: Template-driven
  • Complex forms (aka data entry): Reactive forms
  • The HTML elements that support data entry.
  • Field validation: simple and complex/custom
  • Validation error messages
  • Asynchronous field validation

STOP HERE

Take a break before proceeding to the next chapter.�Walk around for 5 minutes and get glass of water.

DEMO

Let’s take this moment to look at the working increment we built in this chapter.

49

50 of 83

5: Services: that provide CRUD operations

In the previous chapter we focused on the View-side of building data-entry pages; let’s take a brief pause to discuss the Service-side.

  1. Command Query Request Separation (CQRS) pattern
  2. Update a Course user story
  3. Delete a Course user story

50

51 of 83

The Analysis model of the Update a Course user story.

  • Four step process:
    1. Data Resolver selects a specific Course from Service
    2. Course pre-populates the View
    3. User edits the data
    4. Submit calls the Service update method

51

52 of 83

The Design model of the Update a Course user story.

52

53 of 83

How to pre-populate the EditCourse view with an existing Course.

ngOnInit(): void {

this.activatedRoute.data

.pipe(

map((data:Data) => data['course'] ?? null),

)

.subscribe({

next: (course: Nullable<Course>) => {

this.form = this.makeForm(course);

}

});

}

private makeForm(course: Nullable<Course>):� FormGroup<EditCourseForm> {

// extract initial data

const initialData : EditCourseData = {

id: course?.id ?? null,

code: course?.code ?? '',

title: course?.title ?? '',

units: course?.units ?? 3,

// some fields not shown

}

// create form configuration (partial)

return this.fb.group({

id: new FormControl<Nullable<UUID>>(initialData.id, {...})

code: new FormControl<CourseCode>(initialData.code, {...})

title: new FormControl<string>(initialData.title, {...})

units: new FormControl<number>(initialData.units, {...})

53

The View is initialized with the ActivatedRoute and pulls the Course from the data Observable.

The Course object is passed to the method that builds the form. It extracts the Course data into an initialData object literal. If there is no Course (we are creating not updating), then we provide default values.

That is then used to populate the initial values of each form control for the form group.

54 of 83

The Analysis model of the Delete a Course user story.

54

Basically, the same Analysis model for being able to delete Courses from the View All Courses page.

55 of 83

The Design model of the Delete a Course user story.

55

56 of 83

5: Services: that provide CRUD operations

In the previous chapter we focused on the View-side of building data-entry pages; let’s take a brief pause to discuss the Service-side.

  • Command Query Request Separation (CQRS) pattern
  • Update a Course user story
  • Delete a Course user story

STOP HERE

Take a break before proceeding to the next chapter.�Walk around for 5 minutes and get glass of water.

DEMO

Let’s take this moment to look at the working increment we built in this chapter.

56

57 of 83

6) View Composition: decompose complex views into smaller, easier to maintain subviews.

  1. View hierarchies
  2. Course Card
  3. Fancy Icon Button
  4. Course Details Section

57

58 of 83

Pages, and Views in general, are a natural hierarchy of subviews.

  • HTML is a classic example:

<body>� <h2>View All Courses</h2>

<p><a routerLink="/courses/create-course">Create a Course</a></p>� </body>

  • But more abstractly we can think of subviews as chunks of coherent view (or interaction) content:

58

References:

59 of 83

Let’s consider the View All Courses page and propose new subviews.

59

The page is roughly composed of three elements: a title (<h2>), a curriculum filter (<select>) and a table of Courses.

Let’s propose two new subview components: a CourseCard and a fancy IconButton.

60 of 83

Create subview components when you see duplicated view code.

60

<div class="courseCard"

[class]="course.curriculum"

(click)="viewCourse(course)"

>

<h4>{{ course.code }}:&nbsp;</h4>

<p><em>{{ course.title }}</em></p>

</div>

<app-course-card [course]="course"

(courseClicked)="viewCourse($event)"

width="100%"

></app-course-card>

build a subview component

61 of 83

Creating widgets allows for greater consistency and ease of development.

Our current HTML buttons are okay:

We can make them a little more fancy by adding a icon:

We’ll use the FontAwesome collection of icons.

61

62 of 83

The template of the IconButton is simple:

<button type="{{type()}}"

class="icon-button"

(click)="activateButton($event)"

[disabled]="disabled()"

>

<i class="fa {{iconName()}}"></i> {{ title() }}

</button>

62

The name of the FontAwesome icon, such as fa-pencil (used for Edit) or fa-ban (used for Delete).

The text title of the button, such as “Edit” or “Delete”.

The disabled button flag is controlled by an input Signal so it is dynamically controlled by the parent View.

63 of 83

Sometimes we need the Parent view to inject HTML content into the body of a Child view.

<app-course-detail-section title="Code">

<p class="projected-content">

{{ courseCode() }}

</p>

</app-course-detail-section>

<section>

<h3> {{ title() }} </h3>

<ng-content></ng-content>

</section>

63

Paragraph is injected into the section below the heading.

ViewCourseDetails

CourseDetailSection

64 of 83

6) View Composition: decompose complex views into smaller, easier to maintain subviews.

  • View hierarchies
  • Course Card
  • Fancy Icon Button
  • Course Details Section

STOP HERE

Take a break before proceeding to the next chapter.�Walk around for 5 minutes and get glass of water.

DEMO

Let’s take this moment to look at the working increment we built in this chapter.

64

65 of 83

7) Global Layout: add UI elements that are common across all pages.

  1. Add Header and Footer to App component
  2. Global navigation bar
  3. Fixed position for Header and Footer

65

66 of 83

Most web applications use a global header and footer that is shared across all pages. Use the App view for that.

66

Header has application title and nav and user controls.

Footer usually has Copyright info and year.

67 of 83

The Header and Footer is part of the App component.

<header>

<h1>{{appTitle}}</h1>

<nav>

<a>Global nav (TBD)</a>

</nav>

<div class="user-controls">

<a>User controls (TBD)</a>

</div>

</header>

<main>

<router-outlet/>

</main>

<footer>

<p>SWEN-261 &copy; {{year}}</p>

</footer>

67

68 of 83

Global navigation bar is usually either at the top or on the left side of the app.

68

Nav links that are shared across all pages.

69 of 83

Global navigation bar is usually a list of links.

<header>

<h1>{{appTitle}}</h1>

<nav>

<ul>

<li><a routerLink="/courses/view-all">View all courses</a></li>

<li><a routerLink="/courses/create-course">Create a course</a></li>

</ul>

</nav>

<div class="user-controls">

<a>User controls (TBD)</a>

</div>

</header>

69

70 of 83

Fixed position for Header and Footer

70

The Header is fixed at the top of the page.

The Footer is fixed at the bottom of the page.

The Page content is fixed in the center and is scrollable.

71 of 83

7) Global Layout: add UI elements that are common across all pages.

  • Add Header and Footer to App component
  • Global navigation bar
  • Fixed position for Header and Footer

STOP HERE

Take a break before proceeding to the next chapter.�Walk around for 5 minutes and get glass of water.

DEMO

Let’s take this moment to look at the working increment we built in this chapter.

71

72 of 83

8: Security: users, authentication and authorization

  1. What is security?
  2. Users and Authentication
    1. Login Page
    2. UserService with login operation and user$ Observable
  3. Authorization Guard and Route configuration
    • Angular Router supports guards on specific pages
    • Not Authorized Page
  4. Conditionalize View elements (hide or disable) based upon security info
  5. Add User widget in global Header
  6. Add User dialog
    • Extend UserService with logout operation

72

73 of 83

What is security?

  • Ensure that the app protects: confidentiality, data integrity and availability.
  • Authentication: validate that a user is who they say they are
  • Authorization: ensure a user only has access to certain data and operations
  • …just scratching the surface

73

74 of 83

Security code can be tricky. We will provide you with the essentials that you can tweak as needed.

74

75 of 83

Create a Route guard to protect secure pages.

75

76 of 83

Security information to be used to conditionalize aspects of the UI.

76

Log in link is only shown when no one is logged in.

The Delete button is disabled when no one is logged in.

If an Admin logs in, then the Delete button is enabled.

If an Student logs in, then the Delete button is hidden.

77 of 83

The UserWidget in the global layout provide a pop-up dialog.

77

78 of 83

Security is a complex topic, we are just scratching the surface…

  • Your project will need some level of user-support and security.
  • Feel free to steal the infrastructure we will provide in the activity.
  • You can tweak it to your application’s needs.

78

79 of 83

8: Security: users, authentication and authorization

  • What is security?
  • Users and Authentication
    • Login Page
    • UserService with login operation and user$ Observable
  • Authorization Guard and Route configuration
    • Angular Router supports guards on specific pages
    • Not Authorized Page
  • Conditionalize View elements (hide or disable) based upon security info
  • Add User widget in global Header
  • Add User dialog
    • Extend UserService with logout operation

STOP HERE

Take a break before proceeding to the next chapter.�Walk around for 5 minutes and get glass of water.

DEMO

Let’s take this moment to look at the working increment we built in this chapter.

79

80 of 83

What’s coming up…

  1. Architecture of Web UIs
    • Online Lecture (video and slides)
    • In-class Activity (instructions)
  2. Architecture of Distributed Services
    • Online Lecture (video and slides)
    • In-class Activity (instructions)
  3. Architecture of Persistence
    • Online Lecture (video and slides)
    • In-class Activity (instructions)

But first… do the Activity: Setup Your Dev Environment before the next class.

80

81 of 83

STOP HERE

The rest of this lecture is beyond the scope of the UI Spike activity.

You may read the following content to learn more about about topics that I think will be useful to you. Come back to these pages as reference throughout the semester as a reference guide.

81

82 of 83

9: Dev Tools: debug your View and Service components on the browser

  • TBD

82

83 of 83

10. Asynchronicity: the main types of Observer pattern tools

  • TBD

83