Google Analytics in eine Angular App einbinden

Um Google Analytics in eine Angular App einzubinden muss man genau zwei Dinge tun:

  • Den Google Analytics Code im body-Bereich der index.html Datei einbinden UND die Zeile ga(’send‘, ‚pageview‘); herauslöschen (diese muss manuell gesendet werden)
  • In der root-Komponente auf Änderungen im Router lauschen um dann entsprechend ga(’send‘, ‚pageview‘); aufzurufen

Lauschen auf Änderungen im Router:

    ngOnInit() {
        this.routerEventSubscriber = this.router.events.subscribe((event) => {
            if (!(event instanceof NavigationEnd)) {
                return;
            }

            // Inform Google Analytics
            ga('set', 'page', event.urlAfterRedirects);
            ga('send', 'pageview');
        });
    }

    ngOnDestroy() {
        this.routerEventSubscriber.unsubscribe();
    }

[Update]
Wenn man die Analytics-Daten nur in der Produktiv-Umgebung abfeuern möchte, kann man das am besten über die environment-Variable machen:

if( environment.production === true ) {
// Inform Google Analytics
ga('set', 'page', event.urlAfterRedirects);
ga('send', 'pageview');
}
[/Update]

An den Anfang der Seite/Komponente springen

Das Laden von Komponenten in SPAs hat sehr viele Vorteile. Einer der wenigen Nachteile ist allerdings, dass man standardmässig nicht mehr an den Anfang der Seite springt, wenn man einen Link anklickt.

Mit einem einfachen Event-Subscriber direkt auf der Root-Komponente kann man dem allerdings entgegenwirken:

export class AppComponent implements OnInit, OnDestroy{
    private routerEventSubscriber: Subscription;

    constructor(private router: Router) {}

    ngOnInit() {
        this.routerEventSubscriber = this.router.events.subscribe((evt) => {
            if (!(evt instanceof NavigationEnd)) {
                return;
            }
            window.scrollTo(0, 0)
        });
    }

    ngOnDestroy() {
        this.routerEventSubscriber.unsubscribe();
    }

}

Entfernen oder Leeren eines HTML-Elementes

Wenn ihr ein HTML-Element leeren oder direkt löschen wollt, kann das direkt im Template mit Hilfe der Referenz-Variable gemacht werden:

<div #myElement>
  Bald ist dieses Element weg
</div>

<!-- Element leeren -->
<button (click)="myElement.innerHTML = ''">Div leeren</button>

<!-- Element löschen -->
<button (click)="myElement.remove()">Div löschen</button>

Firebase: Werte auslesen ohne .subscribe()

Bei der Arbeit mit Firebase werden Werte i.d.R. via .subscribe() ausgelesen. Das hat allerdings den Nachteil, dass jedesmal die Zeilen innerhalb von .subscribe() neu ausgeführt werden, wenn sich die Werte in Firebase geändert haben.

Möchte man nur einmalig Werte auslesen, kann man bei der Definition des Observables mit der Funktion take() arbeiten.

Beispiel:

let myFirebaseObservable: Observable<any> = this.angularfireService.database.object('firebasenode').take(1);
myFirebaseObservable( snapshot => {
   console.log( snapshot.$value );
});

Automatische Erstellung URL-freundlicher Strings

Wer gerne on-the-fly URL-freundliche Strings erstellen möchte (aka „slugify„), der kann sich folgender Pipe bedienen:

/**
 * Create user friendly and URL valid name of the category name.
 * Source: https://gist.github.com/mathewbyrne/1280286
 */

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({name: 'slugify'})
export class SlugifyPipe implements PipeTransform {

  transform(value: any, args?: any): any {
    if( value == '' ) {
      return value;
    } else {
      return value.toString().toLowerCase()
          .replace(/\s+/g, '-')           // Replace spaces with -
          .replace(/[^\w\-]+/g, '')       // Remove all non-word chars
          .replace(/\-\-+/g, '-')         // Replace multiple - with single -
          .replace(/^-+/, '')             // Trim - from start of text
          .replace(/-+$/, ''); // Trim - from end of text
    }
  }
}

Das Original (=der JS-Aufruf) findet ihr hier: https://gist.github.com/mathewbyrne/1280286

[UPDATE]
Um deutsche Sonderzeichen zu beachten könnt ihr die Rückgabe wie folgt erweitern:

      return value.toString().toLowerCase()
          .replace(/ä/g, 'ae')             // Replace ä with ae
          .replace(/ö/g, 'oe')             // Replace ö with oe
          .replace(/ü/g, 'ue')             // Replace ü with ue
          .replace(/ß/g, 'ss')             // Replace ß with two s
          .replace(/\s+/g, '-')           // Replace spaces with -
          .replace(/[^\w\-]+/g, '')       // Remove all non-word chars
          .replace(/\-\-+/g, '-')         // Replace multiple - with single -
          .replace(/^-+/, '')             // Trim - from start of text
          .replace(/-+$/, ''); // Trim - from end of text

[/UPDATE]

Limit auf ngFor anwenden

Wer eine Reihe an Daten mit *ngFor ausliest und „on the fly“ die Daten bereits filtern möchte (z.B. um nur eine bestimmte Menge anzuzeigen), der kann die filter-Methode einsetzen:

Beispiel-Daten (sportsdata.ts):

export default [
    {
        id: 1,
        name: 'Fussball'
    },
    {
        id: 2,
        name: 'Beachvolleyball'
    },
    {
        id: 3,
        name: 'Eishockey'
    },
    {
        id: 4,
        name: 'Volleyball'
    },
]

Komponente:

import { Component, OnInit } from '@angular/core';
import Sportsdata from "sportsdata.ts";

@Component({
  selector: 'my-component',
  templateUrl: './sportsdata.component.html',
})
export class SportsdataComponent implements OnInit {
    sportsdata: {id: number, name: string}[]

    constructor() { }

    ngOnInit() {
        this.sportsdata = Sportsdata;
    }

    public getSportsdata(begin: number, end: number) {
        begin = begin - 1;
        end = end - 1;
        return this.sportsdata.filter((item, index) => index >= begin && index <= end )
    }
}

Template:

<div *ngFor="let sportdata of getSportsdata(1,2)">
    {{ sportdata.name }}
</div>
<hr>
<div *ngFor="let sportdata of getSportsdata(3,4)">
    {{ sportdata.name }}
</div>

Custom Pipe: Deutsches Währungsformat

Standardmässig bietet Angular 2 mit der Curreny Pipe eine Möglichkeit, numerische Werte in ein entsprechendes Währungsformat zu verwandeln. Der (m.M.n) große Nachteil liegt allerdings darin, dass zum einen das Währungskürzel fest vor den jeweiligen Betrag gesetzt wird (oder eben gar nicht angezeigt). Zum anderen bleibt als Dezimaltrenner weiterhin der Punkt bestehen, anstelle des in Deutschland üblichen Kommas.
Mit einer entsprechenden (einfachen) Custom Pipe kann dem allerdings entgegen gewirkt werden:
customcurrency.pipe.ts:

import { PipeTransform, Pipe } from "@angular/core";
import { isNumeric } from "rxjs/util/isNumeric";

@Pipe({name: 'customcurrency'})
export class CustomcurrencyPipe implements PipeTransform {
    transform(value: string, currencySymbol: string): any {

        // Cast to float and make it 2 decimal places, set the currency symbol and replace . with ,
        var numberValue = parseFloat(value).toFixed(2);
        numberValue = numberValue.replace(/\./g, ",");
        numberValue = numberValue + " " + currencySymbol;

        return numberValue;
    }
}

Template:

{{ shippingCosts | customcurrency: '€' }}

Und das war’s!
ps: Vergesst nicht die CustomcurrencyPipe Klasse in app.module.ts (unter „declaration“) zu registrieren, damit die Pipe global in der App genutzt werden kann.

Neue Komponente anlegen

Zum Anlegen neuer Komponenten empfiehlt es sich auf die angular cli zurückzugreifen.
Mit dem Befehl

ng generate component <NAME>

wird die Komponente in einem neuen Ordner angelegt, inkl. aller notwendiger Dateien (.ts, .html, .css und .spec.ts).

Zusätzlich wird die Komponente automatisch im Modul (app.module.ts) importiert und damit automatisch anderen Komponenten zur Verfügung gestellt.

Die Befehle (generate, component, …) können auch abgekürzt werden:
generate => g
component => c

Wer keinen extra Unterordner und sowohl das CSS als auch das Template inline erstellen möchte, kann auf folgenden Befehl zurück greifen:

ng g c —flat —inline-style —inline-template

—flat => kein Unterodner
—inline-style (Abkürzung: -is) => inline CSS
—inline-template (Abkürzung: -it) => inline Template