Angular 17 Notes
Angular 17 Notes
-> Lazy-Loading( By default, NgModules are eagerly loaded. This means that as soon as the
application loads, so do all the NgModules, whether they are immediately necessary or not. For
large applications with lots of routes, consider lazy loading —a design pattern that loads
NgModules as needed. Lazy loading helps keep initial bundle sizes smaller, which in turn helps
decrease load times.,some of components loaded when the user need it )
Design Pattern — Decorator in Angular | by Bulicka Ola | Design Pattern — Decorator in Angular
| Medium
->ng g c componentName
property binding
*ngFor
===========Lec2
1-Binding
2- Directives
built in directives:
1-component directive (the tag used to display the component using component selector)
->use trackBy with ngFor: To reduce the number of calls your application makes to the
server by tracking changes to an item list. With the *ngFor trackBy property, Angular
can change and re-render only those items that have changed, rather than reloading the
entire list of items.
->note: we cant use multiple template binding on one element(this mean we cant use
two structural directives on the element)
-so use ng-container tag (this tag doesn’t appear )
->ngSwitch
3-Attribute directive
->NgClass (difference between NgClass and class binding that in NgClass we can applay
another class if the condition is false)
->NgStyle (at NgStyle we can use many properties but style binding use one property)
custom directives:
============Lec3
1-control flow
2- custom directives
Note: initially the background color will take the default color red not gray
In Angular, decorators are functions that allow you to modify the behavior of classes,
methods, properties, or parameters. They provide a way to add metadata or apply
transformations to code elements, making it easier to define and configure various
application elements. Decorators are extensively used in Angular to define
components, services, directives, pipes, modules, and more.
Lifecycle • Angular
-> there are four phases for the component(Creation, ChangeDetection, Rendering,
Destruction)
-> if they are related(parent component and child component) use input and output
decorators
->to send data from parent to child use input decorator , the parent send data to child in
the child selector
-> to send from child to parent use event: child is the publisher of the event and parent
is listener
-> to publish event first define event using EventEmitter(generic interface) and the
output decorator, then fire the event using emit function
->note: when use template reference variable we can use its tag at view(html) in
another tag ,but we can not use it in ts
->non null assertion operator (!): use it if we don’t want to give initial value for the
member
->now use @ViewChild("temp ref variable") decorator function to tell myInp variable
which tag it will have after the view is loaded
->we use ngAfterViewInit life cycle hock to use inside it the tag to insure that the
view has loaded and we get the tag (the component should implement AfterViewInit
interface), and we use nativeElement.value to change the value of the tag
->first use of @ViewChild is to get a tag from view into ts by using its template ref
variable
->Also we use it if the component has child component so we use ViewChild by using
child component name
->What is the deference between using ViewChild decorator to use variable from child
into parent , and using EventEmitter and @output decorator:
-when we use ViewChild if the variable inside child changed the parent will not feel
the change in the variable, but using event and output decorator make parent feel
the changes
2-Services:
->service is a class ,we use it if there is variables or methods that will be used in many
components
->services use singleton design pattern: this mean if many components make
instances from this service if one component make change in any variable so each
components will feel this change as they have the same instance
-so if there is any change in class A we will modify the object of B that has
instance of A as parameter , and we will not modify class B
-so we have injected object from class A inside constructor of class B
->providedIn: ‘root’ (this mean we can inject and use this service inside any component
in the project)
-as service use singleton design pattern so all components use this service will have
the same instance ,but if we want any component make its own instance of the
service we make providers array in the component decorator and pass to it the service
name
3-Routing:
-so when we want to make a path matches any path the user write instead Home,
Products or About paths we write path: ‘**’ and it navigate to notFound page
-if we write this path first one , if the user write Home, Products or About paths it will
navigate to notFound page not there pages because ** matches any path and the first
match wins
->router-link directive:
->nested routing:
->and then use router-outlet directive inside the component and import it
->redirectTo , path: ‘’ :this mean if the path is /About and there is nothing after About it
redirect to vision component and the path will be /About/Vision
->to go to another component from html we use routerLink, but from ts we use
service from router module (Router service) ,inject it in the constructor
->To get the id or a parameter from url we use ActivatedRoute service from router
module
->use ngOnInit life cycle hook to get the parameter inside it to be sure that the
component was loaded ,so we don’t use the constructor .
-then use snapshot object and paramMap key to use get method that return the
parameter (return as string so cast it to number)
-use (?) if the value may be null
=============>Lec5
->to go to the previous page or component use button and make click event on it
->then to make next and previous buttons to go to next and previous product
->so don’t use snapshot , but use paramMap property (this of type observable ) that use
observer design pattern and this make the component detect any change on the url , and
use subscripe() method that take a call back function
->Observer design pattern:
->use this pattern when there is changes in a class and want other classes detect the
changes of this class , so these classes should subscribe the class that has changes
-> the class has updates or changes called observable , other classes that should detect
changes called observer or subscriber
->observable vs promise:
-promise use .then() and .catch() or async and await , but observable use subscribe
-async logic code in promise implemented any way, but in observable implemented
when we subscribe it
->Reactivex library
->create observable:
- the constructor of the object take call back function which called when any component
subscribed this object(observable)
-there is 3 methods:
- next() :to make the observer detect the change or updates happed in the
observable
->want to send every 2sec element from notification array to the observer:
-but function should return the observable , it is generic and its type is the type
of array notification
->then make home component(subscriber) when loaded subscribe the observable in the
notification service:
-call subscribe method and handle on it the next , error and complete
->there is error : if the observable completed or there is an error the interval not
stopped(still called every 2second)
-so on the call back function of the observable we should return object which is
unsubscribe method and clear interval on it
->unsubscribe function called when it completed or there is error and if the
component want to unsubscribe (one of the difference between observable and
promise is the observable can unsubscribe)
-there is operators which create the observable like from and interval
-it acts as observable and observer(others can subscribe on it and it can subscribe on
other observables)
-BehaviorSubject: if there is a subscriber it will send the items for it, and if there is a
new subscriber it will send for it the last item sent to the previous subscriber then send
other items.
-PublishSubject: if there is new subscriber will send other items without last item in
previous subscriber
-we should save the token in the local storage when user login in using setItem(), and
remove the token when logout using removeItem() , getItem() to know if the user logged or not
->create 2 buttons:
->but now header will not change the links else if we refresh the page because
ngOnInit() doesn’t called again
1-Guards:
-CanMatch
-guard is a function of type CanActivateFn which imported from router module, this
function return boolean
-then put the guard on the rout that I want,on product route we use another property
called canActivate that take array of guards
->authGuard function return true if the user authantecated(logged in ), and false if unAuth
->so we want to inject userAuth service, but authGuard is a function not class:
-if the user isn’t logged , inject router service and use navigateByUr to go to login
component
2-use API ( json-server - npm)
->create folder (server), then from cmd (npm init) , npm i json-server
->then create file db.json and create array of products and categories
-> to use json file or API on the products service , should use http module
-> create getAllProducts method, that use get() method which take url that receive the
request
->getProductById method return observable of Iproduct , and take the id , so the path will be
products/${id}
-> getProductByCatId method return observable<Iproduct[]>, it take catId so the path should be
products?catId=${catId}
->create add-product component, make a button for it in the header and a path in the
routes, and create array of categories in ts file
->then use two-way binding to get the data from the form(html) and use it in ts file
->in ts file create member call newProduct to get the data from html on it
->in add-product ts file : inject apiProduct service to use addProduct method , and
subscribe on the method as it return observable
-in next : show alert for done (SweetAlert2 - a beautiful, responsive, customizable and
accessible (WAI-ARIA) replacement for JavaScript's popup boxes), then go to products
page so inject router service to use navigateByUrl
->then to make validation on the form :use template-driven form if the form is simple and make
the validation in html file , but reactive forms for dynamic forms if the user can change input in
runtime and handle validation in ts file
->use template-driven forms approach : Template-driven forms • Angular
->make submit button disabled if any input not valid, so put a reference on the
form with value ngForm, then on submit button use key invalid at the form
reference
->for Name input: required, apply regular expression using pattern attribute,
-then put reference with value ngModel on the name input,so if the input
invalid and touched show message error
-if theres many errors use key object called errors for each error and use (?) as
it may be null
==============>Lec7:
->in api-product service: we have getAllProducts which is get request, and used from
httpClient the get method which take url as first parameter,and it take options which is
an object and we can send headers on this object using key(headers) and its value is an
object from HttpHeaders
->in addProduct method which is post method as it use post method from httpClient,
post method take url and body, and also take options like get
-but we can use opthions object and use from it (key params) which is an object of
HttpParams, and send query string on it using set method
-if there is more than one query string , make variable of type HttpParms and append on
it query strings
2-interceptor:
->It is a layer between my application and the server, any request from app before
arrives to server it passes by the interceptor, and also the response
->in the interceptor we handle any logic we want to apply for all requests or responses
like send the authorization header with any request , and if we want to check on the
status of any response
->then go to app.config file ,in providers array which has providersHttpClient method ,
this method has withFetch() to use fetch api not ajax, and will take another function
called withInterceptors() which take array of all interceptors so we have to import the
function of interceptor,and this to make any request or response use this interceptor
->if we want to check if the request is POST we have to append another heade:
-so use req.method ,and we have to clone the request object as we cant change
the request so use clone() method
->to use any response we have to subscribe on next() method as it return observable by
using pipe() method , and use tap() operator on it to get the data in observable which is
the response
-tap take a call back function which called whith the next() or error() method of
the observable
->for single page application if the app has a lot of components if all of them loaded at
the beginning this Slows down the performance, but by using lazy loading we can make
some component not loaded at the begging
-use loadComponent key , its value is a function which calls import() method, and the
import take the ts file pass of product component
-import() returns promise, so use then() to get the response on it as obj which has
component name, so the product component will be loaded when the user use it
->note: we can make image or any thing lazy loaded not only all the component
->import reactive forms module, and handle the form in ts file not html because it used
for complex forms like when we get array of inputs from user or if the input should be
changed at runtime
->in the template driven forms the validation is html validation, but in reactive forms is
custom validation
->use any bootstrap form(take name , email and password from user)
->in template-driven forms we use two way binding to get the value of each input
-we want to create the form in ts file, so create member variable of type
FormGroup imported from forms module, and its value is an object of
FormGroup
->to connect the form created on ts file by the form in html file , on html form use a
directive [formGroup]=”form name in Ts file”
-and each input should have name attribute , and another attribute called
formControllName to connect this input by the name of the input in ts
->add another input to the form for address which is object of two values{city , street}
-in ts add another key called addres which is object of formGroup not
formControll,because it contains two other objects (city and street of type form
control)
-in html create input for city an street and connect them by ts by adding
formControlName attribute for them
-but we should put these two inputs in parent div or container , and this
container has formGroupName attribute
->to make validation for reactive forms:
-in ts file each FormControl() take first parameter the intial value for input, then
take array of validatorOrOptions
-in this array use validators object to applay validation like validators.required,
and use pattern() method for regular expretion
-then on the input in html write error messages , check the error using
userRegForm.get(‘controlFlowName’)?.errors.[validation]
->if we make a form for update any data like update product or user information ,the
old data should be in the inputs of the form and then modify it
-so we have to use ngOnInit() to make a get request when the component
loaded to get the user or product with id equal the id in url
-and the response will have the new data ,so use setValue() method to set the
new data (name:response.get(‘name’)), but by using this method we have to set
all values
->so we want to add another input in the form for phoneNumbers as array of numbers:
-in ts make a new key phoneNumbers which is object of type formArray which
take array of formControl
->in html:create input for phones a button + to add another phone number
-put the input in container or div with attribute formArrayName , and the input
take attribute formControlName
-make read only property for phones array ,the return as FormArray
-then use this phones property in the addNewPhone method to push on the
array of phones
-then in html to repeat the input we have to loop on the phones in the div of the
input, and make binding on formControl attribute to have the value of the index
in the array
->in ts instead using formControl and formGroup , we can inject formBuilder service
-change every formGroup and use fb.groub(), formArray by fb.array() ,and don’t
use formControl but make the values as array
===========>Lec8
->If the components are related(parent and child) we used @Input() and @Outout()
decorators, but if it isn’t related we used services
->it is a state management life cycle: -state is the changed data that I want it to be
shared
3-actions: if the component want to change the value in the store then dispatch
or fire an action
4-reducer:after the component fired the action, this action is passing by the
reducer which has the logic that we want to do to change the value
5-effects: it is a side effects after change the data in the store the the side
effects do some thing with this changed data like go to the api or save data in
local storage
->we want to make counter and make it shared between all components in the app
->in store folder create folder for counter, then make two ts files for actions and
reducers
->in actions file: call createAction() method that return the action to change the
counter, and its parameter is a string for the name of the action ,so any
component want to change the counter will dispatch this action ,(second thing
2-actions)
->in reducer file: write the logic to change the counter, call createReducer()
method, its first parameter is the initial state or value for the data (counter)
-then it take on() method to listean on the action, this method take the
name of the action , then take a call back function that take the
state(last changed value of the counter) and do the change on it like
increase or decrease this state,(then 3-reducer)
->then in app.config.ts , in provideStore() it take object of all thing I want to be
shared , so it take counterReducer, at begaining the key(counter)take the initial
value (initialState) from reducer file
-first inject store service to use methods to read values from store or despatch
any action, store service is generic and take object for type or values in the
store(Store<{counter:number}>)
-create member variable to get the data from store on it, its type is observale
and it is generic of type number because the type of counter in reducer is
number
-then call select() method that take the name of the kay we write it in
provideStore({counter:counterReducer}) which is counter, then it return an
observable to subscribe on this variable(counter) if any other component
change it, and save this value in another member( count) to use it in html
-instead using another member(count) and subscribe , we can use the observale
member(counter) in html , but we have to use a pipe (async)
->then make a button in home component to change the counter:
-then in ts file , we injected store service, so we want to use from it the dispatch()
method that take the action name
->each value in the store can have more than action, like counter we can make another action
on it like decreaseCounter,and add another on() method for it in the reducer
->make another value in the store for the language if it english make the direction of the page
from left to right, and if any ine change it to arabic so change the direction to be from right:
->in store folder create folder Language,and make two files for action and reducer
->in action: call createAction() ,it take the type(any name for the action),
-then it should take props method:this method generic that it takes an object for the
type of new value
->in reducer:create variable for initial state,then call createReducer that take the initial
state and on() method to listean on the action , that take action name and call back
function for the logic(to change language)
-call back funck take the state for the value and action to get the value from props
method on it
-> in app component in ts file: inject store service<> with type of language:string
->then in ts make member variable for direction with initial value(ltr:left to right), then
subscribe on the observable member to change the value of dir
-then in ts:create member variable (observable) to select the value using select
method,and another member to get the new value on it by subscribe on the observable
- from store service use dispatch(),that take action name and inside it send new value
for language that will be used in props method in creatAction
->note:ngrx is a state managent so if we change the values in the store and then make
refresh for the page the values will have the initial values not the last value,if we want
to save the change use DB
->or we can save the last value at local storage using Effects:
-in this file create a class for effect(it is a class not method like actions and
reducer), and use @injectable() decorator on the class
-this method take call back function and use on it the action service to call pipe
method (()=>this.actions.pipe())that will have any action dispatched and select
from them the action of language to make on it side effect to store it in local
storage
-to select the action use ofType(languageAction) operator that take action name
-second operator for pipe is tap method that take call back function which take
the action dispatched type((action)=>) and on this call back function we save the
value in local storage
-the last operator for creatEffect() is an object that has dispatch:false to stop
getting another dispatched actions
->then in reducer file make the initial value equal the value in local storage