Skip to content

Instantly share code, notes, and snippets.

@dhilgarth
Created December 18, 2018 08:46
Show Gist options
  • Select an option

  • Save dhilgarth/783ed994be6e3af0c236fc36f327c9cd to your computer and use it in GitHub Desktop.

Select an option

Save dhilgarth/783ed994be6e3af0c236fc36f327c9cd to your computer and use it in GitHub Desktop.
Passing meta data for interceptors to Angular HttpClient
export class LoadingInterceptorConfig {
constructor(public disableLoadingIndicator: boolean = false) {
}
}
import { HttpParams } from '@angular/common/http';
import { Type } from '@angular/core';
export interface IWithMetaData {
meta: IMetaData;
}
export interface IMetaData {
add<T>(data: T): void,
get<T>(type: Type<T>): T
}
interface IMetaDataInternal {
metaData: { [key: string]: any }
}
function add<T>(this: IMetaDataInternal, data: T): void {
this.metaData[data.constructor.name] = data;
}
function get<T>(this: IMetaDataInternal, type: Type<T>): T | undefined {
return this.metaData[type.name];
}
function hasMetaData(obj: any): obj is IWithMetaData {
return obj.meta && obj.meta.get && obj.meta.add;
}
export function getMetaData<T>(httpParams: HttpParams, type: Type<T>): T | undefined {
if (hasMetaData(httpParams)) {
return httpParams.meta.get(type);
}
return undefined;
}
export function withMetaData(httpParams: HttpParams): HttpParams & IWithMetaData {
const meta: IMetaData & IMetaDataInternal = {
add,
get,
metaData: {}
};
return Object.assign(httpParams, {meta});
}
import { getMetaData } from '../some/path/meta-data'
import { LoadingInterceptorConfig } from '../some/path/LoadingInterceptorConfig'
// ...
private overlayDisabled(req: HttpRequest<any>): boolean {
const config = getMetaData(req.params, LoadingInterceptorConfig);
return !!config && config.disableLoadingIndicator;
}
// ...
import { withMetaData } from '../some/path/meta-data'
import { LoadingInterceptorConfig } from '../some/path/LoadingInterceptorConfig'
// if you don't want to pass any other parameters:
const params = withMetaData(new HttpParams());
// if you have other parameters to pass:
const params = withMetaData(queryParameters);
params.meta.add(new LoadingInterceptorConfig(this.disableLoadingIndicator));
// Important: Don't perform any other operations on `params` after you added the metadata.
// As HttpParams is immutable, this would mean that our meta data would be lost.
this.httpClient.get<...>(`${this.basePath}/api/x/y`, {params});
@moshmage
Copy link
Copy Markdown

moshmage commented Jul 8, 2019

Just letting you know I ended up using this (with some slight modifications) until Angular gets its shit together with the shitty excuses.
Kudos, mate.

PS: I did have to make a facet to the HttpClient so I could use the meta params as a options,

// MyRequestOptions is a remnant from a preivous implementation that redeclared HttpRequestOptonArgs with more props

export interface MyRequestOptions {
  skipErrorHandler?: boolean;
  hideLoader?: boolean;
  external?: boolean;
  suppressError?: boolean;
  ignoreSomething?: boolean;
}

const LoadInterceptorMeta = (options: MyRequestOptions): {params: HttpParamsWithMeta} => {
  const params: HttpParamsWithMeta = withMeta();
  const {skipErrorHandler, suppressError, external, hideLoader, ignoreCrId} = options;

  [
    new LoaderInterceptorConfig(hideLoader),
    new ExernalInterceptorConfig(external),
    new ErrorInterceptorConfig(skipErrorHandler, suppressError),
    new SomethingInterceptorConfig(ignoreSomething)
  ].forEach(interceptor => params.meta.add(interceptor));

  return {params};
};

@Injectable({
  providedIn: 'root'
})
export class HttpFacetService {

  constructor(private http: HttpClient) { }

  get(url: string, options: MyRequestOptions) {
    return this.http.get(url, LoadInterceptorMeta(options));
  }

@dhilgarth
Copy link
Copy Markdown
Author

Great, happy to hear it was helpful

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment