angular-docs-cn/aio/src/NOTES.md

5.2 KiB

Design Notes

Application State

Apart from loading up the navigation and search data, there is only one significant state in the app, which is the document being viewed. Other state, such as highlighting the current navigation items and bread crumbs can be derived from that state. The simplest indication of this state is the current Location#path, which acts as the single point of truth in the application.

  • The document to display is computed from the path.
  • Navigation to display different documents is achieved by updating the path.
  • Whether a navigation item should be highlighted as active is computed from the path

Navigation between documents can be achieved through changes to the Location.

Concepts

There are three main concepts in the application: documents, navigation and search.

  • The document data includes the contents of the document for rendering.
  • The search data includes keywords used for building the search index.
  • The navigation data contains information about the visual trees that can be rendered in the app to navigate to the documents.

Documents

Information about documents to be displayed are provided as data that can be fetched from the server. There are two parts to the data for each document: DocumentContents.

  • DocumentContents contains the actual document that will be rendered. This can be loaded (and then cached) lazily only when the document is to be viewed.

Each document is uniquely identified by the path that is also used to fetch its DocumentContents. The DocumentContents are stored in JSON files on the server. They are loaded lazily on demand and then cached.

interface DocumentContents {
  title: string;
  contents: string;
}

type DocumentContentsJSONFile = Array<DocumentContents>;

Navigation

Within an application there can be multiple navigational views for displaying links to documents. For example, there might be views for the top level Toolbar and for the more detailed SideBar navigation.

Each view is represented as a tree of NavigationNodes. Each NavigationNode may, optionally, have a url, a path and children.

interface NavigationNode {
  title: string;
  url?: string;
  path?: string;
  tooltip?: string;
  target?: string;
  children?: NavigationNode[];
}

The url property represents a link to an external url outside of the app. The path property identifies the document to display for this navigation url. It is used both as the URL segment in the browser and in the request to fetch the document contents. It is not valid to have both url and path properties on a single node. If neither url nor path properties are then the node is a pure container, in which case it ought to have

The NavigationNode data is stored in a JSON file that is fetched from the server at startup

interface NavigationViews {
  [name: string]: NavigationNode;
}

The mapping of a URL back to NavigationNode is computed by inverting all the NavigationNode structures to produce a NavigationMap of URL to node.

interface NavigationMap {
  [url: string]: NavigationMapItem
}

Each NavigationMapItem contains information for updating the current navigation views and also caches the DocumentContents once it has been loaded.

interface NavigationMapItem {
  node: NavigationNode;
  parents: NavigationNode[];
  document?: DocumentContents;
}

The SearchTerms are stored in a single JSON file that is loaded by the search WebWorker at startup and used to generate the search index.

interface SearchTerms {
  url: string;
  title: string;
  body: string;
}

type SearchTermsJSONFile = Array<SearchTerms>;

LocationService

Since the core Angular Location service does not expose a subject, nor emits events when the location is changed programmatically, we have our own LocationService that does this for us.

export class LocationService {
  currentUrl: Observable<string>;
  go(url: string): void
}

You can subscribe to the currentUrl to be updated when location changes occur. You should navigate to new documents by calling go.

DocumentService

The DocumentService is responsible for monitoring the LocationService.currentUrl and updating the currentDocument. When the currentUrl changes, the DocumentService will fetch the DocumentContents from the server if necessary and cache it for the future.

export class DocumentService {
  currentDocument: Observable<DocumentContents>;
}

The mapping of URL path to the path to fetch the document contents is simply:

  private computePath(url) {
    url = url.startsWith('/') ? url : '/' + url;
    return 'content/docs' + url + '.json';
  }

NavigationService

The NavigationService is responsible for:

  • fetching and exposing the NavigationViews for use in displaying navigation UI.
  • building the NavigationMap from the NavigationNode data.
  • updating observables for the currently active NavigationNodes that can be used to render the navigation UI when the LocationService.currentUrl changes.
class NavigationService {
  navigationViews: Observable<NavigationViews>;
  currentNode: Observable<NavigationNode>;
  activeNodes: Observable<NavigationNode[]>;
}