Error: Can’t bind to ‘ngModel’ since it isn’t a known property of

A confusing error message, which may occur if you’re using a SubComponent (declared by SubComponentModule) in a ParentComponent (declared in a ParentComponentModule) and:

  • you forgot to add SubComponentModule in ParentComponentModule‘s imports (then it’s not accessible by SubComponent!)
  • you forgot to add the SubComponent in the
    SubComponentModule ‘s exports (then it’s not accessible outside the Component declared by this very module)

Angular Component: unit testing

If Angular services are quite easy to tests (the main difficulty being /what to test/), Component testing deals with more challenges. This post sums up some key points.

Please note that we are using ngx-speculoos to do so, which offers some friendly syntaxic sugars to write the tests. Please go through the presentation of the package before reading forth.

What to test ?

When testing the Component-Under-Test, here are some suggestions about what to test:

  • the presence of HTMLElement or SubComponents in the generated template (potentially, depending on the CUT inputs, some user actions, etc.): for this, syntaxic sugars in the CTester (ngx-speculoos) are welcome.
  • the Services methods called by the CUT (at initialization, on a button push, etc.): this is done in a usual manner, via Services mock
  • the inputs provided to the SubComponent: the subcomponents are not fully tested here (they are tested in their own unit tests), we only tests that we provide them with the right inputs
  • the behaviour of the CUT when the subcomponent outputs: here also, we need to emulate the output emissions of the mocked subcomponents

Component-Under-Test lifecycle hooks

ngOnInit()

When writing tests, you might want to perform some actions before the actual initialization of the CUT (before its ngOnInit() is called), such as: setting up spies on related services, setting up CUT inputs, etc.

It appears the Component actually initializes with the first tester.detectChanges(); occurrence (tester is a CTester, see ngx-speculoos). For desambiguation purposes, we suggest to create a initComponent function, to call at the appropriate time in your tests:

  function initComponent(): void {
    tester.detectChanges();
  }

ngOnChanges()

Unfortunately, ngOnChanges will not be called every time you update the CUT inputs. This is something to be done manually, with laborious code such as:

component.ngOnChanges({
  quantity: new SimpleChange(null, { id: 22 }, false)
});
// instead of
// component.quantity = { id: 22 };

SubComponents references

You’ll have to mock all sub-components used by the Component-Under-Test (the tests will actually run correctly without them, only displaying console errors and warnings). Yet, you’ll soon want to check at the inputs of these sub-components (to check the CUT has provided them with the right data), as well as emulate their outputs (to check the CUT behaves appropriately in these cases).

The fixture created by TestBed helps us get a reference to any subcomponents, and fortunately ngx-speculoos keeps that functionality. In the definition of your CTester, you can implement this kind of accessor:

class CTester extends ComponentTester<StatisticsPanelComponent> {
  // ...
  get selectPeriodComponent(): TimeAbsoluteComponentMock {
    const debugElement = this.fixture.debugElement.query(By.directive(TimeAbsoluteComponentMock));
    // this select a component by its Component name
    // to select by other means, please refer to the DebugElement query documentation
    return debugElement.componentInstance as TimeAbsoluteComponentMock;
  }
  // ...
}

Then in your test:

it('should give its child appropriate inputs', () => {
  // ... test setup ...
  expect(tester.selectPeriodComponent.suggestTime).toBeFalse();
}
it('should behave appropriately when its child outputs', () => {
  tester.selectPeriodComponent.periodChanged.next({type: PeriodType.Absolute});
  expect(......);
}

Mocking Pipes

To mock pipes (especially custom pipes), one solution is to override the mocked pipe prototype directly. It’s a bit of a brutal solution, but it works.

First, create a mock of the pipe, which we will declare in the TestBed options, so it’s accessible from the CUT:

@Pipe({ name: 'svUserSetting', pure: false })
export class SvUserSettingPipeMock {
  transform(obj: unknown): unknown | null {
    return null;
  }
}

The mock will directly be used by the CUT, as it’s the only directives matching the name ‘svUserSetting’ declared within TestBed. Now, we’ll hijack its behavior to test different scenarii:

beforeEach(() => { // ... or directly in a test
  spyOn(SvUserSettingPipeMock.prototype, 'transform').and.returnValue(true);
});


RouteReuseStrategy: advantages and pitfalls

The Angular philosophy is to destroy a Component as soon as it’s not in use anymore, meaning: not in the DOM anymore, and this happens quickly when RouterOutlet is used to display such or such content, depending on the URL route. The Component will be created again, if the user navigates back to a route that contains it.

Recreating Components can be trouble (depending on the usecase)

This is useful for large applications (to reduce the memory) where Components are kept simple or when they will not be met again often enough to care about their destruction/reconstruction time.

But for applications where the user is expected to go back and forth the same Components, this can create several uncomfortable side-effects for the user experience:

  • a clipping may result, especially if some somewhat heavy initialization process occurs in the Component (= in ngOnInit); though, this might reveal a design smell. For instance, all data fetching (typically, from the API server) and calculation should be done and kept in a sidecar service, whose responsability will be to handle the ‘data state’ related to the Component, which can fetch it from there very quickly when initializing again.
  • the ‘UI state’ of the Component is lost, and that might go against the user experience. By ‘UI state’ (versus ‘data state’), I mean all the little interface details, not related to any business data, that evolves when the user plays with the Component. Examples: a selection in a Select node; the beginning of some text in a TextArea node; the expanding of a collapsable widget; the scrolling in a large list; the navigation in a map. For form-related elements, it would be possible to store the Form state in a sidecar, but for the rest of the myriads of possible little things, it wouldn’t be possible (too much effort) to store them all and restore them when the Component is met again, and the user would face a ‘default UI state’ each time. Again, this depends on the complexity and nature of the Components, and if we care at all about the UI to reset everytime.
  • when depending on third-party Component, we may still face an initialization time, resulting in clippings and annoying waitings. It will most likely be very difficult to save the internal ‘UI state’ of such Components, and for some of them, it would need some unwanted hacking. A third-party map component, for instance, is likely to request its tiles again if destroyed and recreated.

Angular RouteReuseStrategy to the rescue!

Angular offers a mechanism to keep a Component on the side when navigating away and use it again – unchanged – when the same route is met again, called RouteReuseStrategy. The set up is not sexy; it feels more like a toolbox than an integrated part of the framework, but it’s not difficult, and soon enough you can specify the different routes of your applications, whose related Components will be preserved for later (note that you define reuseable routes; you can’t flag a Component itself as reusable). And that’s it! The navigation is lightning flash again, your Components are met again as they were, hooray!

Notice: be wary though that your Component, when kept aside for later, is still very much alive. Its subscription will still be active, so be sure that your Component is not subscribed to anything exterior to itself (which should be very much the case anyway!).

RouteReuseStrategy: caveats

Sadly, no solution is ever perfect straight away.

In my design, there’s a little piece missing from the RouteReuseStrategy (SO users still agrees that it feels more like a bug), which is: some Component lifecycle hooks, to be alerted of its detaching (when it’s kept aside for later) and reattaching (reused).

Again, it might not be a problem for a lot of usecases. For mine, I couldn’t think about a proper alternative to what I have.

Description:

  • My Component depends on a part of the URL to identify which entity to display. For instance, the route /station/14 is linked to StationComponent (via RouterOutlet) and indicates the Station #14 should be displayed within it.
  • The Component should initialize depending on the route (and not some external state), because we want the same behavior whether the user has come to this route by navigating the application, or by launching this URL directly. For that purpose, subscribing to ActivatedRoute.params seems the most logical way, as this Observable emits some ParamMap, in which the interesting bit of the URL (defined in the routes given to the RouterModule) is directly proposed as paramMap.get(‘stationId’). Awesome!
  • Some other Components in my application rely on the displayed Station (if any). These Components can not subscribe to ActivatedRoute.params as they’re not connected to the route (from the RouterModule point of view). They could listen to URL changes by other means, but in a messy way, most likely very coupled to the route definitions. To resolve this, simple: we use a state service to keep the information of the displayed Station, on which my other Components can subscribe, and which is modified by my StationComponent whenever it detects a change in the route parameters.
  • Now if the user navigates to another Component, say, a Digest, then my state service will be alerted that now a Digest is displayed, and not a Station anymore. If he navigates back to a Station – one different than the first – then StationComponent is reused, it detects the change in the route parameters and notifies the state service that now a Station is displayed, this very new Station. Good!
  • BUT! If the user navigates away and come back to the same Station, then StationComponent is reused, but this time it does not see any changes in the route parameters (if it was 14, from /station/14 before, and now it’s still /station/14, then no changes have occured, as the observed ActivatedRoute is only the one related to StationComponent). No event is emitted by ActivatedRoute.params, and the notifying of the state service is not done, resulting in a unsynced state within my application. Curses !

That’s where I lack of an elegant way to resolve this. To me, the Component should be able to react to its reattaching, during which it would have an extra opportunity to notify the state service.

But RouteReuseStrategy does not call any Component lifecycle hooks. : /

RouteReuseStrategy’s missing Component Lifecyle hooks: a fix

A workaround (found on SO) consists on replacing the default RouterOutlet by a custom one, which will trigger some lifecycle hooks in its related Component.

sv-router-outlet.directive.ts

import { ComponentRef, Directive } from '@angular/core';
import { ActivatedRoute, RouterOutlet } from '@angular/router';

@Directive({
  selector: 'sv-router-outlet',
})
export class SvRouterOutletDirective extends RouterOutlet {

  detach(): ComponentRef<any> {
    const instance: any = this.component;
    if (instance && typeof instance.onDetach === 'function') {
      instance.onDetach();
    }
    return super.detach();
  }

  attach(ref: ComponentRef<any>, activatedRoute: ActivatedRoute): void {
    super.attach(ref, activatedRoute);
    if (ref.instance && typeof ref.instance.onAttach === 'function') {
      ref.instance.onAttach(ref, activatedRoute);
    }
  }
}

To use, define a Module for this new outlet, and load the module wherever you’ll replace the default <router-outlet> by <sv-router-outlet>.

sv-router-outlet.module.ts

import { NgModule } from '@angular/core';
import { SvRouterOutletDirective } from './sv-router-outlet.directive';

@NgModule({
  declarations: [
    SvRouterOutletDirective,
  ],
  exports: [
    SvRouterOutletDirective,
  ],
})
export class SvRouterOutletModule { }

Angular Elements

To allow new developments to be made in Angular and used in the Plain-Old-Javascript V1 application, we’ve worked with something Angular calls “Elements”. Angular Elements builds as WebComponents, a standard package importable in any page and fully responsible for its rendering and internal logic.

Modular Design

As their goal is to be injected in a foreign application, the Elements must be very autonomous. This helped a lot to design actual modules, with very few dependencies. The first Elements created (Automatic Export Parameter Setting and Phyc Export) don’t even use the Store, which is too coupled to the rest of the whole Superviseur V2 application, and handles their own data privately. A way should be thought, in needed, to use light-weight version of the Store within the Elements, and for them to be able to exchange data with a Store, if any.

Development organization

The easiest way to develop-test-debug the Elements is to develop them directly within an Angular environment. To accelerate the process, we don’t add them to the whole Superviseur but instead create mini-development-applications. In addition to the files of the Element itself (contained in, for example, MyFeatureModule), we create/edit these files:

  • angular.json: declaration of the new dev-app
  • package.json: npm command to start the dev-app
  • tsconfig.elements-dev.ts: adding the dev-app start file (note: there could also be one tsconfig file per AngularElement)
  • dev-myFeature.ts: a bootstrap start file
  • appMyFeature.module.ts: a module including MyFeatureModule but also some other modules we want to use within the Angular context, such as BootstrapModule and UserMessageModule.

This allows to test the application with ease in the Angular context and code most of the code.

When done, we want to build the WebComponents from the Angular Elements. Note that we’ll produce only one package containing all the Components we want to inject in the old application V1. To do so, we’ve created a new Angular project called ‘elements’ in angular.json with associated build commands in package.json. In src/elements, lie:

  • elements.ts: the project start file
  • elements.module.ts: in which we have to add our new Elements and define the new HTML tag for this one
  • concatenate-elements.js: a handy script to move generated files and concatenate them in the output directory (script used within package.json commands)
  • test.html: a simple plain-old page which imports the generated files, in which we want to add the new defined HTML tag for our Component

Note that test.html must be called from your web server (example: http://localhost/angular/src/elements/test.html) and not directly (not: file:///D:/Ceneau/angular/src/elements/test.html) for the API server to be reached properly !

With all that in mind, we’re set to go.

Inputs, Outputs

WebComponents can certainly handle Inputs and Outputs, just as an Angular Component can. But we’re in plain HTML, so inputs will simply given as simple HTML attribute. Note that they have to be kebab-case and not camelCase (and that the translation is automatically done under the hood by the generated WebComponent)! So if my Angular Component have an @Input() clientId: number, the HTML tag to summon it would be:

  <sv-aeps-pilot-ccgst id=”aepspilot” client-id=”8″></sv-aeps-pilot-ccgst>

If your input must change, I’m not too sure the changing of the attribute will be detected by the Components… As an alternative, we can totally get a reference on the Components itself and call one of its methods:

      var component = document.getElementById("aepspilot");
      comment.clientId = 2;

Note that you must use camelCase now !

For the output, to subscribe to them from a plain-old page:

var node = document.getElementById('myFeature');
node.addEventListener("messageInfo", function(event) {
  var message = event.detail;
  // ...
});

By convention, our Elements have 3 output emitters ( EventEmitter<string>) handled by the old application:

  • messageInfo
  • messageWarning
  • messageError

Limitation: Dev vs Prod

Certain parameters, such as the root URL of the API server, changes drastically between the dev environment and the staging/production/etc. The way it’s done now, parameters are included in the generated Component package, so a package generated in dev will only work in dev, and so on. As for now, we only commit the production package in the source control, along with the V1 files which import it.

Limitation: Internationalization (i18n)

I struggled with my first Component package size when I tried to include i18n in it, and reverted to use localized string directly in my components at the time. Now, Angular 9 has come with a new i18n system, and maybe it would be easy to use with Angular Elements.

Limitation: External CSS

The fact that the resulting WebComponent will be injected in an existing application does not protect this component from the default CSS rules applied by the user agent, which as we know can very a great deal from one browser to another (it should be protected from the global CSS styling of the existing application, though, if the encapsulation works well). Therefore, it is paramount to test the Component in-situ, meaning in the target application, and correct the Component CSS accordingly. The use of CSS resetter would also be a good practice within the Component, as this article describes: https://blog.jiayihu.net/css-resets-in-shadow-dom/.

Limitation: Error handling

Warning: I want to throw Exceptions in my service, to catch them in my Controller and display a user message accordingly. I tried to do so with a custom Error class, as follows:

 
export enum ExportPhycErrorType {
  SensorCodeCanNotByEmpty = 1,
  SiteMeteoCodeCanNotBeEmpty = 2,
  StationCodeCanNotBeEmpty = 3,
  StationHasActiveMeteoQuantityButNoMeteoCode = 4,
  StationHasActiveCorrelatedQuantityButNoStationCode = 5,
  OnlyOneCorrelatedAllowed = 6,
  OnlyOneMeteoAllowed = 7,
}
export class ExportPhycError extends Error {
type: ExportPhycErrorType;  
constructor( errorType: ExportPhycErrorType ) 
{    
super();
this.type = errorType;
}
}

In my service:

return throwError( new ExportPhycError( ExportPhycErrorType.OnlyOneMeteoAllowed ) ); 

In my controller:

obs.subscribe(
()=>{
//...
      }, (err) => {
        if (err instanceof ExportPhycError) {
          let msg;
          switch (err.type) {
            case ExportPhycErrorType.SensorCodeCanNotByEmpty:
              msg = 'Une grandeur hydrométrique doit avoir un code capteur valide si son export est activé.';
              break;
}
//...
}
});

This works well within an Angular application, as well as when an Angular application uses the generated Web Component. However, it does not work within an plain old JS app like V1. Indeed, the ‘err’ passed during the error handling is a callstack, and does not match ExportPhycError at all.

A replacement solution is to not use ExportPhycError and directly pass a ExportPhycErrorType.xxx (a number) to throwError(), and switch on the number value.

HttpClient and cold Observables

TL;DR: use obs.toPromise() with the Observable returned by the HttpClient library if you condiser the end-consumer will attach callbacks to the Promise before the API answers; otherwise, use .shareReplay(1) and subscribe directly a first time to the Observable.

HttpClient library, whether in NestJS or Angular, uses cold Observables.

A cold Observable will only “activate” (here: do the HTTP call) when it is subscribed to, for the simple reason that when it emits (here: when we receive response from the call), we want at least someone to listen, so that the result don’t go unheard straight to the void.

Yet, I find that in a lot of usecases involving API calls, the user which want to make the call will or will not deal with the result, depending on the situation (it could be updating a stock, which returns the resulting inventory, which we want to store somewhere or not). I’m talking about a situation where you’re developping a module to place calls, used by consumers services.

consumer <-> HTTP module <-> remote API

My first trial involved subscribing to the Observable directly in my HTTP module, before handing the Observable to the consumer.

const obs = httpClient.get(url);
obs.subscribe( () => {}, () => {} );
return obs;

Note that I provide two empty callbacks in .subscribe to avoid nuclear mole bomb (see previous post) ?

This works, but it works too much: if you observe API calls in the Network tab of your dev tools, you’ll see 2 API calls at once. Why that? Because the way it’s done, the cold Observable given by HttpClient will activate n times if you subscribe n times to it. So here, it’s fine if the consumer does not subscribe it, but possibly problematic if it does.

For that matter, there’s a nice Rxjs operator: .share(). (Btw, don’t let people who say it’s equivalent to .publish().refCount(): it’s not.)

const obs = httpClient.get(url).pipe( share() );
obs.subscribe( () => {}, () => {} );
return obs;

This operator will share the result of one call with all subscribers at the time of result coming: nice! But actually not enough. If the call is real fast, and the consumer takes time to subscribe, it will miss the first result and another call will be made (resulting again in two calls, which we really want to avoid).

So there’s another Rxjs operator for that: .shareReplay(1).

const obs = httpClient.get(url).pipe( shareReplay(1) );
obs.subscribe( () => {}, () => {} );
return obs;

This operator will share the last result it got (and HttpClient will only ever emit one result, so we’re fine with that) with any present or future subscribers. Awesome !

Now all that seems a bit far-fetched. There’s a way simpler solution, but note that it’s not appropriate if you think the consumer will attach callbacks later on, after the API has sent results (in which case, error-handling seems to be simply impossible). It’s to use the Observable .toPromise() function. Why that? Because due to the nature of the 2 structures (Observable and Promise), .toPromise() has to subscribe to the Observable, activating it in the same time, so we don’t have to take care of forcing the call anymore. Then, you handle a Promise to the consumer. This Promise will receive the first emission of the Observable (and there will be maximum one, so that’s fine), and keep it to show it to any callback the consumer will attach to .then().

const obs = httpClient.get(url);
return obs.toPromise();

Only caveat: if the API call gets into an error, and if the consumer does not handle error on the Promise before that, then you’re doomed, and the error is likely to bubble up and crash the process. At the time of writing, I found no way to handle this situation, except by interecepting the error with the Observable .catchError() operator and providing a default replacement value, which is probably not the best on the consumer side…

Debugging Typescript with Visual Studio Code and module aliasing

Note: from VS Code versions after 1.46.0, the internal javascript debugger has an auto-attach mode which seems sweet, and maybe make all the text below deprecated. Turn option “Debug: Toggle Auto Attach” on, and run a npm/yarn command: your breakpoints should be hit. More details here:
https://github.com/microsoft/vscode-js-debug#debug-nodejs-processes-in-the-terminal.

Our policy is to go more and more towards Javascript, for client-side applications as well as backoffice jobs, and with that, to embrace technologies such as NodeJS and language add-ons such as TypeScript. Frameworks like Angular (web apps) and NestJS (server-side apps) provide a full range of ready-to-use schematics and release-builds optimizations. Now we want to use an IDE which leverages those tools with powerful IntelliSense and debugging possibilities. IntelliJ IDEA comes as a choice of reference but is not for every budget, so we’ll give a go for Visual Code Studio. This post is about my findings on how to debug a NestJS app (NodeJS app following Angular policies) with VSCode.

Debugging NestJS apps

To avoid ridiculous import paths ‘../../../../adir/amodule’, module aliasing is used in the form of ‘@myalias/amodule’, improving readability and ease in moving code files. The aliases are set in the tsconfig.json file at the root of the project, needing a ‘baseDir’ attribute and a set of ‘paths’ (both to set under the ‘compilerOptions’). VSCode IntelliSense knows this trick perfectly and reacts accordingly, but when it comes to debugging, the default launch.json created by VSCode struggles at matching the paths, and quickly results in :

Debugger listening on ws://127.0.0.1:31189/821980d6-4e30-4360-8ac5-6b47af4faced
For help, see: https://nodejs.org/en/docs/inspectorDebugger attached.
Error: Cannot find module ‘@myalias/app.service’
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:582:15)
at Function.Module._load (internal/modules/cjs/loader.js:508:25)
at Module.require (internal/modules/cjs/loader.js:637:17)

The trick here is to indicate explicitly that the tsconfig-paths module must be used, just like it’s indicated in the default package.json ‘start’ script :
“start”: “ts-node -r tsconfig-paths/register src/main.ts”
In VSCode launch.json file, it’s done by :
“runtimeArgs”: [“–nolazy”, “-r”, “ts-node/register”, “-r”, “tsconfig-paths/register”]

To wrap it up, VSCode launch.json file should look like :

{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
“version”: “0.2.0”,
“configurations”: [
{
“type”: “node”,
“request”: “launch”,
“name”: “Debug Nest Framework”,
“args”: [“${workspaceFolder}/src/main.ts”],
“runtimeArgs”: [“–nolazy”, “-r”, “ts-node/register”, “-r”, “tsconfig-paths/register”],
“sourceMaps”: true,
“cwd”: “${workspaceRoot}”,
“protocol”: “inspector”
}
]
}

Debugging NestJS tests

It’s very very useful to be able to debug the tests written for the application – the same tests which will be automatically run within Continuous Integration. NestJS uses the Jest framework to write tests (close to the Jasmine framework), and here are the launch.json configuration to add to debug all tests or just the test currently shown in the editor :

{
    ...
    "configurations": [
        ...,
        {      
          "type": "node",
          "request": "launch",
          "name": "Debug test - all",
          "program": "${workspaceFolder}/node_modules/.bin/jest",
          "args": ["--runInBand"],
          "console": "integratedTerminal",
          "internalConsoleOptions": "neverOpen",
          "disableOptimisticBPs": true,
          "windows": {
            "program": "${workspaceFolder}/node_modules/jest/bin/jest",
          }
        },
        {
          "type": "node",
          "request": "launch",
          "name": "Debug test - current file",
          "program": "${workspaceFolder}/node_modules/.bin/jest",
          "args": [
            "${fileBasenameNoExtension}",
            "--config",
            "jest.config.js"
          ],
          "console": "integratedTerminal",
          "internalConsoleOptions": "neverOpen",
          "disableOptimisticBPs": true,
          "windows": {
            "program": "${workspaceFolder}/node_modules/jest/bin/jest",
          }
        }

    }
}

Byebye, old HttpModule

Welcome, HttpClientModule

HttpModule has been deprecated since Angular 4.3, but hadn’t been replaced yet. Now to prepare for the coming version 6 where it’s not supported anymore, we just got rid of it to welcome the newer HttpClientModule.

All objects from the “@angular/http” package are obsolete and have been replaced by objects from “@angular/common/http”. It was also the opportunity to have a good spring cleaning of those areas of code.

As we’re still receiving mixed types of server response (the version is still hybrid with legacy Symfony mechanisms), we indicate in the HttpClient calls options: observe = ‘response’, so the response we receive is not directly json-decoded, but returned as is.

Especially, the @ngx-translate/http-loader, which is responsible for loading the i18n translation files, has been upgraded from 0.1.0 to 2.0.1 to support the new HttpClient.

Tests

Tests were a bit verbose before when it got to Http. They are now simplified by the use and import in TestBed of the newer module:

import { HttpClientTestingModule } from ‘@angular/common/http/testing’;

Angular – Accessing services from the browser console

Though it is possible to access the properties of an Angular Component by selecting its corresponding DOM Element (in the WebTools DOM Explorer) and using the magical “ngprobe(0)” object in the console, it’s quite laborious and not really glamour.

For that reason comes to the rescue new service ConsoleUtilsService, which you will never use because it doesn’t provide any methods, but which is responsible for making some selected services directly available from the console. Everything provided that way will be packed in the global variable “sv“.

Example of direct use from the console:

sv.storage.getInstantEntity('Station', 10);

This feature is naturally delivered only in development environment and will not be accessible in production.

Upgrade to Angular 5.2 and Angular-CLI 1.7

It’s time to upgrade the application, and it goes with few changes to take in consideration !

For you to get a grasp at the new features of each release of Angular or its CLI, this blog is most interesting: http://blog.ninja-squad.com/tags.html#Angular 5-ref

Steps to do after pulling the new sources

Note: npm has been upgraded to 5.6.0 and yarn to 1.3.2.

  • mise à jour du package @angular/cli en global
npm update -g @angular/cli@1.7.1
  • mise à jour de typescript en global
npm update -g typescript
  • mise à jour des packages locaux (dans répertoire angular)
yarn install

Angular-CLI

Configuration has been updated for this new version. Note that test.ts has also received modifications.

Angular

The new command “ng update” of the latest CLI allows to update all Angular modules, here to version 5.2.6.

In addition, have been updated via “yarn upgrade”:

  • yarn upgrade @angular/material –latest
  • yarn upgrade localize-router –latest
  • yarn upgrade ng-dynamic-component –latest
  • yarn upgrade ng2-google-charts –latest
  • yarn upgrade codelyzer –latest
  • yarn upgrade @angular/cdk –latest
  • yarn upgrade @ngx-translate/core –latest
  • yarn upgrade typescript@~2.5.3
  • yarn upgrade @angular/cdk@5.2.2
  • yarn upgrade tslib@^1.0.0

The 3 last ones are for compatibility with used tools.

Note that because we upgraded Typescript, you might need to upgrade your IDE plugin for Typescript, for it to understand the lattest evolutions (especially the new options in tsconfig.json).

Netbeans user: this way !

New options have been added to the compiler:

  • fullTemplateTypeCheck: true
  • preserveWhitespaces: false