Angular is ... a framework

home

Intro

Angular is for making dynamic single web-pages. It has no back-end part -- routing page requests and nice database use are not angular's problem. It uses javascript (actually TypeScript, but same thing). Angular's main feature is spreadsheet-ness: in your HTML put <p>Hello {{name}}</p>. It will fill in the name, including tracking changes.

A bit longer example, this will change the paragraph as the user changes the textBox:

<input type=text [ngModel]="animal"/>
<p>I like {{animal}}</p>

An important skill is remembering which domain you're in, and which rules apply. The back part is regular javascript, but you're avoiding getElementbyId; instead you want to use magic angular HTML references. Then over in the HTML-template part you're using angular-HTML special syntax mixed with some javascript. And that's only the start.

Communication beyond the magic linkages is a pain -- angular likes having a tight heirarchy of parts with strict communication protocols. Angular seems designed for non-coders -- it would rather make up new syntax than provide useful javascript functions. It seems to have frequent big updates with big changes ("AngularJS" is the old version, with the most documentation; the current version is Angular2, version something.something).

It's a Google project. It seems to have the worst of both worlds. It tries to stick to real javascript, making it cumbersome; but then adds enough magic syntax to make it awkward.

Modules / chunks overview

Angular assumes you want to break your web page into several reusable modular chunks. Each chunk has an "angular" hidden part and an HTML-template part. Angular doesn't use code to write out the page -- it merely fills in your existing HTML template. Of course, the template can have embedded IF's and loops (following a unique angular syntax).

The heirarchy part is also done in the HTML template, not through code: <cowPart></cowPart> is how you include angular module cowPart in another module. Communicating to/from sub-components is set-up in the HTML as well with more special commands. Ug.

A module

An angular module is two things: a file with a special javascript class, and an HTML template. That template is normal HTML code but with special angular bits thrown in. It's generally in a file by itself, but can be a short string included in the class file. The files will be dot-ts (TypeScript) and dot-HTML (if you have a seperate HTML template). There's no required name or file structure -- instead a master list includes all names and paths.

A sample angular module. First the HTML file. This would be the entire thing, exactly like this:

<h1>{{dogName}}'s flock</h1>
<p>Nothing special goes before or after,
just the HTML you want inserted</p>

<p>There {{herdSize==1?"is":"are"}} {{herdSize}} sheep</p>
<p (click)="doubleHerd()">Click to double the herd</p>

From a quick look at this we know the rest must have variables dogName and herdSize, and function doubleHerd(). As they change, the page will change -- that's the point of using angular. Note the funny syntax's -- {{}} establishes we're using angular variables. But then the call to doubleHerd() looks like a regular javascript call -- the secret is that (click) is an angular callback, making it all into angular stuff. Note "is/are" is computed with a javascript expression inside of our {{}}'s, using angular variables (more on all of this later).

Now onto the main Component part, in pieces. First, angular requires you to javascript import every little thing you use. For this simple one we'll just need Component (which we always need):

import { Component } from '@angular/core';

This next thing surprised me. Javascript has decorators! They can go in front of anything and add special attributes. Who knew? They work like: @decoratorName({field:value, field:value ...}). Angular leverages that to add some useful tags:

@Component ({
  selector: 'sheepDog',

  templateUrl: './sheepDog.component.html',
})

selector is this component's official angular-HTML tag. templateUrl is where to find the HTML part (which is called the HTML-template -- get it, templateUrl?). There's an option to instead put the HTML inline, right here. Replace templateUrl with simply template and put the HTML as a string (ex: template: '<p>{{amount}} sheep</p>'.

The last part is a new-style javascript class holding our angular variables and callback functions (and whatever else). If you're like me, this looks nothing like javascript, but it is, and instantiates and object with three properties when used:

export class sheepDogComponent {
  herdSize : number = 4;
  dogName : string = "Fred";

  doubleHerd() { this.herdSize *= 2; }
}

That's everything in your dot-ts file. I lied a little about javascript: colon-number and colon-string are from TypeScript, which angular prefers, but the rest is real javascript.

Nowhere in any angular file will we ever write new sheepDogComponent(). That's taken care of automatically when angular sees us requesting a sheepDog. For multiple copies it also handles which herdSize goes with which HTML {{herdSize}}.

model to HTML Communication

The simplest thing is to have the HTML part use a variable from the javascript model. Merely put it inside double-curlies:

<p>My name is {{dogName}}.
  I guard {{herdSize}} sheep</p>

You're allowed to use expressions (but you can't write your own small functions -- only 1-line value-returning expressions):

<p>My name is {{dogName.substring(0,4)}}.
  I guard {{herdSize*2-1}} sheep</p>

You can use them for properties, but not for style (not sure why):

<input type="text" value={{herdSize}}/>
<p class={{getSheepClass()}}>Info about sheep...

<!-- but not style: -->
<p style={{getStyleString()}}>This will not work

A tricky bit is that {{}} auto-update only works if you "touch" something in a component class. Normally that would happen anyway, but there can be times you somehow squirm around the normal mode -- for example, changing a file-level global through a timer won't trigger an HTML redraw. In that case you'll need to create a dummy callback (we'll see this later) to trigger an update.

pipes

These are borrowed from similar languages as a non-function-looking way to call functions. But they're pointless in Angular since you can already use javascript. For example this uses pipes to get the first 5 letters of w, in lowercase (followed by working angular code using regular javascript):

<p>Size is {{w | slice:0:5 | lowercase}}</p>

// same, but more obvious to a programmer:
<p>Size is {{w.substring(0,5).toLowerCase()}}</p>

Again, I think these are in angular since they're semi-standard, weird as they are, in frameworks like this.

HTML to model communication

This is where users can change an HTML dropdown on their page, which changes a real angular variable (which auto-triggers a page redraw using the new value(s), as we've seen).

Fancy ngModel shortcut

For input and select HTML elements (textboxes and dropdowns) angular provides a fancy shortcut. [(ngModel)]="varName". It provides a 2-way link. It tracks the variable, as if we used {{varName}}, and also copies user-made changes to the back part. An example:

// tracks dogName, also dogName tracks changes to this box: 
<input type="text" [(ngModel)]="dogName"\>
<p>Check it works: {{dogName}}</p>

This method has two limitations. One, it only fires for an OnChange. It can't be made to track changes as you type. The other is you must link to a variable. You can't use this for when you need changes to call a function.

ngModel also requires an import: import { FormsModule } from '@angular/forms'; and possibly imports: [ FormsModule ] in the appropriate place.

The long way

As mentioned, ngModel is a shortcut. The "real" way, which also gives more control, is using the special Angular callbacks (it uses 2 pieces of angular magic):

<input type="text" (change)="updateName($event)"/>

<p>Dog's name is: {{dogName}}</p>

Angular event callbacks go in parens. They use slightly different words than javascript: (change) for OnChange, plus (click), (keyup), (focus), (blur), (focusout), and more. The actions go in quotes (not {{}}'s), but updateName is an angular action, found in the angular section of your code (when angular sees (click) it knows "oh, this whole thing is angular, not basic javascript").

$event is Angular magic. It bundles up info about what the event was, when it occurred and -- what we'll use the most -- what item it happened to. We'll generally be sending $event when a regular callback would send "this". It starts with a dollar sign since it just does. Our back-part receiving function might look like this (down at the end):

import { Component } from '@angular/core';

@Component ({ ...  })
export class nameChangeExample {
  dogName = "Rex";

  updateName(e:Event) {
    console.log("printing to prove we called this");
    this.dogName=(e!.target! as HTMLInputElement).value
  }
}

That is basically e.target.value, except TypeScript insists on the "this won't be null" assurances (the !bangs) and a cast to HTMLInputElement. Ugg.

If we wanted the textbox to start with dogName we'd also use the {{}} trick (for its value):

<!-- starts with dogName, tells us about changes: -->
<input type="text"
 value={{dogName}}
 (keydown)="updateName($event)"
/>

Angular item ID's

Angular allows you to add useful references to HTML items. Simply add #myElementID inside the first tag. As an example, this paragraph is angular-named "dogInfo":

<p #dogInfo>About dogs</p>

We can use dogInfo as a reference to that paragraph. That works within our back-part javascript, and, surprisingly, also within the HTML part.

ID's within HTML

In HTML you can reach-out to that element with simply the name and dot-innerHTML or dot-value (and so on). Here a button clears a named textbox:

<input type="text" #catName/>

<input type="button" (click)="catName.value='' "/>

Since we used the angular event (click), the sytem understands the rest is angular code; it figures out what catName must be.

Here's another with a sneaky but common bug-fix:

<input type="text" #catName (keyup)="0"/>
<p>Cat name is {{catName.value}}</p>

The paragraph copies the value from the textbox -- that part is fine. The problem is it won't track. HTML is only redrawn after an angular event. The solution is that dummy callback. (keyup)="0" is a do-nothing event, but it updates the page.

And here's a silly one showing innerHTML. The heading copies the paragraph, surrounded by NEW's:

<p #p1/>{{dogName}} has {{herdSize}} sheep</p>
<h1>NEW {{p1.innerHTML}} NEW</h1>

Using angular-ID's from code

Using these in our real functions is probably more useful, but takes more set-up. Much more. We'll need to declare a variable for the link, connect it, add imports, and use an extra field. Working (partial) code:

// 2 more things we need to import:
import {ViewChild, ElementRef} from '@angular/core';

export class sheepDog {
  // declare a variable for the link:
  @ViewChild('catName') catTextBox!: ElementRef;

    // inside some function:
    var w = this.catTextBox.nativeElement.value;

The line @ViewChild('catName') catTextBox!: ElementRef; is completely new. It looks for #catName in the HTML and hooks it to new variable catTextBox (the bang! is required to assure TypeScript it won't be null). To use the reference we now need to add dot-nativeElement. But otherwise it works the same, as a handy reference to any tagged element.

Now that we have a formal variable to catName, our HTML can use it (which is completely useless, but fun). It requires nativeElement:

// using the angular variable (from the back part):
<p>Name is {{catTextBox.nativeElement.value}}</p>

// Easier way, use tag from HTML part:
<p>Name is {{catName.value}}</p>

Creating a heirarchy

An angular component can be included in another by using its official name (the one after selector:) in a paired tag; for example: <sheepDog></sheepdog>. creates an instance of the sheepDog class and inserts the HTML template. Strangely, nothing goes between the tags -- anything you put there is ignored. Why not use the single tag format? Who knows?

It's mixed right-in with the parent's HTML. For example (assume standardHeading is another angular component we created):

<h1>My sheep farms</h1>

<standardHeading></standardHeading>

<p>Farm#1:</p>
<sheepDog></sheepDog>

<p>Farm#1:</p>
<sheepDog></sheepDog>

And again, note our 2 sheepDogs are seperate instances -- each has their own name and so on. Including them multiple times is fine.

Parents writing information to sub-components

Suppose a Ranch component uses a sheepDog component:

<!-- Ranch's HTML template: -->
<h2>Tony's Sheep Farm</h2>

<p>We have a very good dog:</p>
<sheepDog></sheepDog>
<p>And more stuff we don't have room to describe</p>

When we include something, we're allowed to assign to it's variables (which overrides the defaults). This renames one dog "Tony", and the next name1:

<sheepDog [dogName]="'Tony'"></sheepDog>
<sheepDog [dogName]="name1"></sheepDog>

The syntax is new. Start with the variable in the child which you want set, in square brackets. Assign it the new value, in quotes. Note how it's assumed to be an expression -- "name1" is a variable; "'Tony'" is the constant 'Tony'.

As usual, we can use any sort of expression, since this a a 1-time assignment to that variable:

<sheepDog [dogName]="'Mrs. '+randDogName()">
<sheepDog [dogName]="parentColor.substring(0,3)">
<sheepDog [dogName]="DogNames[0]">

But none of that won't work yet. We're only half done. The child component variable needs to be prepped as parent-writable. It needs to be decorated with @Input() (which needs yet another import):

import { Input } from '@angular/core';

@Component({ ... })
export class setByParentExample {

  // mark var as able to be set by parent:
  @Input() dogName = 'dummy. Will be set by parent';

Sub-components talking back to parents

A child component can send events up to the parent using a 2-step process. Step 1 is the child having a regular callback to a function. Step 2 is having that function send a new type of event up to the parent.

As a quick review, here's our old name-change event code:

<input type="text" (change)="updateName($event)"/>
<p>Name is {{ dogName }}</p>

@Component ({ ...  })
export class nameChangeExample {
  dogName = "Laura";

  updateName(e:Event) {
    this.dogName=(e!.target! as HTMLInputElement).value
  }
}

Step 2 is having that function to send a new event up to its parent. First is a special EventEmitter, which needs to be decorated with @Output:

// adding a Emitter:
import { Output } from '@angular/core';

  // declared as a class variable:
  @Output() nameEmitter = new EventEmitter<string>();

nameEmitter's only purpose is to send its emit event to anyone listening. We'll add that to the old callback:

  updateName(e:Event) {
    this.dogName=(e!.target! as HTMLInputElement).value;

    // new: tell our parent name has changed:
    this.nameEmitter.emit((this.dogName));
  }

The child component is now done.

Up in the parent. The HTML part is told to catch the events from nameEmitter, sending it to a function:

// in the parent HTML template:
<sheepDog
  (nameEmitter)="setName2($event)"  // new output line
  [dogName]="parentName">  // old line
</sheepdog>
<p>Testing: name in parent is {{parentName}}</p>

It looks like a normal event. The event, in parens, is nameEmitter. It calls function setName2 using the same funny $event trick.

There's one more bit of weirdness. We normally need to work to get to the event's value. But in these it's unwrapped for us. $event turns back into the dogName first sent by emit():

  // callback in the parent component class:

  // input is NOT the event! Just the string sent by emit:
  setName2(c:string) {
    this.parentName=c;
    ...
  }

  parentName:string = "Dogus Maximus";

And that's it. To sum up: 1) start with a basic event, 2) add an EventEmitter and call its emit, 3) tell the parent HTML to receive it in the HTML part, 4) add a regular callback to the parent.

Here's everything in the child component class together:

export class sheepDog2 {
  @Input() dogName:string = "I am overwirtten by parent";

  @Output()
  nameEvent: EventEmitter<string> = new EventEmitter();

  nameChange(e:Event) {
    this.dogName=(e.target! as HTMLInputElement)!.value;
    this.nameEvent.emit(this.color);
  }

Once you set all of this up you've got pretty good 2-way communication. Changes in a subpart call a function in the parent, which probably changes some of its variables and redraws the child using those new values.

shortcuts

Communicating to children gets shortcuts, but they're not all that helpful. Now matter what, you'll need to create the emitter, manually call emit, and add @Input to the child variable.

One, which isn't technically a special shortcut, is using inline code:

<sheepDog (nameEmitter)="parentName=$event"></sheepDog>

As before, $event magically turns into the string sent by emit().

The super-shortcut re-uses the two-way [()] syntax. It sets dogName at the start, and tracks it in parentName (on events):

<sheepDog [(dogName)]="parentName">

It's a shortcut for the not-all-that-much-longer:

<sheepDog
  [dogName]="parentName" // copy our variable into child's
  (nameChange)="parentName=$event" // child events change our var
></sheepDog>

Any-to-any communication (Services)

Angular's term for a class instance usuable by any component is service. They're not too bad. You make a regular class, but decorated with Injectable (instead of Component). This "service" provides us with a global n:

// a service providing a global variable, n:
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root', // this means 1 shared root-level instance
})
export class sampleService {
  n=9
}

A brief note here: injection is another word for a plug-in. So the creepy sounding @Injectable merely means this isn't a main Angular thing -- it's made to be plugged into Components.

A component that wants a Service needs to import it (obviously) and then include it as a parameter in your constructor (what?!?), and that's it. This gives us a link to an instance of sampleService:

import {sampleService} from "../sampleService"

@Component( ... )
export class useService {
  // if you don't have a constructor, write one,
  // if you do, add a new parameter:

  constructor(public ss:sampleService) {}

It makes no sense why this should work. That constructor does nothing. Worse, public (or private) before a parameter isn't a thing. It's just a signal to Angular to magically add field ss, linked to an instance of the service.

With just that constructor we have a ready-to-use ss variable. Any function can use ss.n or we can put {{ss.n}} in our HTML template.

Multiple copies of services

This is a completely different use, so different that it seems confusing to also call it a Service. We can make a service which is bound to one particular Component, with each one getting a new copy.

The idea is to create Model/View seperation: the Component sets up the actual HTML, which is the View, while the Service performs the logic. We can already do that by creating a regular javascript class for the logic, but I suppose turning it into a Service helps angular somehow.

A service's @Injectable decorator has a spot telling us how many instances to create. 'root' (in quotes) means to make one globally shared instance:

@Injectable({
  providedIn: 'root', // creates 1 global instance
})

Giving the name of a Component switches it so only that Component can use it, and each gets a fresh instance. This one is for sheepDogs:

// SheepDog Service (with one instance per sheepdog):
import { sheepDog } from './sheepDog/sheepDog.component';

@Injectable({
  // list components which can use it (no quotes):
  providedIn: sheepDog
})
  ...

Then sheepdog needs to include the service by name (the new providers entry under @Component):

// sheepDog component using individual instance of a service:
import { SheepDogService } from "../sheepDogService"

@Component ({
  ...
  // say we can use this service:
  providers: [myLocalService]
})
export class sheepDog {
  // as before, put in the constructor and get it for free:
  constructor(public sds:SheepDogService) {}

  // use it as normal:
  addx() { sds.x++; } // assuming dot-x exists

Again, the net effect is splitting sheepDog into two parts. We could have put everything in sheepDog, but instead we move some into sheepdogService, which every sheepDog gets an instance of.

General handles to children

This is where a programmer can finally use angular. When we include another components we can get a link to the the actual instance angular creates! Yay! No more weird magic rules. It works about the same as the #angularID trick. When you request a component, add a #tag:

<sheepDog #sDog1></sheepDog>
// we can eventually use sDog1 to find this instance

Once again we'll use @ViewChild to find it. Since we'll be getting a sheepDog component, we'll need to import that:

import { ViewChild } from '@angular/core';
import { sheepDog } from "./sheepdog.component";

  // ViewChild finds #sDog1 and links to our var sd1:
  @ViewChild("sDog1") sd1! : sheepDog;

  // reach directly into component:
  getClick() {
    this.sd1.dogName="Rex";
  }

Note the how sd1 is a link to that instance of the sheepDog class (before it was a link to an HTML element). We can just reach in as if we were using a normal program, and not a monstrosity like angular. If we could put this into a global service everyone could have access to everything.

Special inits

Angular gives you an special init which run after everyone runs their constructor. It only seems to work in components, not services:

import { OnInit } from '@angular/core';

// inherit it as an interface:
export class sheepDog implements OnInit {

  // wwrite it:
  ngOnInit() { console.log("I'm run after all constructors(?)"); }

@ViewChild's are run after constructors, as well. If you need an initialization step after any of your ViewChild variables are set-up, angular provides ngAfterViewInit:

// import it:
import {AfterViewInit} from '@angular/core';

// inherit it as an interface:
export class sheepDog implements AfterViewInit {

  // write it:
  ngAfterViewInit() { ... }

There are probably more, and I'm not sure how those interact.

Control structures

Programs which generate HTML, such a PHP, use regular IF's and loops around print statements. Frameworks like Angular have to work a little harder, using special IF/loop controls. It's not quite as flexible, but it mostly works.

if's

An angular-HTML IF goes inside the starting tag as *ngIf. The condition goes in quotes. The only creates the paragraph is color isn't empty:

<span *ngIf="color!=''">
  We have a non-empty color
</span>

As usual, we have full access to the component's varables. The block goes to the matching end tag -- other nested elements go along for a ride. A longer example:

<span *ngIf=
  "dogName.length>=3 && dogName.length<=6">
  len is 3 to 6
</span>

If the condition is false, the HTML-code is gone (not hidden). Any code attempting to reference parts of it will fail.

IF-ELSE exists, but it's awkward. Many people simply write a second IF with the condition flipped. To make an else, add it elsewhere as a special block with a "template reference variable"; then use a special else-clause to select it. Here the block labelled #A2 is the else:

<span *ngIf="x>3; else A2">3 or more</span>

<p>I am positioned AFTER A2 (if it is used)</p>

<!-- the else clause, named A2: -->
<ng-template #A2>
<span>3 or less</span>
</ng-template>

The new clause "else A2" searches for a sepcial ngTemplate block tagged #A2 and pulls it. The #A2 block can be anywhere -- angular will move it. And, of course, A2 is arbitrary -- name it whatever you like.

ng-template tags

ng-template tags are special angular things. By default they are not used. They're expected to hold special angular commands -- tagged else-clauses, or IF's, or FOR's.

*ngIf is actually a shortcut for an [ngIf] inside of an ng-template. Here's the "real" syntax of a simple IF (occurring when color is red):

// long version of an IF:
<ng-template [ngIf]="color=='red'">
<span>fire engines are red</span>
</ng-template>

then;else syntax

Angular allows a more symetric IF where you list both the true and false blocks. A weird side-effect is that your own contents is never used:

<p *ngIf="color.length>4; then longColor; else shortColor"> </p>

<ng-template #longColor>
  <span>long</span>
</ng-template>

<ng-template #shortColor>
  <span>short</span>
</ng-template>

It looks like, but it's a lot of work for a simple if/else.

Nested IF's

Nesting IF's is possible, but looks funny -- the nested IF's are inside of the included blocks. This impossible-to-read mess adds a nested if-else to the "long" branch and a simple IF to the "short" one:

<p *ngIf="color.length>4; then longColor; else shortColor"></p>

<ng-template #longColor>long
<span *ngIf="color.includes('a'); else hasNoA">has an A</span>
</ng-template>

<ng-template #hasNoA>does not have any A's
</ng-template>

<ng-template #shortColor>short
<span *ngIf="color.length<3">--very short</span>
</ng-template>

It might look nicer if it was all in then/else format, using blocks for every branch; but that would be even longer.

Loops

Loop syntax is similar, except uses *ngFor followed by a special angular foreach like: "let varName of LIST". For example, this angular loop shows "1 and 4 and 9 and":

<span *ngFor="let x of [1,4,9]">{{x}} and </span>

As with IF's, these loops repeat everything up to the matching tag. You might note a somewhat new rule here: {{{x}} should look up an instance variable, but it's also used to grab the loop variable (I assume it checks for local loop vars first?)

Nested loops are made in the obvious way. This creates a table with 3 rows and 6 columns:

<table>
  <tr *ngFor="let animal of ['cow', 'duck', 'tiger']">
    <td>{{animal}}</td>
    <td *ngFor="let i of [2,4,7,0,0]">{{i}}</td>
  </tr>
</table>

ngFor's provide a few magic variables, set each time through: index (0-based), even & odd, first ... used like this:

<span *ngFor="let num of [3,7,9,4]; let i=index">
  <p>Num#{{i}} is {{num}}</p>
</span>

i will run through 0 to 3. You'll commonly see the same variable, such as: let odd=odd. This is because angular doens't allow direct use of the variable -- you can only use it in the speical let part.

Loops and #tags

#tags in lines generated by an ngFor won't change for each line. If you tag a looped line with #A0, you'll get lots of copies of lines all tagged as #A0. As it turns out, that's not a problem. For one thing same-line references will still work. And if you need an array of every tag, you can get that later with new decorator @ViewChildren.

For an example of using "your" tag. Here all 4 lines have tag #numP, but each (click) event knows to use it's own (clicking on a paragraph will turn itself and only itself into abc):

<span *ngFor="let num of [3,7,9,4]">
  <p #numP (click)="numP.innerHTML='abc'">
    I will turn into abc when clicked
  </p>
</span>

Likewise you could send numP to a function:

  // inside of the *ngFor (sending "our" numP):
  <p #numP (click)="numClick2(numP)">

  // the function in the Component:
  numClick2(e:any) { e.innerHTML="xxx"; }

Once again, each line understands numP is "it's" version. Notice some weirdness: e didn't need to use nativeElement since numP was already partly unwrapped (I wasn't sure what type it was, so used any).

If that won't work and you need a list of all lines, you can gather those identical tags into an array using the @ViewChild trick -- but with @ViewChildren to get a list -- then do whatever you like with it:

<!-- a sample list of lines, all with #numP -->
<span *ngFor="let num of [3,7,9,4]">
  <p #numP">Num is {{num}}</p>
</span>

// in our Component:

import { ViewChildren, QueryList } from '@angular/core';

  // in the class:
  @ViewChildren("numP") NumPs : QueryList<ElementRef>;
  // NumPs is now an "array" of links to each *ngFor #numP

  // sample function using array of *ngFor items:
  numClick() {
    this.NumPs.forEach(
     (ref, i, dummy)=
       ref.nativeElement.innerHTML="abc"+i; }
    );
  }

The funny forEach syntax is because QueryLists don't have direct indexing. You're forced to use a forEach (or another provided list function). That function is supplied with the element, the index, and an array which I don't understand the purpose of. If you hate doing that, just pull the elements into an real array inside of ngAfterViewInit().

Setting style; properties

You can set some properties with what we have so far. For example <td colspan={{spanCount1}}> works fine. But just in case, and to maybe make it shorter, angular provides a new syntax using square brackets and quotes:

<td [colSpan]="spanCount1">cats</td>

The idea here is angular knows, from the []'s, that you want the quoted part evaluated.

As a shortcut for styles you can use [style.property]="computedValue". It even uses the correct spellings -- font-size instead of the common mutation "fontSize":

<p [style.color]="color2">uses the "color2" variable</p>
<p [style.font-size]="getFntSz1()">Call a function</p>

Classes have a shortcut where you provide an object with potential class names matched with computed true/false values. Below we set the class to "green" or "red" according to the length of the color variable:

<p [ngClass]="{green:color.length>2, red:color.length<=2}">

As a quick check {cat:false, goat:true, horse:false} sets the class to "goat".

There are several stranger versions of this trick. Note that if you hate this method, [class]="computedValue" still works.

 

 

Comments. or email adminATtaxesforcatses.com