Archive for the 'Angular' Category

May 7th, 2017
8:05 pm
Angular 2 expressions containing observables cause null glitch on page display

Posted under Angular
Tags ,

The following expressions caused a brief glitch whereby null was displayed prior to the observable locationsCount emitting its value:-

<span text-capitalize>show all{{showAllActive ? ' ' + (locationsCount | async) : ''}}</span>

This makes sense as the observable with its async pipe, | async , which handles the observable, is part of a string expression. In other cases where the observable is e.g. a returned list, then you would just get an empty list with no entries. However in this case, Angular needed to evaluate and display the expression and so null was briefly displayed instead of the value of locationsCount.

The easiest way around this is to use a logical or which acts as a null coalescing operator in JavaScript/TypeScript, to replace the null with a suitable constant string:-

<span text-capitalize>show all{{showAllActive ? ' ' + (locationsCount | async)||' ' : ''}}</span>

The use of (locationsCount | async) || ‘ ‘  checks the first operand regardless of type, and if it is falsey, the second operand is taken. This is explained in this post here.

An alternative, a more complex solution which also worked in my case and may be interesting in other cases, is to concatenate the observable with another observable which emits a constant string using Observable.of(). The concat method emits all the values from each of the passed observables in turn, proceeding to the next one when an observable closes, as detailed in the RxJS api docs here. Therefore, the constant observable emits a value and completes/closes immediately which prevents the null glitch, followed by the locationsCount observable when it finally emits a value (which came from a mapped http api call):-

initial version without constant observable:-

this.locationsCount = this.locationsAutoCompleteService.getLocationsCount()
.map(count => {
let countString: string = this.formatLocationsCount(count);
return countString;
});

Alternative version with concatenated constant observable:-

this.locationsCount = Observable.of(' ').concat(
this.locationsAutoCompleteService.getLocationsCount()
.map(count => {
let countString: string = this.formatLocationsCount(count);
return countString;
})
);

No Comments »

May 1st, 2017
4:03 pm
Typescript duck typing error when casting a reference.

Posted under Angular & TypeScript
Tags , , ,

The following code fragment in a dao gave an error when casting the response json. The cause is not clear, but 2 code variations were tried:-

//API calls
getFeatures(): Observable<FeaturesSearchResult> {
return this.http.get(this.queryFeatures())
      // *** This version originally failed citing that property total_rows did not exist
.map(response => {return <FeaturesSearchResult>(response.json())});
}

I then tried using the “as” operator for the cast instead of the <> syntax. This worked. Strangely, right at the end I managed to get an example with the”<>” syntax working too, but the reason and differences were not at all clear.
However, I noted that the latter is also the preferred syntax now, as unlike the “<>” syntax it is also compatible with JSX/.tsx syntax (JSX is an embeddable React xml-like syntax which transforms into JavaScript)
See here for details on JSX/.tsx, and on the React wikipedia entry. The working code fragment follows:-

//API calls
getFeatures(): Observable<FeaturesSearchResult> {
return this.http.get(this.queryFeatures())// *** This version originally failed citing that property total_rows did not exist
      // *** This version worked by using the “as …” syntax for casting rather than <>
.map(response => {return response.json() as FeaturesSearchResult});
}

The full listing of the code for the working version (less imports for brevity) follows:-

features-dao.ts
@Injectable()
export class FeaturesDao {
constructor(private appConfig: AppConfig,
private http: Http) {}

//API calls
getFeatures(): Observable<FeaturesSearchResult> {
return this.http.get(this.queryFeatures())
.map(response => {return response.json() as FeaturesSearchResult});
}

//API query definitions
queryFeatures(): string {
return `${this.appConfig.apiBase}_design/places/_view/featuresByOrdinal?include_docs=true`;
}

}
export interface FeaturesSearchResult extends CouchDBResult<FeaturesSearchResultRow> {}
export interface FeaturesSearchResultRow extends CouchDBResultRow<number[], any, FeatureDoc> {}
couchdb-result.ts
export interface CouchDBResult<R extends CouchDBResultRow<any,any,any>> {
total_rows: number;
offset: number;
rows: R[];
}

export interface CouchDBResultRow<K,V,D> {
id: string;
key: K;
value: V;
doc?: D;
}
feature-doc.ts
export interface FeatureDoc extends CouchDBDoc {
ordinal: number;
name: string;
description: string;
searchable: boolean;
rateable: boolean;
}

No Comments »

April 27th, 2017
4:15 pm
Angular 2 – Reactive Programming/Observables with multiple HTTP API calls

Posted under Angular
Tags , ,

A common pattern used in service layers is to make calls to an underlying repository or API, and then map the results to domain layer objects via mappers/convertors. Often, it may be necessary to make multiple repository calls and then combine them in the mapping phase to create the resulting domain object graph which is then returned. With traditional synchronous calls, e.g. to an underlying JPA repository, this is a straightforward exercise.

However, Angular 2 by default makes HTTP api call results available asynchronously as Observables, which poses an immediate issue with how to combine the results. I certainly did not want to embed Observables as properties within my domain objects, as I wanted the domain objects as POTOs (Plain Old Typescript Objects) and did not want to couple them/pollute them with Observables.

Handling the above pattern is in fact straightforward, but does involve a paradigm shift compared with imperative OO style programming as you need to get your head around reactive programming, in this case ReactiveX/RxJS which Angular uses.

  • In this case we are using RxJs Observables for which the api is documented here.
  • The available operators for use with Observables are documented here.
  • ReactiveX/RxJs makes extensive use of Marble diagrams an example of which may be found here.
  • Another useful introduction site to RxJS may be found here.

Note that it is possible to convert the observables to promises and use promise chaining to achieve similar results. However, I decided to stick with observables as the majority of comments online such as this post indicate that observables can do all that promises can, and more, and they are the default/chosen direction for Angular 2. It felt counter intuitive to have to convert the observables to promises all the time when there was no real need – whilst  and to do so appeared to go against the chosen way forward for Angular 2.

My first prototype needed to combine 2 API calls, and for this I used the combineLatest instance method. (This is called on one Observable and allows one or more other observables to be combined with it. There is also a static method available on the Observable class.) I found this solution in this StackOverflow post. These methods do do the following :-

  1. Combine 2 or more observables and emits a single output observable
  2. Before the output observable emits an item, all of the input observables must have emitted at least one item
  3. Once all the observables have emitted something, the output emits an output item.
  4. It continues to emit items whenever any of the input observables emit another item.
  5. Note that in our case, multiple emits for an observable do not occur. Whilst we are using observables, each one will only emit a single output item in our case, when the HTTP call completes.
  6. Note that per the example code below, I use lambdas (=> operator) routinely. The lambda used on the return of combineLatest will be called when the output observable emits an item (i.e. when both the HTTP calls have completed). The other lambdas are just used for standard synchronous filter/map/reduce operations on the arrays – these are standard in Javascript and hence Typescript, so they are not asynchronous/using observables.

For the requirement of my original pattern, i.e. make a number of repository calls, then map them all to a domain object graph, the above approach works fine. Note that there are a number of other operators on observables which are quite nuanced and this example just scratches the surface of Reactive programming, but in my experience the above is a very common pattern. Some of the other operators/methods distinguish between emits on an observable and the observable actually closing. As in the above case we just get one emit from each, we don’t need to get into that issue.

An outline example from my prototype code follows (imports and domain objects omitted for clarity). Note that it is just a prototype and a number of issues have not been properly addressed yet (such as externalisation of configuration data such as API urls):-

places-service.ts

@Injectable()
export class PlacesService {

static apiBase: string = 'http://localhost:5984/places-guide/';
static apiGetByLocationName: string = `${PlacesService.apiBase}_design/places/_view/placesByLocationName?include_docs=true`;
static apiGetFeatures: string = `${PlacesService.apiBase}_design/places/_view/featuresByOrdinal?include_docs=true`;

constructor(private http: Http, private featureMapper: FeatureMapper, private placeMapper: PlaceMapper) {}

fetch(): Observable<Place[]> {
return this.http.get(PlacesService.apiGetByLocationName)
 
       //The lambda here is called when the output observable emits an item (which only happens once when both HTTP calls complete).
.combineLatest(this.http.get(PlacesService.apiGetFeatures), (placesRows, featuresRows) => {
let features: Feature[] = this.featureMapper.mapAll(featuresRows.json().rows);
let places: Place[] = this.placeMapper.mapAll(placesRows.json().rows, features, PlacesService.apiBase);
return places;
});
}
}
 
place-mapper.ts
@Injectable()
export class PlaceMapper {

constructor(private placeFeaturesMapper: PlaceFeaturesMapper) {};

public map(row: any, placeFeatures: PlaceFeatures, apiBase: string): Place {
let place: Place = Place.create(
row.id,
row.doc.name,
row.doc.strapline,
row.doc.description,
Address.create(
row.doc.address.address1,
row.doc.address.locality,
row.doc.address.postTown,
row.doc.address.postCode),
row.doc.lat,
row.doc.long,
row.doc.website,
row.doc.phone,
row.doc.email,
placeFeatures,
apiBase + row.doc._id + "/thumbnail.jpg",
apiBase + row.doc._id + "/detail.jpg"
);
return place;
}

public mapAll(rows: any[], features: Feature[], apiBase: string){
let placesPlaceFeaturesMap: {[key: string]: PlaceFeatures } = this.createPlacesPlaceFeaturesMap(rows, features);
return rows
 
      //this is standard array filtering and mapping with lambdas
.filter(row => row.doc.type == 'place')
.map(row => this.map(row, placesPlaceFeaturesMap[row.doc.placeFeaturesId], apiBase));
}

createPlacesPlaceFeaturesMap(rows: any[], features: Feature[]): {[key: string]: PlaceFeatures } {
let placesPlaceFeaturesMap: {[key: string]: PlaceFeatures } =
rows.filter(row => row.doc.type == 'placeFeatures')
        //This is a standard array lambda. Reduce is used as we are populating a single return object.
        .reduce((map, row) => {
map[row.doc._id] = this.placeFeaturesMapper.map(row, features);
return map;
 
        //Note that the {} is the seed/initial value for the reduce, where we initialise the empty output object
}, {}
      );
return placesPlaceFeaturesMap;
}
}
place-features-mapper.ts
 
@Injectable()
export cl

ass PlaceFeaturesMapper {

public map(row: any, features: Feature[]): PlaceFeatures {
let list: PlaceFeature[] = this.buildList(row.doc._id, row.doc.placeFeatures, features );
let map: {[key: string]: PlaceFeature} = this.buildMap(list);
return PlaceFeatures.create(row.doc._id, list, map, features);
}

buildList(placeFeaturesId: string,
rawPlaceFeatures: {[key: string]: {rating: number} },
features: Feature[]): PlaceFeature[] {
let placeFeatures: PlaceFeature[] = features
.filter(feature => rawPlaceFeatures[feature.id])
.map(feature => PlaceFeature.create(
placeFeaturesId,
feature.id,
feature.ordinal,
feature.name,
feature.description,
feature.searchable,
feature.rateable,
rawPlaceFeatures[feature.id].rating)
);
return placeFeatures;
}

buildMap(placeFeatures: PlaceFeature[]): {[key: string]: PlaceFeature} {
let placeFeaturesMap: {[key: string]: PlaceFeature} =
placeFeatures.reduce((map, placeFeature) => {
map[placeFeature.featureId] = placeFeature;
return map;
}, {});
return placeFeaturesMap;
}
}

 
feature-mapper.ts
@Injectable()
export class FeatureMapper extends AbstractMapper<any, Feature> {

public map(row: any): Feature {
let feature: Feature = Feature.create(
row.id,
row.doc.ordinal,
row.doc.name,
row.doc.description,
row.doc.searchable,
row.doc.rateable);
return feature;
}
}
 
abstract-mapper.ts
export abstract class AbstractMapper<R,T> {
public abstract map(row: R): T;

public mapAll(rows: R[]): T[] {
return rows.map(row => { return this.map(row);});
}
}
 

No Comments »

April 22nd, 2017
2:54 pm
Declaring Providers for Dependency Injection

Posted under Angular
Tags ,

Providers need to be declared as they ‘provide’ the objects to be injected – in many cases this will be a singleton reused whenever injected (much like a normal Spring bean in Java).

To be visible everywhere in the entire application, they should be declared in the Providers list in the root @NgModule  (e.g. app.module.ts).

However if not used globally, they can be for example registered in a component whereupon they will be visible to that component and its children only.

This angular doc here discusses dependency injection and where to register providers.

This angular doc here is the NgModule faq and also discusses the issue. It points out that registering the providers in the root AppModule (@NgModule as above) is the normal use case, and other cases are rare. In particular it makes the following points:-

Should I add application-wide providers to the root AppModule or the root AppComponent?

Register application-wide providers in the root AppModule, not in the AppComponent.

Lazy-loaded modules and their components can inject AppModule services; they can’t inject AppComponent services.

Register a service in AppComponent providers only if the service must be hidden from components outside the AppComponent tree. This is a rare use case.

More generally, prefer registering providers in modules to registering in components.

Discussion

Angular registers all startup module providers with the application root injector. The services created from root injector providers are available to the entire application. They are application-scoped.

Certain services (such as the Router) only work when registered in the application root injector.

By contrast, Angular registers AppComponent providers with the AppComponent‘s own injector. AppComponent services are available only to that component and its component tree. They are component-scoped.

The AppComponent‘s injector is a child of the root injector, one down in the injector hierarchy. For applications that don’t use the router, that’s almost the entire application. But for routed applications, "almost" isn’t good enough.

AppComponent services don’t exist at the root level where routing operates. Lazy-loaded modules can’t reach them. In the NgModule page sample applications, if you had registered UserService in the AppComponent, the HeroComponent couldn’t inject it. The application would fail the moment a user navigated to "Heroes".

Should I add other providers to a module or a component?

In general, prefer registering feature-specific providers in modules (@NgModule.providers) to registering in components (@Component.providers).

Register a provider with a component when you must limit the scope of a service instance to that component and its component tree. Apply the same reasoning to registering a provider with a directive.

For example, a hero editing component that needs a private copy of a caching hero service should register the HeroService with the HeroEditorComponent. Then each new instance of the HeroEditorComponent gets its own cached service instance. The changes that editor makes to heroes in its service don’t touch the hero instances elsewhere in the application.

Always register application-wide services with the root AppModule, not the root AppComponent.

No Comments »

March 3rd, 2017
1:37 pm
Various DI related error categories in Angular 2

Posted under Angular
Tags ,

This post is a common point to document basic errors of the above kind.

1/ Karma tests fail to run giving the following kind of error:-

‘places-list’ is not a known element:
1. If ‘places-list’ is an Angular component, then verify that it is part of this module.
2. If ‘places-list’ is a Web Component then add “CUSTOM_ELEMENTS_SCHEMA” to the ‘@NgModule.schemas’ of this component to suppress this message. (”
<div> Places results:- </div>

[ERROR ->]<places-list></places-list>

In this case the application ran but the tests failed as above, following the addition of a new component, PlacesList, which was added via ng new component, and used in the root AppComponent.

This StackOverflow post details the issue and the solution. In my case the new component needed adding to the declarations list in TestBed.configureTestingModule in app.component.spec.ts as the component was a required dependency. I had added it (or ng generate may have, I cannot recall) to the @NgModule declarations list in app.module.ts, which enabled the application to run. However the test bed needed it too.

 

2/ I hit a similar issue with the PlacesService. I was getting this error on the tests:

Chrome 56.0.2924 (Windows 7 0.0.0) PlacesListComponent should create FAILED
Error: No provider for PlacesService!
Error: DI Error

I used 2 different ways around this problem.

a/ I added PlacesService as a provider in  places-list.component.spec.ts – this enabled both the tests and the app to work.

beforeEach(async(() => {
  TestBed.configureTestingModule({
    declarations: [ PlacesListComponent ],
    providers: [PlacesService]
  })
  .compileComponents();
}));

b/ Alternatively, I could also add PlacesService as a provider in both app.component.ts (i.e. at the top level) and the test definition,  places-list-component.spec.ts

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  providers: [PlacesService]
})
beforeEach(async(() => {
  TestBed.configureTestingModule({
    declarations: [ PlacesListComponent ],
    providers: [PlacesService]
  })
  .compileComponents();
}));

 

Whilst b/ defines the provider in 2 places, from basic knowledge this feels better as in a/ the provider is defined in the component that uses the service which feels almost as closely coupled as if I was not using DI at all.

Interestingly, when I removed the PlacesService as a provider from app.components.ts and added it to the @NgModule as a provider, in app.module.ts, this failed similarly. This was strange as I expected app.module.ts to declare the provider globally (expect perhaps for the testbeds).

This needs further looking into and understanding of the DI concepts – on the face of it, the providers (which are the actual lists of components to be injected) should be as decoupled as possible from the classes where they are used. At the moment, a lot of what I am seeing looks far too incestuous, coming from a background in Java/Spring where Spring is entirely external and responsible for the ‘provider list’.

No Comments »

March 3rd, 2017
10:23 am
Using <ng-container> as a dummy tag to simplify markup when directives are used

Posted under Angular
Tags ,

Sometimes you need an element to hang e.g. an *ngIf directive on, but you don’t want the element to appear in the markup.

In the following example, we end up with an extra unwanted <div> level just because we needed to hang the *ngIf somewhere (noting that it is not permissible to have the *ngIf on the same element as the *ngFor).

<div *ngFor="let place of places.rows">
  <div *ngIf="place.doc.type == 'place'">
    <span>{{place.doc.name}}, </span>
    <span>{{place.doc.strapline}}</span>
  </div>
</div>

Instead of a <div> we can use <ng-container>. This does not appear as an element in the markup (but does appear as a comment only) :-

<div *ngFor="let place of places.rows">
  <ng-container *ngIf="place.doc.type == 'place'">
    <span>{{place.doc.name}}, </span>
    <span>{{place.doc.strapline}}</span>
  </ng-container>
</div>

This is analagous to the <th:block> dummy element in Thymeleaf, which does exactly the same thing.

This StackOverflow post details this issue. This alternative post mentions the use of ng-if-start and ng-if-end, but notes that these are undocumented in Angular 2 so may not be fully supported.

For a related issue where nested loops are in use causing a similar problem, this post details the use of ng-repeat-start and ng-repeat-end as an alternative solution.

Note however that ng-repeat-start/ng-repeat-end only works for Angular 1.

No Comments »

March 1st, 2017
1:31 pm
Configuring Angular 2 with Webstorm for development/debugging

Posted under Angular
Tags

In contrast with the pain of all my previous attempts at getting debugging working using Angular 2 eclipse, webclipse, and vs code, this was thankfully almost a non event!

It has confirmed Webstorm as my preferred IDE going forward.

The aim of this exercise was simply to be able to debug an application generated using angular-cli – i.e. to put a breakpoint on the initial generated code and have it obeyed.

I went through the following steps:-

  1. Installed Node, npm and angular-cli as detailed on the angular2 quickstart page
  2. Downloaded and installed the current version of Webstorm (as a trial) from here
  3. Visited this page re setting up angular-cli for Webstorm and made sure all the actions were/had been done
  4. Opened an existing angular-cli generated project.
  5. Visited this jetbrains blog post re setting up for debugging.
  6. The above blog post points out that in the early access preview version of Webstorm 2017.1, no additional configuration was needed other than adding a run configuration using Run – Edit configurations… – Add – JavaScript Debug and entering the url (http://localhost:4200/). This was such a contrast with the previous pain of trying to get vs code working that I could not resist giving the EAP a try, so installed this version (which is available for download here, and is allowed as part of trial use).
  7. Note that Webstorm is Java based (a fork of IntelliJ) so needs a JVM. The 2016.3 release which I initially tried installed its own Java 8 by default. However, for the EAP I had to tick the box on the initial wizard screen to install java, or else it used whatever jre was available globally. As I use various versions, I run Webstorm with its own jre.
  8. Debugging worked exactly as stated. Initially, Webstorm complained that it needed its own debug plugin for chrome, and helpfully provided the relevant link to the chrome store in the message. I was able to install the plugin directly, and Webstorm then immediately started working with no further ado.
  9. To commence debugging it is necessary to start the application. This can be done outside Webstorm in a command window by entering npm start or ng serve.
  10. You can also set up a run configuration to allow starting within webstorm. To do this visit run/Edit Configurations. Press + to add a new configuration and select npm. Give the configuration a suitable name and ensure that the package.json field points to your package.json file for the project. Pick start for the desired command. The Node interpreter for the project should be already set up from the initial node/Webstorm installation – in my case this was E:\Program Files\nodejs\node.exe. Having done this you can run with this configuration and the project will build if required and start.
  11. Note that when using vs code, it was necessary to start chrome with its debug mode/debug port enabled, which required a shutdown of all chrome instances and starting using specific command line flags as detailed in my previous post here. This was a nuisance to have to do each time. However, with Webstorm, none of this is needed. To contrast the two approaches, vs code uses a vs code chrome plugin which talks to chrome using chrome’s standard debugging mechanism/debug port. However, for Webstorm, no plugin is needed at the Webstorm end, but it is using its own custom chrome plugin in chrome for debugging. This does not need any special startup for chrome – it just works.
  12. When talking to CouchDB, I hit CORS issues and initially installed a Chrome CORS plugin to get around this. Later I just enabled CORS in CouchDB which is simpler and more convenient, as detailed here.

Following this I was able to plant a breakpoint, modify a couple of assigned properties in the code, and continue execution, with the results of the changed assignments visible in the browser.

As an additional bonus, I tried the existing Tour of Heroes tutorial (which uses systemjs rather than webpack) under debug, and this also worked perfectly.

No Comments »

March 1st, 2017
12:05 pm
Angular 2– Issues debugging default angular-cli/webpack generated application

Posted under Angular
Tags , , ,

Further to getting the Tour of Heroes tutorial (which is systemjs based) debugging correctly in vs code (see here), I moved on to creating a new app via angular-cli as a basis for moving forward.

The point about angular-cli is that it uses webpack as its packaging tool, which is better than existing packagers for breaking down enterprise level applications. It mandates a standard for project file structure which was lacking in the past in angular, and creates everything according to that standard. It also allows additions of components etc. which will also conform to the same structure.

Previously I had settled on using vs code, as I had issues with all the previous IDEs I had tried (eclipse with angular 2 eclipse, webclipse) as per here).

I tried the following steps:-

  1. create a new angular project via ng new
  2. build/start it via npm start
  3. run chrome in debug mode via the following shortcut "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" –remote-debugging-port=9222
  4. debug in vs code using a suitable (clearly not as in the end I could not get it to work) launch configuration

The problem is that vs code could not map the .ts source to the .js. via the sourcemap, which is provided to do the mapping.
When adding a breakpoint, the following error occurs:-
“Breakpoint ignored because generated code not found”.

As vs code is widely used, there were a number of posts about this issue as follows :-

https://github.com/angular/angular-cli/issues/2453
https://github.com/angular/angular-cli/issues/1223
https://github.com/angular/angular-cli/issues/4526
https://github.com/angular/angular-cli/issues/2491

Unfortunately I could not resolve the problem via any of these.

A key point that these posts do not clarify on is that when starting with npm start or ng serve, any generated js file bundles (e.g. main.bundle.js) which are bundled js files under <project>/dist/) are deleted along with the <project>/dist directory, and the generated js is entirely served from memory. The IDE therefore has to get this js via a url, so all the discussion about tweaking the sourceMapPathOverrides to things like:-

"webpack:///*": "/*"
"webpack:///C:*":"C:/*" (for windows – substitute correct drive letter is the theory)

…seem to miss the point if they are aiming at target directories for the js. Of course, they may refer to the need to derive map keys for the sourcemap which would make sense if the sourcemap contains urls as values to return the generated js, but this is not made clear.
Either way, I could not get any of this to work in vs code and could not get a working breakpoint on the initial line of code that assigns the "app works" string.

In the end I dumped using vs code and gave Webstorm a try. This was immediately successful with almost no configuration needed – details as per this post.

No Comments »

February 23rd, 2017
1:03 pm
Angular2 Tour of Heroes Tutorial – Issues and Learning Points

Posted under Angular
Tags ,

Whilst adding the changes to for 2 way data binding by adding the new file src/app/app.module.ts as detailed here, VS Code reported the following errors:-

[ts] Cannot find module ‘@angular/core’. (1,24)
[ts] Cannot find module ‘@angular/platform-browser’. (2,31)
[ts] Cannot find module ‘@angular/forms’. (3,31)

The compilation was not affected and the app worked.

The notes state that you should add it to the NgModuledecorator’s imports array, however this decorator and indeed the above file were not even present in the project.

Having looked into it, it appears that the available git repos do not match the tutorial notes! Annoying! There might be a VS Code issue but it looks likely that it is a repo issue.

The standard repo is here. This appears to already have the changes listed above for  app.module.ts, so is not suitable for starting the tutorial.

The version I used from Rob Lourens, which contains the launch.json configurations for VS Code, is here. This is different again, and still does not match the tutorial start!

No Comments »

February 22nd, 2017
10:28 pm
Angular2 Tour of Heroes Tutorial – IDE/Debugging Setup

Posted under Angular
Tags , ,

The aim of this was to get the tutorial up and running in a suitable IDE, such that I could debug and step through the code whilst understanding it. The tutorial site is here. The standard repository on Git is here.

A number of different IDE options where tried, and most of them hit problems and were therefore discounted. The options tried were as follows:-

Eclipse with the Angular 2 Eclipse plugin

The following links document how to set this up:-

http://fcorti.com/2016/08/22/angular-2-eclipse-how-to/

http://stackoverflow.com/questions/35890887/how-to-get-angular2-to-work-in-eclipse-with-typescript

When loading the Tour of Heroes tutorial, I tried to import it as a file system project as the cloned Git repo was not an ecplipse project.

The problems I hit with this were as follows:-

  1. After importing into eclipse, there were compile errors on import and export statements in rollup.js.
  2. The core problem appeared to be eclipse bug 496348 which was listed as resolved but judging by the comments at the end was still a problem.
  3. I tried various ways around this, such as upgrading to a dev release of eclipse Neon, trying a prerelease of eclipse Oxygen, and upgrading the eclipse plugins. None of these solved the problem.
  4. As this was not a very commonly used IDE, there was not that much in the way of online help. In particular, no-one appeared to have posted online about getting the Tour of Heroes demo working with it. Therefore, support etc. going forward would likely be a problem.

Webclipse

  1. This is a paid for eclipse plugin, also available as a separate IDE on its own called Angular IDE, detailed   here.
  2. I tried this also with Eclipse Neon and Oxygen, and received similar Typscript related errors that I could not eliminate when trying to load the Tour of Heroes demo. I therefore dumped this too.
  3. Whilst I did not try IntelliJ/Webstorm at this stage, which was the Jetbrains/IntelliJ paid for option, one Stack Overflow comment (which I now cannot find) cited that there were still Typescript issues with it, even in IntelliJ. (With hindsight, I wish I had, as in the end I have standardising on it as it works both for this tutorial, which uses systemjs, and for applications generated via angular-cli which use webpack. Details on this stage of the journey here and here).

Visual Studio Code

  1. This is the IDE I settled on at this stage. Whilst it meant learning another IDE, it had a number of overriding benefits.
  2. Basically it just works with no problems and no wacky Typescript errors! The basic point here is that Microsoft originated Typescript, and they are the authors of VS Code, so unsurprisingly it has the best compatibility.
  3. As it is probably the most commonly used IDE for Angular, unlike with the other IDE solutions, there are many examples online for it, including for the Tour of Heroes tutorial, which needs a custom launch.js file for running the demo.

 

The setup steps for it were as follows :-

  1. Follow the initial steps including installation of the latest Node.js and npm from the Angular tutorial site here
  2. Rob Lourens has forked the Tour of Heroes git repo here, with a custom launch.js file for launching in VS code. Clone that git repo and follow his instructions.
  3. Note that this uses the VS Code debugger for Chrome extension, in order to allow browser run angular JS code to be debugged inside VS Code instead of in the Browser.
  4. In order to get this working, I had to start the app from the command line first via npm i (to build) then npm start.
  5. Also, initially I could not get VS code to connect to Chrome, either by running up a new chrome via Rob’s launch.js configuration “Launch localhost with sourcemaps”, or by connecting to an existing chrome using “Attach with sourcemaps”. The issue was that Chrome needed starting with a command line option to allow debug connections via its debug port. This is detailed here (comment by auchenberg) – the command line is C:\Program Files (x86)\Google\Chrome\Application\chrome.exe –remote-debugging-port=9222
  6. Once the above was done, I could connect from VS code provided I tried to attach to the existing chrome using  “Attach with sourcemaps” – otherwise, a new chrome was started which did not allow debug connections!
  7. The steps needed were therefore 1/ run (having built) using npm-start, 2/ run up a debug chrome, then 3/ click on the debug icon in VS code, select the  “Attach with sourcemaps” dropdown launch.js option, then hit the green go button just to the left of it. This successfully fired up the demo.
  8. Note that I was able to breakpoint in the code using VS code either on the Typscript (.ts) files or the equivalent transpiled .js files. It appears that the compiled code is interspersed in the same folders as the Typescript, which does not seem cool at all – something to look into. I would expect that the build artifact code would be separate as in Java.

No Comments »