Archive for 2017

May 8th, 2017
3:55 pm
How to refer to child component instances from an Angular component class

Posted under Angular
Tags ,

With Angular, the component objects are automatically created and associated with their corresponding elements in the template.

This raises the question then – if you want to refer to a child object from a parent component, how do you do it? There may be multiple child components of the same time in the parent component, so how do you get a reference to a specific one?

As a contrast, when using JSF for example to refer to child component code, the parent managed bean (= component object in Angular) is actually responsible for declaring the managed bean objects for its children. On the page, the child component element will typically have a specific e.g. controller attribute where the managed bean for that child is passed in, e.g. as <child controller=#{controller.child}>…  where controller.child  refers to the child property of the parent managed bean. In this way, unlike Angular, the object hierarchy is explicitly declared in the code.

In Angular, there are a number  of ways to do this, but in the end they all come down to using reference information from a particular template element to direct which object is required.

It is instructive to read the whole section on Angular template syntax in the Angular docs, which includes all the binding techniques.

1/ Passing an element reference in a method call from the template

<ion-auto-complete id="location-search" #locationSearch [dataProvider]="locationsAutoCompleteService"
(itemSelected)="onItemClicked($event, locationSearch)"></ion-auto-complete>

In this case, (itemSelected)="onItemClicked($event, locationSearch)" is passing the element reference #locationSearch as the second argument to onItemClicked. This passes the reference to the component object for  <ion-auto-complete>. (Note that in this case the first argument, $event, is the actual location object that was clicked in an autocomplete list).

2/ Using the @ViewChild decorator in the parent class, passing it a child reference used in the template

export class AutoCompleteComponent {

@Input() public dataProvider: any;
@Output() public itemSelected: EventEmitter<any>;
@ViewChild(Searchbar) searchBar: Searchbar;

In this case, the component only contains a single searchbar, so using a class reference is not ambiguous. If there were multiples, the first one would be taken. You can inject references to multiple children via @ViewChildren if there is more than one present – this gives you access to an array of them.

Where you want to use a reference to a specific element, you can use @ViewChild with an element reference, e.g. in 1/ above you would use  #locationSearch to inject a referent to the <ion-auto-complete #locationSearch > element as follows:-

@ViewChild(‘#locationSearch’) searchBar: Searchbar;

3/ Another related technique is to make a method call in the template e.g. in an event call, using an element reference to another element in the component. This is detailed here. Note that <child-component #f contains the #f element reference, and the inc() method on the #f element is called from the button click event using <button (click)=”f.inc()”>

@Component({
    selector: 'child-component',
    inputs: ['bar'],
    template: `"{{ bar }}" in child, counter  {{ n }}`
})
class ChildComponent{
    constructor () {
        this.n = 0;
    }
    inc () {
        this.n++;
    }
}

@Component({
    selector: 'my-app',
    template: `
        <child-component #f [bar]="bar"></child-component><br>
        <button (click)="f.inc()">call child func</button>
        <button (click)="bar = 'different'">change parent var</button>
    `,
    directives: [ChildComponent]
})
class AppComponent {
    constructor () {
        this.bar = 'parent var';
    }
}

bootstrap(AppComponent);  

There is a working plunker for the above example here.

No Comments »

May 8th, 2017
12:50 pm
Tail utility for Windows

Posted under Windows & Windows 7
Tags

I have used Baretail which may be found here. It has a number of features but crucially allows you to a follow additions to a log file, as you would with tail –f on linux.

Baretail is an improved version of Wintail which is also from Bare Metal Software.

No Comments »

May 8th, 2017
12:41 pm
CouchDB continually fills the log with Shard/disk loading/database errors.

Posted under CouchDB
Tags ,

In my case the log had grown to nearly 1GB, and there does not appear to be any log rotation set up by default!

It turns out that this will occur if you have not configured the node after installation – either for single node operation, or as a cluster.

This can easily be done via the configuration option in Fauxton, and at the same time it allows you to set credentials for the admin account.

Doing this prevented the log spamming and log growth was then minimal.

This post here discusses the issue.

No Comments »

May 8th, 2017
12:36 pm
Angular 2 -Difference between @Input and inputs in Angular2 Components?

Posted under Angular
Tags ,

This post discusses the alternative way of specifying input parameters for angular 2.

This can be done using either:-

@Component{(
    selector: "my-component",
    inputs: ["attr"]
)}
export class MyComponent {
}

or alternatively:-

@Component{(
    selector: "my-component"
)}
export class MyComponent {
    @Input()
    public attr: any;
}

No Comments »

May 8th, 2017
12:15 pm
Ionic error on startup – ionic Error: ENOENT: no such file or directory

Posted under Ionic
Tags , ,

The cause of this is not immediately obvious, but it blocked startup via ionic serve – the error continues to cite a template error of some kind.

The actual issue is an invalid file path on the templateUrl attribute of the @Component({ decorator of the relevant component mentioned in the error. I found a variety of different file paths used – some with no path and just the filename, some with “./” on the front, and the offending one had a prefix of “src/” which caused the failure.

Just correcting the file path on the attribute fixes the problem.

No Comments »

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
8:09 pm
Webstorm 2017.1 update failure due to Kaspersky false detections

Posted under Ionic & Kaspersky & WebStorm
Tags , ,

1/ I took the latest 2017.1 upgrade when offered by Webstorm. This upgrade results in the following version:-

WebStorm 2017.1.2
Build #WS-171.4249.40, built on April 25, 2017
Licensed to Steve Woodley
You have a perpetual fallback license for this version
Subscription is active until April 9, 2018
JRE: 1.8.0_112-release-736-b21 x86
JVM: OpenJDK Server VM by JetBrains s.r.o
Windows 7 6.1

During the upgrade, Kaspersky complained that E:\Program Files (x86)\JetBrains\WebStorm 2017.1\jre32\bin\unpack200.exe contained a trojan malware virus. This caused the upgrade to fail.

I checked this online and discovered that Webstorm often gets cited as giving false malware positives, all of which are false. I was happy to allow this to proceed as a Kaspersky exception.

This Kaspersky forum post gives details on what to do (including disabling file antivirus). It then says to add a file exception rule for the file – the instructions for doing this may be found here. Whilst the link is for a 2014 version of Kaspersky, it is similar enough to be correct with the current version as at 2017, with just a few textual prompt/description differences. Note that I added the full file name, but did not enter a value for the file/folder name mask ref the “virus encyclopedia” quoted in the instructions. (I wouldn’t have known what to enter there anyway!). These 2 fields are an either/or – this is not quite made clear in the UI prompts, and is not enforced e.g. via a radio button choice or similar.

Once I did this I checked for updates in Webstorm, retried the new update, and it completed OK.

 

2/ Having done this, I restarted Webstorm and reloaded my Ionic project. Whilst loading the project, Kaspersky complained that “Server-side JavaScript run by a program with restrictions is attempting to create an embedded key or parameter in a protected registry key”

Effectively, Node.js was attempting to create a new subkey in the registry under TCP/IP Settings (not sure why it would do this, but I was confident that this was not Malware). Whilst Node.js was a trusted program, it was doing  it as instructed via an ionic batch script.

I tried to keep allowing the action but this did not work. The solution in the end came when I noticed that the component hierarchy mentioned in the Kaspersky error consisted of a series of green hyperlinks for each level. I was able to click on the green links, and this immediately took me to a Kaspersky settings screen for that component. I was able to see that the script component calling Node.js did not have permissions to create a security registry key. I was able to easily click on the relevant “?” entries to create a security registry subkey, and set the option to Yes.

So in all a plus for Kaspersky in making it easy to fix, but a minus as I had to work it out for myself and had not been able to find any online or other help on it.

Note for the future – any errors etc. from Kaspersky may have clickable links in them which take you to a place where you can add a rule to stop the error – this is always worth looking into. In my case the clickable links were not underlined but were green in colour.

Once I had done this, restarting Webstorm and opening the project went without any errors from Kaspersky.

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 26th, 2017
8:21 am
Ionic 2 Super Starter template application – Cannot find module "ionic-native"

Posted under Ionic
Tags , ,

This template is noteworthy as it contains a number of simple ready made use cases/patterns such as swipe gesture support, master/detail pages, searching, and simple entry forms.
As per this post, a tutorial starter app with the above template should be created as follows:-

ionic start my-super-starter-app super –v2
npm install

When I tried to run this I got the following error trace:-

Runtime Error

Cannot find module "ionic-native"

Stack

Error: Cannot find module "ionic-native"
at g (http://localhost:8100/build/polyfills.js:3:7133)
at Object.<anonymous> (http://localhost:8100/build/main.js:108352:7)
at __webpack_require__ (http://localhost:8100/build/main.js:20:30)
at Object.<anonymous> (http://localhost:8100/build/main.js:82204:73)
at __webpack_require__ (http://localhost:8100/build/main.js:20:30)
at Object.<anonymous> (http://localhost:8100/build/main.js:120594:70)
at __webpack_require__ (http://localhost:8100/build/main.js:20:30)
at http://localhost:8100/build/main.js:66:18 at http://localhost:8100/build/main.js:69:10

Ionic Framework: 3.0.1
Ionic Native: ^3.5.0
Ionic App Scripts: 1.3.0
Angular Core: 4.0.0
Angular Compiler CLI: 4.0.0
Node: 7.5.0
OS Platform: Windows 7
Navigator Platform: Win3
User Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36

This Ionic forum post documents the problem, which appears to be because the starter template expects A version of ionic-native lower than 3 (mine was 3.5.0 as above). As per the post, I tried the following:-

  1. Edited my package.json and changed the ionic-native version to 2.9.0
  2. Entered npm install ionic-native –save

This did not work, it failed with a similar error.

Fortunately the post links to an updated template as the solution, in github here.

This can be cloned and used instead of entering ionic start my-super-starter-app super –v2

I tried the fixed version and it worked correctly. Note ref the comments in the various posts that it was not necessary to install ionic-native explicitly via npm install ionic-native –save

No Comments »