Angular Notes

by Jerry Sky

Notes on Angular (non JS).

1. Resources


2. Installing Bootstrap

  1.    npm install bootstrap
  2. Modify $WORKING_DIRECTORY/angular.json:

    "styles": [
      "node_modules/bootstrap/dist/css/bootstrap.min.css",
      "styles.css"
    ]

3. NgModel input element inside ngFor

Nested ngModel input element inside ngFor need to refer to a value inside an Object. If it isn’t wrapped in an Object Angular won’t compile the app for some odd reason.


4. Router vs. Location

When using Angular navigation use the Router’s navigate function. The Location’s go function is meant to interact with URL, not to navigate in application routes.

Source


5. Ending an Observable

To complete the Observable use return of(). It will stop propagating any further notifications as of with no arguments will complete right away and not emit any notifications.


6. Upload progress

To get notifications about a file being uploaded use reportProgress: true in any HTTP method’s additional options object.

Source


7. The .htaccess file

For serving a static Angular app on a standard Apache server you need to setup a .htaccess file like so.

Source


8. Tracking many files

When dealing with multiple Angular projects or Angular projects mixed with some other opened at once the system can be overwhelmed with the amount of files to track as the code editor is trying to observe every single file in all of the projects. The solution seems to be to alter a default number of files the system is allowed to track.

  1. Open /etc/sysctl.conf and add line fs.inotify.max_user_watches=524288.
  2. Execute sudo sysctl -p.
  3. View /proc/sys/fs/inotify/max_user_watches and verify that the output number equals to 524288.

9. Testing components that contain Angular Material components

When testing a component with some components from Angular Material (e.g. MatButton or MatCard) you have to include appropriate Angular Material modules to your tests.
For example, when the component contains a mat-button you should add to the imports of the test a reference to the MatButtonModule:

beforeEach(async(() => {
    TestBed.configureTestingModule({
        imports: [
            MatButtonModule, // said reference
        ],
        declarations: [
            ...
        ],
    }).compileComponents();
}));

otherwise, the test will complain about unidentifiable components.

Secondly, if it is necessary to test the interaction with an Angular Material component (instead of e.g. testing only the function that is invoked by this component) it is advised to use Angular Material’s component harnesses. This method prevents from possible issues due to change in the internal API of Angular Material.

“Relying on implementation details of third party libraries is cumbersome because you are vulnerable to refactorings, and you need to understand implementation details.”

Instead of accessing the components in the HTML through invoking the query method use mentioned earlier Angular Material’s component harnesses.

Setup:

let loader: HarnessLoader;
let component: [...];

beforeEach(() => {
    fixture = TestBed.createComponent([...]);
    component = fixture.componentInstance;
    loader = TestBedHarnessEnvironment.loader(fixture); // (1)
    fixture.detectedChanges();
})

Here we are preparing the TestBed for our testing purposes. Notice the (1) additional line that loads the harness environment.

Now we can test Angular Material components. Here is an example from the source article:

it('should filter out the alive characters if we set filter to dead', async () => {

    const deadRadioButton = await loader.getHarness<MatRadioButtonHarness>(
        MatRadioButtonHarness.with({
            label: 'Dead'
        })
    );
    const table = await loader.getHarness<MatTableHarness>(MathTableHarness);

    await deadRadioButton.check();
    const rows = await table.getRows();
    expect(rows.length).toBe(5);

});

Sources:


Angular has the anchor links disabled by default (at least when the routing is enabled).

Refactoring the module responsible for routing in a given app as follows:

[...]
const routerOptions: ExtraOptions = {
    useHash: false,
    anchorScrolling: 'enabled',
};

@NgModule({
    imports: [RouterModule.forRoot(routes, routerOptions)],
    exports: [RouterModule]
})
export class AppRoutingModule { }

will enable this functionality.

Source: an answer on Stack Overflow


11. Using SVG icons with Angular Material

To add a custom SVG icon that can be used throughout the whole app you need to import MatIconRegistry:

import { MatIconRegistry } from "@angular/material/icon";

and the DomSanitizer:

import { DomSanitizer } from "@angular/platform-browser";

to resolve the path by trusting the local asset file.

Then, inside of app.module.ts inject said dependencies into the class constructor and add the desired icon(s) to the registry:

constructor(
    private MIR: MatIconRegistry,
    private DS: DomSanitizer
) {
    this.MIR.addSvgIcon(
        'custom_icon',
        this.DS.bypassSecurityTrustResourceUrl("assets/custom-icon.svg")
    )
}

Source: Digital Ocean Article