- Create new project by Angular CLI
- Integrate Bootstrap
- Update main Template app.component.html
- Test: run project by Angular CLI
- Generate new Class
product.ts
- Declare attributes to match with JSON properties received from REST API
- Generate new Component by CLI (normally to contain set of Class entities) components/product-list
- Add new component selector to the main Template app.component.html
- Generate new Service by CLI (to provide functions calling API then map data to the Component)
product.service
- Inject HttpClient by constructor [from @angular/common/http] (to support HTTP methods)
- Import HttpClientModule [@angular/common/http] and new Service (to allow inject to other parts of the app) into app.module.ts
- Update Component to subcribe data from the Service
product-list.component.ts
- Inject the Service by constructor (to invoke methods of the Service)
- Update Template to display data [product-list-table.component.html][]
- Get sample templates including HTML and CSS files (work from front-end)
- Install Bootstrap CSS style locally by CLI:
npm install bootstrap
- Install Fontawesome (for icons):
npm install @fortawesome/fontawesome-free
- Verify installed entries in
node_modules
directory orpackage.json
- Inject CSS style entries globally by configurating
styles
in angular.json - Add CSS styles globally in src/style.css
- Restart app (if running) to make change with new configuration.
- Integrate sample templates to the app templates [app.component.html] [product-list-grid.component.html]
- Define routes in the app module
[app.module.ts]
- Use ** to for generic matching
- First match wins: start from most specific to generic
- Configure Route based on the defined routes in
imports
:RouteModule.forRoot(<routes_name>)
- Define Router Outlet (location of dynamic content) in app.component.html
- Setup Route Link in the Template (where links to different routes, e.g. menu) [product-categor-menu.html]
- Enhance Components in the routes to read param path (if there is)
[product-list.component.ts]
- Add param as new property of the class
- Inject
ActivatedRoute
(which loaded the Component) by the constructor (for accessing route params) - Create/Update methods to handle the route with params, which will delergate to Service methods
- Update Service methods to get the params and call the appropriate API based on the params [product.service.ts]
- Create new component for search [[search]]
- Add new route path for searching [app.module.ts]
- Update Search Component
[search.component.ts]
- Inject the router (from
@angular/router
) - Create a navigating method to navigate router to the search path
- Inject the router (from
- Update the Component and Service handling search method using API [list-product.component.ts] [product.service.ts]
- Update Search Template to call the navigating method of Search Component based on the events [search.component.html]
- Generate new Component for product details [product-detail]
- Add new route for product details [app.module.ts]
- Add route link to the template (where the link can be accessed) [product-list.grid.component.html]
- Update the product detail Component
[product-detail.componenet.ts]
- New attribute: product
- Inject Active Route (to get the id in the route path and the Service (to get the product by id)
- Create method in the Service to handle getting the product by id, using API [product-service]
- Update the Template to display product details [product-detail.component.html]
- Install ng-bootstrap by CLI
ng add @angular/localize
: dependency for Angular 9+npm install @ng-bootstrap/ng-bootstrap
- Import NgbModule from ng-bootstrap in app.module.ts
- Update the Service to get metadata regarding pagination provided by Spring Data REST API [product.service.ts]
- Update the Component to handle pagination [product-list.component.ts]
- Update the Template to use ng-bootstrap pagination component
[product-list-grid.component.html]
- Page list
<ngb-pagination>
- Event binding:
(pageChange)
- Use
[()]
for 2-way binding: change in Component leads to change in Template and vice versa - Use
[]
for 1-way binding: change in Component leads to change in Template [maxSize]
: shows a max number of page- Set
[boundaryLinks]
: alow jumping to the beginning/end of page list
- Event binding:
- Dropdown list
<select>
- Event binding:
(change)
- Event binding:
- Page list
- Generate new Component [components/cart-status]
- Add new component selector to the parent container template [app.component.html]
- Update the Template [cart-status.component.html]
- Create model class [common/cart-item]
- Create new Service for manage the cart [services/cart-service]
- Add click handler for "Add to cart"
[product-list-grid.component.html] [product-details.component.html]
- Event-binding for
<button>
:(click)
- Event-binding for
- Update the Component making use of the Cart Service
[product-list.component.ts] [product-details.component.ts]
- Inject the Service by the constructor
- Call the method of the Service the handle the click handler in the Template
- Update the Component related to the Service [cart-status.component.ts]
- Update the Template [cart-status.component.html]
- Generate new Component for cart details [components/cart-details]
- Add new route for cart details in
app.module.ts - Add route link to the template (where the link can be accessed) [cart-status.component.html]
- Update the cart details Component
[cart-details.componenet.ts]
- New attributes (which needed to display on the template)
- Inject cart Service (to get the cart)
- Update the Template to display cart details [cart-details.component.html]
- Generate new Component [components/checkout]
- Add new route to checkout form [app.module.ts]
- Create button with router link to the new route [cart-details.component.html]
- Add support for reactive forms in app.module.ts
- Define forms in the Component
[checkout.component.ts]
- Declare FormGroup property
- Inject Form Builder (to create form)
- Build groups of forms
- Layout the form in the Template [checkout.component.html]
- Add event handler for form submission with
(ngSubmit)
of<form>
[checkout.component.html] - Define method for event handler in the Component [checkout.component.ts]
- Create classes for data types [common/country] [common/state]
- Add methods in Service to populate data
[form.service.ts]
- Declare endpoints and inject HttpClient if need to invoke API to get data
- Update Component to retrieve data from Service
[checkout.component.ts]
- Declare attributes to match the retrieved data
- Subcribe to Service methods to match the data
- Update Template to populate drop-down list with the data [checkout.component.html] Dependency case: when a data type is dependent on other selected type (e.g. list of states dependent on the selected country)
- Add event-binding method for selection:
(change)
for<select>
[checkout.component.html] - Implement the event handler (method) for selection in the Component
[checkout.component.ts]
- Read the selected data, retrieve list of dependent data
- Update Template to populate drop-down list with the dependent data
- @Injectable used for Service: allow the service to be injected into other Classes/Components.
ngOnInit()
of Class is similar to @PostConstruct- Use prefix
+
to convert string to number - To view log, open Develop Tools/Inspect on the broswer (F12 for Chrome)
- Use Safe Navigator operator
?
to guard against null or undefined values in property paths - ActivatedRoute provides access to the url, params, data, queryParams, and fragment observables of the route associated with a component loaded in an outlet
- Race condition: the Template attemps to access undefined property. Solution:
- Initialize fields when declaring [product-detail.component.ts]
- Use Safe Navigator operator in the Template [product-detail.component.html]
- Use
ngIf
in the Template to check if the property is assigned yet
- Use
Subject.next()
to send events to the subscribers [cart-service.service.ts] - Use
Array.find()/findIndex()
to return the first element/id of element passing a given test, otherwise return undefined cart.service - [TypeScript] Use
===
for strict equality test (type and value) - Use
of
operator to wrap object as Observable [ExpirationService][] - [TypeScript] Use
Number(<variable>)
to convert variable into number - [TypeScript] Use
new Date()
to get current day/month/year - For entity create Class, for list of entities create Component