traceur by
Google and babel created by the JavaScript community. npm install -g typescriptgreetText which takes one argument
called name. The syntax name: string represents that the function expects name
to be a string. Our code will not compile if we call this function with anything other than a
string. greetText also has a syntax after the parentheses : string { //code }. The
colon specifies that we will specify a return type for this function - which in this case is a
string. You you try returning a number instead, it will throw an error.
class, we do this:
constructors. new keyword. Use new Person() to create
a new instance of the Person class, for example.
Properties
:Methods
:any type). Note that a void value is also a valid any
value. Constructors
:constructor. They can optionally take parameters but
they can't return any values, since they are called when the class is being instantiated (i.e. an
instance of the class is being created, no other value can be returned). Inheritance
:extends keyword. => functions are a shorthand notation for writing functions. npm install -g @angular/cli
To see the full list of features, you can run ng help to output the current help
documentation.
export keyword. Modules export values that they
want to expose to the application and can keep other parts of the internal logic private. Then, in order
to use an exported value, you have to first import it from another module. Executing an Angular
application is fundamentally loading a module that contains the application bootstrapping logic, which
in turn starts to load and trigger additional modules.
ng new stocks cd stocks ng serve http://localhost:4200 to see the landing page. | Asset | Role |
|---|---|
| e2e | End-to-end testing folder, contains a basic stub test |
| node_modules | Standard NPM modules directory, no code should be placed here |
| src | Source directory for the application. All your application code goes here. |
| .editorconfig | Editor configuration defaults |
| .angular-cli.json | Configuration file for the angular-cli. angular-cli.json file has been
renamed/replaced with angular.json in version 6 of Angular. SO Link
|
| karma.conf.js | Karma configuration file for unit test runner. Unit tests are run using karma. |
| package.json | Standard NPM package manifest file. Difference between "^1.4.0"
and "~2.0.1" version numbers.
|
| package-lock.json | It stores an exact, versioned dependency tree rather than using starred versioning like package.json itself (e.g. 1.0.*). This means you can guarantee the dependencies for other developers or prod releases, etc. |
| protractor.conf.js | Protractor configuration file for e2e test runner. This is now under the e2e folder. End-to-end testing is done using protractor. |
| README.md | Standard readme file, contains starter information |
| tsconfig.app.json | TypeScript compiler configuration for apps |
| tsconfig.json | Default configuration file for TypeScript compiler |
| tsconfig.spec.json | TypeScript compiler configuration for unit tests |
| tslint.json | TSLint configuration file for TypeScript linting rules |
| Asset | Role |
|---|---|
| app | Contains the primary App component and module |
| assets | Empty directory to store static assets like images |
| environments | Environment configurations to allow you to build for different targets, like dev or production |
| favicon.ico | Image displayed as browser favorite icon |
| index.html | Root HTML file for the application |
| main.ts | Entry point for the web application code |
| polyfills.ts | Imports some common polyfills required to run Angular properly on some browsers. What are polyfills |
| styles.css | Global stylesheet |
| test.ts | Unit test entry point, not part of application |
src/app/app.component.ts in the project. @Component annotation declares that this class is a component by accepting an
object. selector property that declares the HTML selector of the component.
That means the component is used in the template by adding an HTML tag
<app-root></app-root>. Know that with this selector we're defining a new
HTML tag that we can use in our markup. The selector here indicates which DOM
element this component is going to use. In this case, any <app-root></app-root>
tags that appear within a template will be compiled using the AppComponent class and get any
attached functionality. templateUrl property declares a link to a template containing an HTML template. styleUrls property contains an array of links to any CSS files that
should be loaded for this component. title. The
value is what you should see rendered in the browser, so this is the source of the value
that ultimately appears.
src/app/app.component.html in the project. {{title}} with the value of the title property from the component.
This is called interpolation and is frequently used to display data in a template.
src/app/app.module.ts AppModule, and NgModule is the decorator. NgModule decorator takes an object with a few different properties. declarations property is to provide a list of any components and directives to make
available
to the entire application. imports property is an array of other modules upon which this module depends - in this
case, the BrowserModule
(a collection of required capabilities). If you ever include other modules, such as third-party modules or
ones you've created, they also need to be listed here. providers property, is empty by default. Any services that are created are to be listed
here.
providers is used for dependency injection. So to make a service available to be
injected throughout our application, we will add it here.bootstrap property defines which components to bootstrap at runtime. Typically, this will
be the same App component, and the CLI already set it up for us. AppModule: The body of the class is indeed empty. But that decorator
above the class (@NgModule) is giving that class its functionality. So really, that class isn't
empty. It just doesn't require any extra logic after the decorator is applied to it.
bootstrapModule takes a class as input and assumes that that class is decorated with @NgModule
import to import a class at the top of the file vs using
imports to add a module: You put something in your NgModule 's imports if you're
going to be using it in your templates or with dependency injection.
angular.json file. One of the properties is the main property. By
default, it points to the src/app/main.ts file. main.ts file as the first set of instructions. src/app/main.ts
platformBrowserDynamic object is used to tell Angular which module is being loading, and
in this case that's the AppModule. It is important to understand that this is the point where
the code begins to execute. platformBrowserDynamic. Your Angular application can start off in many ways,
but when you run on the browser you have a specific way of bootstrapping the application and that is defined
in @angular/platform-browser-dynamic. In short these packages contain angular features which
make getting an Angular app up and running possible in the browser. Bootstrapping is essential and one of
those features.src/index.html file:
app-root element and replace it with the rendered component. main.ts. main.ts
bootstraps the AppModule. The control passes to the app.module.ts where it sees
the field bootstrap and figures out which component to use as the first in order to bootstrap
the application. Control then goes to the app.component.ts class where it sees the templateUrl
that it has to serve along with the selector app-root.
$rootScope
to also communicate between controllers, but it should be avoided as much as possible since it is a global
scope. ng generate service services/stocks.
The CLI will generate the files in the src/app/services directory. StockInterface interface is defined and exported for other components to use. This
provides a TypeScript definition of what a stock object should contain, which is used by TypeScript to
ensure the use of the data remains consistent. StocksService class is exported and is decorated by the Injectable
decorator. The @Injectable() decorator marks it as a service that can be injected. The
decorator
is used to set up the proper wiring for Angular to know how to use it elsewhere, so
if you forget to include the decorator, the class might not be injectable into your application. HttpClient service is injected using the TypeScript
technique of declaring a private variable called http and then giving it a type of HttpClient.
load() method makes a call to the HttpClient service to load the data for
current stock price values. The HttpClient service is called and returns an observable, which
is a construct for handling asynchronous events, such as data from an API call. this.http.get<Array<StockInterface>> is the type variable. This is a
feature of TypeScript that tells it what kind of object it should expect. In this case it will expect
to get an array of objects that conform to the StockInterface. src/app/app.module.ts file
stocks.service.ts file
above: constructor(private http: HttpClient){ }. Because we declare the type as
HttpClient (which is a known service in Angular), the application will use the injector
to ensure that the http property contains an instance of the HttpClient service.
HttpClient), it calls a factory function from the provider and returns the requested object.
NgModule's providers array is
available
to be injected in your application code (hence we add StocksService above in app.module_v2.ts
to the providers array).
@Injectable decorator ng generate component components/summary
src/app/components/summary directory. [ngClass]="{increase:isPositive(), decrease: isNegative()} is a special kind of
attribute known as a Directive. Directives allow you to modify the behavior and display of DOM
elements in a template. NgClass directive, for example, allows you to change the list of
classes that are attached.NgClass directive is able to add or remove CSS classes to and from the element. It's
assigned a value, which is an object that contains properties that are the CSS class names (if you go into
summary.component.css you will see that there are CSS classes with names "increase" and "decrease"), and
those properties map to a method on the controller (to be written). If the method returns true, it will add
the class; if false, it
will be removed. In this snippet, the card will get the increase CSS class when it's positive,
or the decrease CSS class when it's negative.
{{stock?.symbol?.toUpperCase()}}. The double curly braces syntax is the way to
display some value in the page (interpolation). The content between the braces is called an Angular
expression and is evaluated against the controller (like the directive), meaning that it will try to
find a property on the controller to display. If it fails, normally it will throw an error, but the safe
navigation operator ?. will silently fail and not display anything if the property is missing.
{{stock?.lastTradePriceOnly | currency:'USD':'symbol':'.2'}} shows another feature of Angular
called pipes, which are added directly into the expression to format the output. The interpolation
expression is extended with a pipe symbol, | , and then a pipe is named and optionally
configured with values separated with the colon : symbol. Pipes only modify the data before
it is displayed, and do not change the value in the controller. The double curly braces indicate that you
want to bind the data stored in the stock.lastTradePriceOnly property to display it. The data
is piped through the Currency pipe, which converts the value into a financial figure based on a USD figure,
and rounds to two decimal points.
{{stock?.change | currency:'USD':'symbol':'.2'}} ({{stock?.changeInPercent | percent:'.2'}})
has two different interpolation bindings with a currency or a Percentage pipe. The first will convert to the
same currency format, but the second will take a percentage as a decimal, such as 0.06, and turn it into 6%.
Note that the round brackets in the second interpolation are not the part of any syntax, they are just there
because the UI needs that value to be in round brackets.
summary.component.html template needs a controller to wire up the data and the methods.
Make the following changes to the src/app/components/summary/summary.component.ts file. ngOnInit if we already have a constructor?
stock, which is preceded
with the Input annotation. This indicates that this property is to be provided to the
component by a parent component passing it to the summary. Properties are bound to
an element using an attribute, as you can see here - this (hypothetical) example will set the value of
stockData of the parent component in the stock property of the Summary component:<summary [stock]="stockData"></summary> stock @Input property for the Summary component to consume. @Input decorator.
src/app/components/summary/summary.component.css file. :host selector is used because we want components to be as self-contained as possible.
This relies on the Shadow DOM concepts discussed earlier. When Angular renders this component,
it will modify the output to ensure that the CSS selector is unique and doesn't accidentally interfere with
other elements on the page. src/app/app.module.ts file and you'll see that the CLI already modified
the module to include the Summary component in the App module. src/app/app.component.ts file. src/app/app.component.html file to use the Summary Component. *ngIf="stocks", which is a directive that will only render the contents
inside the element when the expression is true. In this case, it won't render the Summary component until
the stock data has been loaded. ng generate component components/dashboard. This will output new
files into the src/app/components/dashboard directory for the HTML, CSS, controller, and unit test. It also
adds the component to the App module (app.module.ts) to be immediately consumable. src/app/components/dashboard/dashboard.component.ts
DashboardComponent class is the component controller, and it declares that it
must implement the requirements of OnInit. If it doesn't, TypeScript will fail to compile the
code and throw an error. It then has two properties: an array of stocks and an
array of strings that represent the stock symbols to display. Initially they're empty arrays,
so we'll need to get them loaded for the component to render. constructor method runs as soon as the component is created. It will import
the Stocks service onto the service property and then request the current list of stock
symbols from it. This works because this is a synchronous action that loads a value directly from memory.
ngOnInit lifecycle hook to call the service to load the stock
data. It uses the list of stock symbols that was loaded in the constructor. We then subscribe
to wait for the results to return and store them in the stocks property. This uses the observable approach
to handling asynchronous requests. We are using observables because the HttpClient returns an
observable for us to receive the response. This is exposed as a stream of data, even though it is
a single event.
src/app/components/dashboard/dashboard.component.html file.
* NgFor will then create an instance of the Summary component for each of the stock
items. It binds the stock data into the component. Each copy of the Summary component is distinct from the
others, and they don't directly share data.
selector of the child component[nameOfDataFieldUsedInChildComponent]="nameOfDataFieldUsedInParentComponent". Remember to
annotate the nameOfDataFieldUsedInChildComponent in the child component with @Input
controls, which are the
various types of inputs and fields the form may contain (such as a text input, a checkbox, or some custom
lement). ng generate component components/manage. Now update the
src/app/app.component.html so that it is the app-manage component that is beign
served. FormsModule to our application, because we are going to use
the form features that aren't automatically included by Angular. Open up the
src/app/app.module.ts file and add a new import:
import { FormsModule } from '@angular/forms'; src/app/components/manage/manage.component.ts and add the following: OnInit lifecycle hook, because it's a synchronous
request to get data that exists in memory.
(submit)="add()" attribute is a way to add an event listener, known
as an event binding. When the form is submitted (which is done by pressing Enter), it
will call the add method. Any attribute that's surrounded by parentheses is an event
binding, and the name of the event should match the event without the on
(onsubmit
is submit). [(ngModel)]="stock" attribute is a two-way binding that will sync the value of the
input and the value of the property in the controller anytime it changes from either
location. This way, as the user types into the text field, the value will be immediately
available for the controller to consume. When the user hits Enter, the submit event
fires and will use the value of the stock property when adding the new symbol. symbol, it will create
a local variable called symbol, create a new table row that binds the value, and a button
that's for removing the item. remove button contains another event binding, this one to handle the click
event. The (click)="remove(symbol)" attribute adds an event listener to the click
event and will call the remove method in the controller, passing along the symbol.
Because there are multiple instances of the button, each one passes along the local variable to know which
symbol to remove.
src/app/app.routes.ts RouterModule is used to activate the router and accepts the routes configuration when
it's initialized. We also import the two routable components, the Dashboard and Manage components, so we
can reference them properly in our routes configuration. AppRoutes, which is assigned to the result of
RouterModule.forRoot(routes). It's a way to pass configuration to the module. In this case,
we're passing the array of routes. We export this so we can import it into our App module and register it.
src/app/app.module.ts:
src/app/app.component.html file, make the following changes:
@Input Decorator @Output - Custom Events and Event Emitters npm install -g npm. The -g flag means that it will be installed globally (gives the ability to run commands on the CLI from
anywhere). Check the version installed by running npm -v or node -v npm install -g @angular/cli ng will show the available commands that you can run. Had to run this in admin version of Command Prompt. The idea here is that Angular is not just a web
framework, but rather an entire ecosystem of tools that help you to build web frameworks. ng commands: "ng.ps1 cannot be loaded because running scripts is disabled on this system", run the following
command in the Command Prompt while logged in as the Admin: powershell Set-ExecutionPolicy RemoteSigned. Source. ng new nameOfTheProject in order to create a new directory and a new Angular app. The directory created will have name as nameOfTheProject.
(Angular Routing: No, Stylesheet: CSS) npm start. This will deploy the application on the port 4200 and can be accessed here: http://localhost:4200/ app-root tag below is not a standard browser element, we have
created it. We have constructed it using a construct that is known as a Component. A Component allows us to link some style (styleUrls) and html
(templateUrl), with some typescript logic (interpolation operator: {{ }}). Anything within {{ }} is evaluated as a JS expression within
the context of the component. @Component is a decorator that identifies the class as an Angular component. app-root). This allows us to extend the browser functionality with our own
functionality. @Component associated with the html, and the html can access values in the
component using {{ }}.
app.component.css file defines css rules that are going to be visible only inside the app.component.html page. <input [value]="data.courseTitle"> is useful when you want to pass in some data to the template that is available at
the component class. <img (click)="onRocketImageClick()" src="./rocketImage">. Here, (click) specifies the type of event that we are listening for on the
img element. The function onRocketImageClick() will have to be added to the component of this html. # . Like so: <input [value]="expression" #titleInputBox>. This is called a "Template Reference". We can now use this reference titleInputBox to refer to the
input element in other parts of the template. The reference can also be injected into the component associated with the html as well. input box and updating it to reflect on the page using <span>{{ data.courseTitle }} app is running!</span>. What if an attacker tries to
input some text that is wrapped inside a <script></script> tag? Angular sees that you are using the value input into the input textbox as a plain
string in your template, and hence will automatically escape any html/script tag that it finds. C:\MY_BACKUP\LearningStuff\Angular8\DeepDiveTutorials\from-github_angular-course npm install and npm start.
ng generate component component-name is the command that we can use for generating our own custom component using the CLI. This will generate the
following four files: @Component decorator means that we can use the selector used in that component to create custom html elements of our own.
@Input Decorator[]="" and @Input() syntax. @Input decorator. The idea here is to define
certain variables, annotated with @Input() on the course-card component, which will be read by the template associated with the component. The parent
component (in this case, the app.component), will pass the required data to the course-card component through the input property syntax that we saw in Chapter 4
above.
@Input() to the course-card component. Alternatively, we can pass in the entire Course object.
@Output - Custom Events and Event Emittersbutton input on the course-card template. Then we add a click handler to the button by using the (click)="" syntax.
EventEmitter class from Angular Core. Refer
the below setup to see how to do this. Note that there is a difference in the way that Angular treats native browser events and custom events. Native events, like the click
event that we saw above, are automatically bubbled to the parent components. But that is not the case with custom events. Custom events do not automatically bubble to their
parent components. (courseSelected)="handleCourseSelectedEvent($event)"
to the first app-course-card, handleCourseSelectedEvent would be called as well.
ngFor Core Directive (also conditionally add styles to HTML elements)*ngFor is a structural directive. A structural directive allows us to change the structure of a page
based on a javascript expression. *ngFor also gives you some auxiliary features such as index, first, last, even, odd. index as i allows us to access the index of the item currently iterating and assign it the name i. first tells us if the element currently in
iteration is the first element of the collection or not. Same for last as well. even and odd tell us whether the elements are the even or
odd numbered iterations respectively.
ngIf Directive and the Elvis Operator ? ngIf is a directive used for showing/hiding certain parts of the page from the user. ngIf is *ngIf="expression". If the expression evaluates to true, then the element on which
the ngIf is being applied will still be present on the screen. If the expression evaluates to false, the element gets hidden. If you "Inspect" the webpage
at this point, you will see that the element has been completely removed from the DOM. It is not just hidden with CSS. false, else it would be evaluated to true. You could also add a function call here that would be resolved at
the level of the component.
? that allows us to check whether the object is null or not. Consider the below example where the first item
in the courses array is undefined. This would create a NPE when we try to access course.description or course.iconUrl in the
course-card.component. We can prevent this by doing course?.iconUrl and course?.description. Instead of having to use suffix every usage of course
with ?, we can instead conditionally show the card depending on whether the course is null or not.
*ngIf is the else clause. We saw above how to hide the image when the iconUrl was null. Let's say that
instead of just hiding the element, we wanted to present some text to the user like "No Image Available". We do this by adding an else clause. The
else block requires a reference to a template block that is going to contain the message. The template block is created using ng-template and we
pass it to the else clause by using the template reference # syntax that we have seen before. This is an example of how we do that:
ngClass Core DirectivengClass directive is used to conditionally add CSS classes to the template. class list by using ngClass directive. ngClass="expression" directive allows us to pass an argument that turns on or off certain CSS classes. The expression can take multiple
kinds of arguments. We can pass it a string, an array, or a configuration object.
ngStyle Core DirectivengStyle directive. ngClass or ngStyle to pass in constant styles to the template. These should
be used only in cases where the styles themselves are dependent on the data that is coming into the component. For instance, a good usage would be if we wanted to set the
background image of the cards to the course image that was being returned from the server. In that case we could use the ngStyle to set the background image
using the background-image: url(course.iconUrl).
ngSwitch Core DirectivengIf directive. So it offers us just two options. Sometimes, we want more. ngSwitch="expression" directive is the expression that we want to switch on, which in this case is going to be
course.category. We use ngSwitchDefault to handle the default case.
ng-container Core Directiveng-container docs. ngIf, ngSwitch), we had clear parent elements onto which we could apply these directives.
This is not always the case. We might find ourselves in a situation where we do not have a single parent component onto which we can apply the directive (?). div just for being able to apply the directive, use ng-container instead, because it will not create extra DOM elements. Refer Chapter 24 for an example.
slice pipe for example allows us to slice arrays similar to how we would do it with the JS
slice method. In the below example, we are slicing courses array such that we will take the elements from index 0 (inclusive) to 3 (exclusive). Hence,
irrespective of the number of elements in the courses array, our list will contain only 3 elements. Also note that here we are passing in multiple args to the pipe by
separating them with the : operator.
json pipe which will print the entire json object to the page. Another helpful pipe is the keyvalue pipe that
prints an object as key, value pairs.
@ViewChild Decorator - How Does it Work?@ViewChild docs. ng-template, giving it a template reference, and then accessing that element through that
reference. But sometimes our component (.ts file) needs a reference to the HTML elements defined in the template. For this, we make use of the @ViewChild and
@ViewChildren decorators. @ViewChild() decorator, we need to specify how we want to fetch the element. There are multiple ways to do this that you can see in
the doc link above. In the below example we are using the component type. @ViewChild(CourseCardComponent) query. Had there been multiple such
elements, then the @ViewChild selector would have returned only the very first element that it found.
@ViewChild - Learn the multiple View Query Configuration Options@ViewChild, we can also query based on a template reference. This is useful in the case when we have multiple components of the same type.
@ViewChild to inject components. But we can also use this to inject plain HTML elements. ElementRef type from Angular Core allows us to handle plain native HTML elements. Notice in the below example that when we logged the component, the type
printed in the console was the component type, i.e. CourseCardComponent. But when we logged the native HTML element, we get the ElementRef type logged
instead. The ElementRef object contains a property called nativeElement which corresponds to the div.courses element. If you hover over it, the
div on the html page will get highlighted. Hence, the @ViewChild decorator will give you different behavior depending on whether you are using to query plain DOM
elements, or if you are querying a component.
@ViewChild() like @ViewChild('cardOneRef', {read: ElementRef}). As we can see in the below example, we are now
getting the app-course-card for the second card printed on the console.
@ViewChild?@ViewChild annotation populated?
@ViewChild decorator are already filled in? AfterViewInit. This will force us to implement the ngAfterViewInit() method. And it is in
this method where we can earliest access the references populated by the @ViewChild decorator. It is the Angular framework itself that calls this method after the
references are filled in. Hence, ngAfterViewInit is the place to put some initialization logic that needs access to the @ViewChild elements.
ngAfterViewInit. This will throw a ExpressionChangedAfterItHasBeenCheckedError. Read about the error
here on the Angular Site. Also has a video lesson about why this error is caused, and how to fix it.
ExpressionChangedAfterItHasBeenCheckedError when an expression value has been changed after change
detection has completed. Angular only throws this error in development mode. The goal of Change Detection is to keep your model (ts code) in sync with the template (your HTML).
It does this by looking for data changes in the component tree from top to bottom. The below image is a simplified breakdown of the steps that Angular performs when the
component is first initialized. Note that the ngAfterViewInit runs after Change Detection. Any code that runs here should not attempt to update the view.
@ViewChild annotations, we can query anything at the level of the component
itself. You cannot query elements that are either in the parent component, or elements that are in the children component either. What this means is that, note in the above
images that the app.component.html makes use of the app-course-card. The course-card.component makes use of the img tag. If you added a template
reference to that img, and tried to fetch that image in the app.component.ts, you would get undefined. @ViewChild queries are restricted to the template that is associated with the component in which the decorator is being used.
@ViewChildren Decorator and QueryList In Detail@ViewChildren is similar to @ViewChild, but the difference being that instead of querying for just one single element, the
@ViewChildren allows us to query for a collection of elements. *ngFor loop. Suppose that we want to get a
reference of all the app-course-card that are created. We can do that by using the @ViewChildren decorator. QueryList<CourseCardComponent>, and not something like a list of CourseCardComponent
as one might expect. Also, just like with @ViewChild, we can specify what type of elements we want to extract. So instead of obtaining references to each of the
CourseCardComponent, we would like to get a reference to the DOM element of each component. Observable to subscribe to the changes in cards. The Observable will emit multiple values as the collection changes
over time.
ng-content In Detail@Input, we can pass in entire custom HTML as input to child elements as well. ng-content tag. The content inside the course-card tag is being projected into the template using ng-content. Any
content that we have between the opening and the closing course-card tag is going to get projected into the template using ng-content. ng-content is going to show any content that is between the opening and closing tags of the component.
ng-content tag. In that case we can use the select
property of the ng-content tag. There are different ways in which we can restrict the content that will be projected in the ng-content tag. We can
restrict using the element tag or using the class on the element. Below image shows how.
ng-content tag in order to catch any elements that would be left over after using the select property. In the below example,
the "Edit Description:" does not have a CSS selector that is used in either of the ng-content's select property. In this case, it is the third
ng-content that enables us to project all the remaining stuff.
@ContentChild Decorator@ViewChild and @ViewChildren decorators to query the template of a given component so that the
component class can have a direct reference to some elements in its own template. The scope of this query was restricted to the template of the component and nothing else.
ng-content. One idea could be to add template reference to the element that we
are interested in, in the app.component.html as below. But as you can see, it prints undefined and does not work. This is expected behavior, since although the
@ViewChild can see within the template, it cannot see within the projected ng-content
@ContentChild. This works similar to how @ViewChild works,
except that it can see only within ng-content. You cannot query other elements that are defined in the template with it. The below image shows the scope of
the @ContentChild. As you can see, you can query elements from the parent element using @ContentChild, but only those elements that are defined
within the opening and closing braces of the course-card component.
@ViewChild query, the @ContentChild decorator can also be used to query components inside the content of the component.
In the above examples, all the content within <course-card>...<course-card/> were native DOM elements. But we can also have components within the
course-card component, as we are having in the below example. We have taken the img and extracted it to a component of its own. So what we have managed to
do is to project a component inside another component. Hence, we also ended up changing the way we were querying the element using the @ContentChild decorator as
well. In the below example, the decorator is going to return an instance of CourseImageComponent. But optionally, we can pass in
@ContentChild(CourseImageComponent, {read: ElementRef}) in order to get a reference to the underlying element itself (just like we did with @ViewChild).
@ContentChildren and the AfterContentInit Lifecycle Hook@ViewChildren, @ContentChildren allows us to query multiple elements. ngAfterViewInit() to get the content. But this is not the earliest point at which Angular has populated these references for us.
We can have the class implements AfterContentInit which will force us to override the ngAfterContentInit() method. This method is the
earliest point at which the references have already been populated for us. You can see this in the console log prints below. The ngAfterContentInit() is called
before the ngAfterViewInit() and already has all valid references. @ViewChildren is QueryList<CourseImageComponent>.
ng-content tag in order to see the elements of the parent component. In the below
example, we have removed the ng-content from the course-card template, and we are still able to query the elements. Ofcourse, doing this also means that the
images will no longer show in the page either. But you can still programmatically access them is what I am saying.
ng-templateng-template on how to show alternate element in case an image is not provided. ng-template is that the HTML associated with the template is included in the DOM only if the template reference that is being used to
refer to the ng-template is actually being used somewhere in the page. Else, the associated HTML is not included (like how elements that use the *ngIf
directive are not included in the DOM if the expression evaluates to false). Refer lecture if this is not clear. ng-template.
ngTemplateOutletng-template that are defined within the template. In addition to that, we can also give to the ng-template its own private
variable context that is going to be visible only inside the ng-template itself. ng-template in your HTML does not instantiate it? In the below example, the #blankImage
ref is not being used anywhere. Hence, we need to manually instantiate it in order for it to show up in the DOM. We do this using the ngTemplateOutlet structural
directive. let-courseName and let-courseNumber below are how we declare variables. These variables will be visible only within the ng-template.
ng-template makes use of two variables: courseName and courseNumber. Hence, when we instantiate the template using
ngTemplateOutlet, we will have to pass in concrete values for these variables. This is done by using a context{} object. let-courseName="description" is how we assign a value to the courseName variable. The point to note here is that the expression will be evaluated
using the context value that has been passed in. So only the variables defined within the context object will be in scope here. ng-template twice, each time with custom context data to show that it is truly parameterized.
div element just so we could use *ngTemplateOutlet directive on it. Instead of using the div, we
could just use the ng-container and avoid introducing another div as per Chapter14.
@Input of type TemplateRef<any> in the
course-card component. The template itself is defined in the parent component. It is then passed as an @Input to the child component, where it is
instantiated using the ngTemplateOutlet and conditionally shown.
*ngIf, *ngFor, *ngSwitch, etc. Structural
directives are attributes that are added to an element. Structural directives are directives which change the DOM layout by adding and removing DOM elements. Structural
directives normally begin with a *. required, disabled, changes the appearance of the element.
ng generate directive folderName/directiveName. A sample example is
ng generate directive directives/appHighlighted. This will create a directive called appHighlighted in the directives folder.
@HostBinding in Detail - DOM Properties vs Attributes$0. Now you can refer to this element using $0. Go to console, and type in $0.className. This will print out the css classes that are
currently assigned to this element. The list would be empty right now. Now when you do $0.className='highlighted', it will assign the highlighted css class
that you have defined in your styles file to this element. It doesn't work with the highlighted class for some reason. warn is another class that is defined in
the same css file, and that works.
@HostBinding Decorator. The @HostBinding
decorator allows us to modify DOM properties of the element onto which it is applied. The @HostBinding can be used to bind to any DOM property of the host
element.
class.className that we can
use to do it.
Similarly, we can also use a shorthand for adding styles as style.styleName
[appHighlighted]. The square brackets around its name specifies that it's an input property, but so
far we have not been passing in any expression into it. Let's change that.
[disabled]="true" disables the button, and doing
[disabled]="false" enables it.
[attr.disabled]="false", the button still stays disabled, because the value of the attribute does not matter.
@HostBinding to set DOM properties. But we can also use it to set HTML attributes. We are changing the attr.disabled
attribute below.
@HostListener - Handling Events in Directives@HostListener decorator. @HostListener('args') takes as args the DOM event that we want to detect. We can also pass-in as args the native event that emitted by doing
@HostListener('mouseover', ['$event'])
exportAs syntax - When to Use it and WhyexportAs syntax to export the directive.
*ngIf are plain angular attribute directives that have the special ability of instantiating the ng-template
onto which they are applied.
ng-template in the component by using TemplateRef,
ViewContainerRef, and then calling createEmbeddedView on the instance of ViewContainerRef and passing in the instance of
TemplateRef.
styleUrls: ['./course-image.component.css']. The styles that are specified in this class will only be visible for the template associated with the
component. They won't be visible for other components. _nghost and _ngcontent.
:host Selector<app-course-card></app-course-card> itself.
:host selector. Note in the below example that the styles are now being applied to the component using a different
attribute selector that uses _nghost. Note that this attribute is different from the _ngcontent attribute that was being applied on the element and its children.
The child elements of the app-course-card do not have this attribute applied to them. Every component will have its own _nghost attribute. The point to note is
that even if there were multiple app-course-card components on the page, they would all use the same _nghost attribute.
::ng-deep modifier::ng-deep to our style, the part of the CSS selector
after ng-deep is no longer going to be made specific to a particular component. The part before the ng-deep selector is still going to
be made specific to that component by applying the special _ngcontent-c* attributes.
host-context Selector - Theming Use Case.yellowTheme selector in the course-card.component.css file, the style was made specific to the elements of the course-card component.
ng-deep selector before the selector. But then the problem is that that would remove the component
specific selector from both the styles, inherently making it the same as adding the style to the global style sheet.
host-context CSS modifier. The :host-context() selector looks for a CSS class in any ancestor of the component host
element, up to the document root. For instance, in the following example, italicizes all text inside a component, but only if some ancestor element of the host element
has the CSS class active. Link to Angular Docs.
@Component() annotation that is present on the ts file, you can pass in an args encapsulation: ... like here. The default value for this is ViewEncapsulation.Emulated. ng run server command. First error was '.' is not recognized as an internal or external command,
and second error was SyntaxError: missing ) after argument list/ unterminated `s' command. These were fixed by replacing the server
definition in the package.json file with "server": "node ./node_modules/ts-node/dist/bin.js -P ./server.tsconfig.json ./server.ts" as mentioned here. localhost:9000/api/courses is the path to access on the browser. HttpClient that we are going to use to fetch data from the backend. HttpClient, we can simply inject it into our constructor. The ngOnInit method is where we should be adding the GET calls.
async Pipe - a Better way of passing Observable data to the ViewObservable that emits the requested data when the response is received. In the above example,
we were manually calling subscribe on the Observable. Note that calling subscribe() is what triggers execution of the observable and
causes HttpClient to compose and send the HTTP request to the server. Each subscribe() initiates a separate, independent execution of the observable. Subscribing
twice results in two HTTP requests. You should always unsubscribe from an observable when a component is
destroyed.async pipe allows us to implicitly subscribe to this observable from the template. This allows us to write reactive components. It also has the additional
advantage that whenever the component is destroyed, the aysnc pipe takes care of unsubscribing us from the Observable which prevents memory leaks.
@Injectable Decoratorng generate service services/courses where services is the name of the folder in which we want the files to be
generated, and courses is the name that we want to assign to the service. The generated service looks something like this. The
@Injectable({providedIn: 'root'}) annotation means that this service can now be injected into the constructor of any class that we want, similar to how we were
injecting the HttpClient in the above examples. The providedIn: 'root' means that there should always be a single instance of the
CoursesService object available for injection (CoursesService should be a Singleton).
Observable<Course[]>.
{...this.course} and then in this new object change the description property by doing {...this.course, description}.
You can try this in your browser if you are confused with this. In the image below is the case where the two names are different, just for clarity.
ng add @ng-bootstrap/ng-bootstrap NgbModule into the app.module.ts and adding
the bootstrap.min.css to the styles in angular.json file. ng new MyProjectName cd MyProjectName ng serve ng generate service services/stocks // Will create a new service in the src/app/services
folder ng generate component components/summary // Will create a new component in the
src/app/component/summary folder npm -v npm install -g typescript npm install -g @angular/cli ng help
ng new angular-hello-world src/index.html, you will see the <app-root></app-root> tag. The app-root
tag is where our application will be rendered. app-root is a component that is defined by our Angular application. In Angular we can define our own HTML tags and give
them custom functionality. The app-root tag will be the “entry point” for our application on the page. ng serve <select>, <form>, <video>. But what if we wanted to
teach the browser some new tags, like <login> to display a login bar. This is the basic idea behind components. We are creating components that are
basically custom tags and teaching the browser how to display them. In the below example, we will be creating our own custom tag:
app-hello-world ng generate component hello-world. This is what the generated component looks like:
@Input decorator.
@Input() allows a parent component to update data in the child component.
{{ }}. For example, take note of the userName property
below. The userName property was defined in the file above as a property, and hence we are able to use it below in the template file for the class.
ng serve, angular will look for the angular.json file to find the entry point to the app. At a high level, the entire process
looks like this: angular.json specifies a main file, which in this case is the main.ts file. main.ts is the entry point for the application and bootstraps the entire application src/app/app.module.ts where it find the AppModule AppModule specifies which component to use as the top-level component. In this case it is AppComponent (src/app/app.component.ts) AppComponent, in its templateUrl then defines the app.component.html which finally contains our app-user-list component NgModule
which points to the component you want to load.
@NgModule. The @NgModule defines four keys that are used. We will look at the keys one-by-one. declarations
: specifies the components that are defined in this module. You have to declare components in a NgModule before you can use them in your templates. When we use theng generate to generate a new component, the CLI automatically adds the component to the list of declarations.
imports
: describes which dependencies this module has. Since we are creating a browser app, we have added the dependency asBrowserModule.
Note that there are two similar keywords: import and imports. We put something in our NgModule's imports if we're going to be using it in our
templates or with dependency injection. providers
: providers is used for dependency injection. So to make a service available to be injected throughout our application, we will add it here.bootstrap
: tells Angular that when this module is used to bootstrap an app, we need to load theAppComponent as the
top-level component.
<button/>
onClick event, we do the above. When the button is clicked, it will call the addArticle method. The addArticle method will be defined in the
same class in which the templateUrl is set as app.component.html. The addArticle function is defined as follows:
<input/> elements, we can pass them as variables into the
addArticle() function on the button. <input name="title" id="title" #newtitle> this markup tells Angular to bind this input HTML element to the variable #newtitle.
The #newtitle syntax is called a resolve. newtitle is now an object that represents this input DOM element (specifically, the type is HTMLInputElement).
Because newtitle is an object, that means we get the value of the input tag using newtitle.value. Similarly we add #newlink to the other
input
tag, so that we'll be able to extract the value from it as well. The objects that are returned from the resolve that we used on the input elements are then
passed into the function addArticle. @HostBinding that I do not understand
@Decorator templateUrl or template @Component is called the Decorator that adds metadata to the class that follows it, which in this case is AppComponent. The
@Component annotation also specifies the selector which tells Angular which element to match. By saying selector: app-root, we're
saying that in our HTML we want to match the app-root tag, that is, we’re defining a new tag that has new functionality whenever we use it. E.g. when we put this
in our HTML: <app-root>, Angular will use the AppComponent component to implement the functionality. template which
defines the view to render. AppComponent class.
{{ }} syntax is called template binding. It tells the view we want to use the value of the expression inside the brackets at this
location in our template. Note that the code inside the brackets is an expression. What it means is that we can do things like this:
[productList]="products" Here we are saying that we want to read the value of the expression 'products' from the AppComponent and store that into the
productList variable that is defined in the ProductsList component. productList is being referred to in the text as 'attribute key' and products as
'instance property'. (onProductSelected)="productWasSelected($event)" We're saying that we want to listen to the onProductSelected output from the ProductsList
component. (onProductSelected), the left-hand side is the name of the output we want to "listen" on. "productWasSelected", the right-hand side is the function we want
to call when something new is sent to this output. $event is a special variable here that represents the thing emitted on (i.e. sent to) the output.