angular/aio/src/app/documents/document.service.ts
Peter Bacon Darwin fe962f6de7 fix(aio): LocationService urls should never start with a slash
There is a weirdness in the Angular Location service.
If the `baseHref` is only a single slash (`'/'`) then it
changes it to be an empty string (`''`). The effect of this
is that `Location.normaliseUrl(url)` does not strip off the
leading slash from url paths.

The problem is that the leading slash only appears on the
initial Location path, and not on urls that arrive from subscribing
to the Location service.

This commit is a workaround this problem.
2017-03-06 22:27:32 -08:00

69 lines
2.1 KiB
TypeScript

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { AsyncSubject } from 'rxjs/AsyncSubject';
import 'rxjs/add/operator/switchMap';
import { LocationService } from 'app/shared/location.service';
import { Logger } from 'app/shared/logger.service';
const FILE_NOT_FOUND_URL = 'file-not-found';
export interface DocumentContents {
title: string;
contents: string;
}
@Injectable()
export class DocumentService {
private cache = new Map<string, Observable<DocumentContents>>();
private fileNotFoundPath = this.computePath(FILE_NOT_FOUND_URL);
currentDocument: Observable<DocumentContents>;
constructor(private logger: Logger, private http: Http, location: LocationService) {
// Whenever the URL changes we try to get the appropriate doc
this.currentDocument = location.currentUrl.switchMap(url => this.getDocument(url));
}
private getDocument(url: string) {
this.logger.log('getting document', url);
const path = this.computePath(url);
if ( !this.cache.has(path)) {
this.cache.set(path, this.fetchDocument(path));
}
return this.cache.get(path);
}
private fetchDocument(path: string) {
this.logger.log('fetching document from', path);
const subject = new AsyncSubject();
this.http
.get(path)
.map(res => res.json())
.catch((error: Response) => {
if (error.status === 404) {
if (path !== this.fileNotFoundPath) {
this.logger.error(`Document file not found at '${path}'`);
// using `getDocument` means that we can fetch the 404 doc contents from the server and cache it
return this.getDocument(FILE_NOT_FOUND_URL);
} else {
return Observable.of({ title: 'Not Found', contents: 'Document not found' });
}
} else {
throw error;
}
})
.subscribe(subject);
return subject.asObservable();
}
private computePath(url) {
url = '/' + url;
url = url.endsWith('/') ? url + 'index' : url;
return 'content/docs' + url + '.json';
}
}