From d894e40dd586f7dec7ee013e3f7ea12391f4119e Mon Sep 17 00:00:00 2001 From: Bob Watson Date: Wed, 14 Dec 2022 15:08:32 -0800 Subject: [PATCH] docs: add first-app-lesson-09 example (#48512) PR Close #48512 --- aio/content/examples/examples.bzl | 1 + .../examples/first-app-lesson-09/BUILD.bazel | 11 ++ .../e2e/src/app.e2e-spec.ts | 39 ++++++ .../first-app-lesson-09/example-config.json | 6 + .../src/app/app.component.css | 12 ++ .../src/app/app.component.ts | 24 ++++ .../src/app/home/home.component.css | 39 ++++++ .../src/app/home/home.component.ts | 39 ++++++ .../housing-location.component.css | 31 +++++ .../housing-location.component.ts | 23 ++++ .../src/app/housing.service.ts | 119 ++++++++++++++++++ .../src/app/housinglocation.ts | 10 ++ .../src/assets/location-pin.svg | 4 + .../first-app-lesson-09/src/assets/logo.svg | 7 ++ .../first-app-lesson-09/src/favicon.ico | Bin 0 -> 948 bytes .../first-app-lesson-09/src/index.html | 16 +++ .../examples/first-app-lesson-09/src/main.ts | 10 ++ .../first-app-lesson-09/src/styles.css | 23 ++++ .../first-app-lesson-09/stackblitz.json | 17 +++ 19 files changed, 431 insertions(+) create mode 100644 aio/content/examples/first-app-lesson-09/BUILD.bazel create mode 100644 aio/content/examples/first-app-lesson-09/e2e/src/app.e2e-spec.ts create mode 100644 aio/content/examples/first-app-lesson-09/example-config.json create mode 100644 aio/content/examples/first-app-lesson-09/src/app/app.component.css create mode 100644 aio/content/examples/first-app-lesson-09/src/app/app.component.ts create mode 100644 aio/content/examples/first-app-lesson-09/src/app/home/home.component.css create mode 100644 aio/content/examples/first-app-lesson-09/src/app/home/home.component.ts create mode 100644 aio/content/examples/first-app-lesson-09/src/app/housing-location/housing-location.component.css create mode 100644 aio/content/examples/first-app-lesson-09/src/app/housing-location/housing-location.component.ts create mode 100644 aio/content/examples/first-app-lesson-09/src/app/housing.service.ts create mode 100644 aio/content/examples/first-app-lesson-09/src/app/housinglocation.ts create mode 100644 aio/content/examples/first-app-lesson-09/src/assets/location-pin.svg create mode 100644 aio/content/examples/first-app-lesson-09/src/assets/logo.svg create mode 100644 aio/content/examples/first-app-lesson-09/src/favicon.ico create mode 100644 aio/content/examples/first-app-lesson-09/src/index.html create mode 100644 aio/content/examples/first-app-lesson-09/src/main.ts create mode 100644 aio/content/examples/first-app-lesson-09/src/styles.css create mode 100644 aio/content/examples/first-app-lesson-09/stackblitz.json diff --git a/aio/content/examples/examples.bzl b/aio/content/examples/examples.bzl index 8bdc67d3bb0..52609862948 100644 --- a/aio/content/examples/examples.bzl +++ b/aio/content/examples/examples.bzl @@ -51,6 +51,7 @@ EXAMPLES = { "first-app-lesson-06": {"stackblitz": True, "zip": True}, "first-app-lesson-07": {"stackblitz": True, "zip": True}, "first-app-lesson-08": {"stackblitz": True, "zip": True}, + "first-app-lesson-09": {"stackblitz": True, "zip": True}, "form-validation": {"stackblitz": True, "zip": True}, "forms": {"stackblitz": True, "zip": True}, "forms-overview": {"stackblitz": True, "zip": True}, diff --git a/aio/content/examples/first-app-lesson-09/BUILD.bazel b/aio/content/examples/first-app-lesson-09/BUILD.bazel new file mode 100644 index 00000000000..1108db20e21 --- /dev/null +++ b/aio/content/examples/first-app-lesson-09/BUILD.bazel @@ -0,0 +1,11 @@ +load("//aio/content/examples:examples.bzl", "docs_example") +load("@aio_npm//@angular/build-tooling/bazel/remote-execution:index.bzl", "ENABLE_NETWORK") + +package(default_visibility = ["//visibility:public"]) + +docs_example( + name = "first-app-lesson-09", + # This example downloads fonts and images from googleapis.com + test_exec_properties = ENABLE_NETWORK, + test_tags = ["requires-network"], +) diff --git a/aio/content/examples/first-app-lesson-09/e2e/src/app.e2e-spec.ts b/aio/content/examples/first-app-lesson-09/e2e/src/app.e2e-spec.ts new file mode 100644 index 00000000000..9d46ebdd336 --- /dev/null +++ b/aio/content/examples/first-app-lesson-09/e2e/src/app.e2e-spec.ts @@ -0,0 +1,39 @@ +import { browser, element, by, logging } from 'protractor'; + +describe('first-app-lesson-09 app', () => { + + beforeEach(() => browser.get('')); + + it('should display correct title', async () => { + expect(await element.all(by.css('.brand-logo')).get(0).getAttribute('src')).toContain('/assets/logo.svg'); + }); + + it('should have a filter string input', async () => { + expect(await element.all(by.css('input')).get(0).getAttribute('placeholder')).toEqual('Filter by city'); + expect(await element.all(by.css('input')).get(0).getAttribute('type')).toEqual('text'); + }); + + it('should have a search button', async () => { + expect(await element.all(by.css('button')).get(0).getText()).toEqual('Search'); + }); + + it('should have a housing-location component', async () => { + expect(await element.all(by.css('.listing > .listing-location')).get(0).getText()).toEqual('Chicago, IL'); + }); + + it('should have a title in the housing-location component', async () => { + expect(await element.all(by.css('.listing > h2')).get(0).getText()).toEqual('Acme Fresh Start Housing'); + }); + + it('should have 10 housing-location components', async () => { + expect(await element.all(by.css('app-housing-location'))['length'] === 10); + }); + + afterEach(async () => { + // Assert that there are no errors emitted from the browser + const logs = await browser.manage().logs().get(logging.Type.BROWSER); + expect(logs).not.toContain(jasmine.objectContaining({ + level: logging.Level.SEVERE, + } as logging.Entry)); + }); +}); diff --git a/aio/content/examples/first-app-lesson-09/example-config.json b/aio/content/examples/first-app-lesson-09/example-config.json new file mode 100644 index 00000000000..6b43b07a8db --- /dev/null +++ b/aio/content/examples/first-app-lesson-09/example-config.json @@ -0,0 +1,6 @@ +{ + "useCommonBoilerplate": false, + "overrideBoilerplate": [ + "src/styles.css" + ] +} diff --git a/aio/content/examples/first-app-lesson-09/src/app/app.component.css b/aio/content/examples/first-app-lesson-09/src/app/app.component.css new file mode 100644 index 00000000000..ca76bf56f4e --- /dev/null +++ b/aio/content/examples/first-app-lesson-09/src/app/app.component.css @@ -0,0 +1,12 @@ +:host { + --content-padding: 10px; +} +header { + display: block; + height: 60px; + padding: var(--content-padding); + box-shadow: 0px 5px 25px var(--shadow-color); +} +.content { + padding: var(--content-padding); +} diff --git a/aio/content/examples/first-app-lesson-09/src/app/app.component.ts b/aio/content/examples/first-app-lesson-09/src/app/app.component.ts new file mode 100644 index 00000000000..f53b0fe39c9 --- /dev/null +++ b/aio/content/examples/first-app-lesson-09/src/app/app.component.ts @@ -0,0 +1,24 @@ +import { Component } from '@angular/core'; +import { HomeComponent } from './home/home.component'; + +@Component({ + selector: 'app-root', + standalone: true, + imports: [ + HomeComponent, + ], + template: ` +
+
+ +
+
+ +
+
+ `, + styleUrls: ['./app.component.css'], +}) +export class AppComponent { + title = 'homes'; +} diff --git a/aio/content/examples/first-app-lesson-09/src/app/home/home.component.css b/aio/content/examples/first-app-lesson-09/src/app/home/home.component.css new file mode 100644 index 00000000000..b9b528d636f --- /dev/null +++ b/aio/content/examples/first-app-lesson-09/src/app/home/home.component.css @@ -0,0 +1,39 @@ +.results { + display: grid; + column-gap: 14px; + row-gap: 14px; + grid-template-columns: repeat(3, 1fr); + margin-top: 50px; +} + +input[type='text'] { + border: solid 1px var(--primary-color); + padding: 10px; + border-radius: 8px; + margin-right: 4px; + display: inline-block; + width: 30%; +} + +button { + padding: 10px; + border: solid 1px var(--primary-color); + background: var(--primary-color); + color: white; + border-radius: 8px; +} + +@media (min-width: 500px) and (max-width: 768px) { + .results { + grid-template-columns: repeat(2, 1fr); + } + input[type='text'] { + width: 70%; + } +} + +@media (max-width: 499px) { + .results { + grid-template-columns: 1fr; + } +} diff --git a/aio/content/examples/first-app-lesson-09/src/app/home/home.component.ts b/aio/content/examples/first-app-lesson-09/src/app/home/home.component.ts new file mode 100644 index 00000000000..5ba8e77c954 --- /dev/null +++ b/aio/content/examples/first-app-lesson-09/src/app/home/home.component.ts @@ -0,0 +1,39 @@ +import { Component, inject } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { HousingLocationComponent } from '../housing-location/housing-location.component'; +import { HousingLocation } from '../housinglocation'; +import { HousingService } from '../housing.service'; + +@Component({ + selector: 'app-home', + standalone: true, + imports: [ + CommonModule, + HousingLocationComponent + ], + template: ` +
+
+ + +
+
+
+ + +
+ `, + styleUrls: ['./home.component.css'], +}) + +export class HomeComponent { + housingLocationList: HousingLocation[] = []; + housingService: HousingService = inject(HousingService); + + constructor() { + this.housingLocationList = this.housingService.getAllHousingLocations(); + } + +} diff --git a/aio/content/examples/first-app-lesson-09/src/app/housing-location/housing-location.component.css b/aio/content/examples/first-app-lesson-09/src/app/housing-location/housing-location.component.css new file mode 100644 index 00000000000..2a970e0a6b8 --- /dev/null +++ b/aio/content/examples/first-app-lesson-09/src/app/housing-location/housing-location.component.css @@ -0,0 +1,31 @@ +.listing { + background: var(--accent-color); + border-radius: 30px; + padding-bottom: 30px; +} +.listing-heading { + color: var(--primary-color); + padding: 10px 10px 0 10px; +} +.listing-photo { + height: 250px; + width: 100%; + object-fit: cover; + border-radius: 30px 30px 0 0; +} +.listing-location { + padding: 10px 10px 20px 10px; +} +.listing-location::before { + content: url('/assets/location-pin.svg') / ''; +} + +section.listing a { + padding-left: 10px; + text-decoration: none; + color: var(--primary-color); +} +section.listing a::after { + content: '\203A'; + margin-left: 5px; +} diff --git a/aio/content/examples/first-app-lesson-09/src/app/housing-location/housing-location.component.ts b/aio/content/examples/first-app-lesson-09/src/app/housing-location/housing-location.component.ts new file mode 100644 index 00000000000..24e930ce9f2 --- /dev/null +++ b/aio/content/examples/first-app-lesson-09/src/app/housing-location/housing-location.component.ts @@ -0,0 +1,23 @@ +import { Component, Input } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { HousingLocation } from '../housinglocation'; + +@Component({ + selector: 'app-housing-location', + standalone: true, + imports: [CommonModule], + template: ` +
+ Exterior photo of {{housingLocation.name}} +

{{ housingLocation.name }}

+

{{ housingLocation.city}}, {{housingLocation.state }}

+
+ `, + styleUrls: ['./housing-location.component.css'], +}) + +export class HousingLocationComponent { + + @Input() housingLocation!: HousingLocation; + +} diff --git a/aio/content/examples/first-app-lesson-09/src/app/housing.service.ts b/aio/content/examples/first-app-lesson-09/src/app/housing.service.ts new file mode 100644 index 00000000000..b2bb86ea1e7 --- /dev/null +++ b/aio/content/examples/first-app-lesson-09/src/app/housing.service.ts @@ -0,0 +1,119 @@ +import { Injectable } from '@angular/core'; +import { HousingLocation } from './housinglocation'; + +@Injectable({ + providedIn: 'root' +}) +export class HousingService { + private img_server = "https://storage.googleapis.com/angular-tutorial-assets/first-app/"; + protected housingLocationList: HousingLocation[] = [ + { + id: 0, + name: 'Acme Fresh Start Housing', + city: 'Chicago', + state: 'IL', + photo: this.img_server + 'house_0.png', + availableUnits: 4, + wifi: true, + laundry: true + }, + { + id: 1, + name: 'A113 Transitional Housing', + city: 'Santa Monica', + state: 'CA', + photo: this.img_server + 'house_1.png', + availableUnits: 0, + wifi: false, + laundry: true + }, + { + id: 2, + name: 'Warm Beds Support', + city: 'Juneau', + state: 'AK', + photo: this.img_server + 'house_2.png', + availableUnits: 1, + wifi: false, + laundry: false + }, + { + id: 3, + name: 'Homesteady Housing', + city: 'Chicago', + state: 'IL', + photo: this.img_server + 'house_3.png', + availableUnits: 1, + wifi: true, + laundry: false + }, + { + id: 4, + name: 'Happy Homes Group', + city: 'Gary', + state: 'IN', + photo: this.img_server + 'house_4.png', + availableUnits: 1, + wifi: true, + laundry: false + }, + { + id: 5, + name: 'Hopeful Apartment Group', + city: 'Oakland', + state: 'CA', + photo: this.img_server + 'house_5.png', + availableUnits: 2, + wifi: true, + laundry: true + }, + { + id: 6, + name: 'Seriously Safe Towns', + city: 'Oakland', + state: 'CA', + photo: this.img_server + 'house_6.png', + availableUnits: 5, + wifi: true, + laundry: true + }, + { + id: 7, + name: 'Hopeful Housing Solutions', + city: 'Oakland', + state: 'CA', + photo: this.img_server + 'house_7.png', + availableUnits: 2, + wifi: true, + laundry: true + }, + { + id: 8, + name: 'Seriously Safe Towns', + city: 'Oakland', + state: 'CA', + photo: this.img_server + 'house_8.png', + availableUnits: 10, + wifi: false, + laundry: false + }, + { + id: 9, + name: 'Capital Safe Towns', + city: 'Portland', + state: 'OR', + photo: this.img_server + 'house_9.png', + availableUnits: 6, + wifi: true, + laundry: true + } + ]; + + getAllHousingLocations(): HousingLocation[] { + return this.housingLocationList; + } + + getHousingLocationById(id: number): HousingLocation | undefined { + return this.housingLocationList.find(housingLocation => housingLocation.id === id); + } +} diff --git a/aio/content/examples/first-app-lesson-09/src/app/housinglocation.ts b/aio/content/examples/first-app-lesson-09/src/app/housinglocation.ts new file mode 100644 index 00000000000..8303b6754eb --- /dev/null +++ b/aio/content/examples/first-app-lesson-09/src/app/housinglocation.ts @@ -0,0 +1,10 @@ +export interface HousingLocation { + id: number; + name: string; + city: string; + state: string; + photo: string; + availableUnits: number; + wifi: boolean; + laundry: boolean; +} diff --git a/aio/content/examples/first-app-lesson-09/src/assets/location-pin.svg b/aio/content/examples/first-app-lesson-09/src/assets/location-pin.svg new file mode 100644 index 00000000000..8a709d4b39c --- /dev/null +++ b/aio/content/examples/first-app-lesson-09/src/assets/location-pin.svg @@ -0,0 +1,4 @@ + + + + diff --git a/aio/content/examples/first-app-lesson-09/src/assets/logo.svg b/aio/content/examples/first-app-lesson-09/src/assets/logo.svg new file mode 100644 index 00000000000..6a4c13d5bac --- /dev/null +++ b/aio/content/examples/first-app-lesson-09/src/assets/logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/aio/content/examples/first-app-lesson-09/src/favicon.ico b/aio/content/examples/first-app-lesson-09/src/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..997406ad22c29aae95893fb3d666c30258a09537 GIT binary patch literal 948 zcmV;l155mgP)CBYU7IjCFmI-B}4sMJt3^s9NVg!P0 z6hDQy(L`XWMkB@zOLgN$4KYz;j0zZxq9KKdpZE#5@k0crP^5f9KO};h)ZDQ%ybhht z%t9#h|nu0K(bJ ztIkhEr!*UyrZWQ1k2+YkGqDi8Z<|mIN&$kzpKl{cNP=OQzXHz>vn+c)F)zO|Bou>E z2|-d_=qY#Y+yOu1a}XI?cU}%04)zz%anD(XZC{#~WreV!a$7k2Ug`?&CUEc0EtrkZ zL49MB)h!_K{H(*l_93D5tO0;BUnvYlo+;yss%n^&qjt6fZOa+}+FDO(~2>G z2dx@=JZ?DHP^;b7*Y1as5^uphBsh*s*z&MBd?e@I>-9kU>63PjP&^#5YTOb&x^6Cf z?674rmSHB5Fk!{Gv7rv!?qX#ei_L(XtwVqLX3L}$MI|kJ*w(rhx~tc&L&xP#?cQow zX_|gx$wMr3pRZIIr_;;O|8fAjd;1`nOeu5K(pCu7>^3E&D2OBBq?sYa(%S?GwG&_0-s%_v$L@R!5H_fc)lOb9ZoOO#p`Nn`KU z3LTTBtjwo`7(HA6 z7gmO$yTR!5L>Bsg!X8616{JUngg_@&85%>W=mChTR;x4`P=?PJ~oPuy5 zU-L`C@_!34D21{fD~Y8NVnR3t;aqZI3fIhmgmx}$oc-dKDC6Ap$Gy>a!`A*x2L1v0 WcZ@i?LyX}70000 + + + + Homes + + + + + + + + + + + diff --git a/aio/content/examples/first-app-lesson-09/src/main.ts b/aio/content/examples/first-app-lesson-09/src/main.ts new file mode 100644 index 00000000000..6aa14fb91c4 --- /dev/null +++ b/aio/content/examples/first-app-lesson-09/src/main.ts @@ -0,0 +1,10 @@ +/* +* Protractor support is deprecated in Angular. +* Protractor is used in this example for compatibility with Angular documentation tools. +*/ +import { bootstrapApplication,provideProtractorTestingSupport } from '@angular/platform-browser'; +import { AppComponent } from './app/app.component'; + +bootstrapApplication(AppComponent, + {providers: [provideProtractorTestingSupport()]}) + .catch(err => console.error(err)); diff --git a/aio/content/examples/first-app-lesson-09/src/styles.css b/aio/content/examples/first-app-lesson-09/src/styles.css new file mode 100644 index 00000000000..8ff9d490e35 --- /dev/null +++ b/aio/content/examples/first-app-lesson-09/src/styles.css @@ -0,0 +1,23 @@ +/* You can add global styles to this file, and also import other style files */ +* { + margin: 0; + padding: 0; +} + +body { + font-family: 'Be Vietnam Pro', sans-serif; +} +:root { + --primary-color: #605DC8; + --secondary-color: #8B89E6; + --accent-color: #e8e7fa; + --shadow-color: #E8E8E8; +} + +button.primary { + padding: 10px; + border: solid 1px var(--primary-color); + background: var(--primary-color); + color: white; + border-radius: 8px; +} diff --git a/aio/content/examples/first-app-lesson-09/stackblitz.json b/aio/content/examples/first-app-lesson-09/stackblitz.json new file mode 100644 index 00000000000..bf7fae0feb5 --- /dev/null +++ b/aio/content/examples/first-app-lesson-09/stackblitz.json @@ -0,0 +1,17 @@ +{ + "description": "Angular - First App - Lesson 09", + "files": [ + "!**/*.d.ts", + "!**/*.js", + "!**/*.[1,2].*" + ], + "tags": [ + [ + "first", + "angular", + "app", + "lesson", + "09" + ] + ] +}