Skip to content

Instantly share code, notes, and snippets.

@guillaumegarcia13
Last active July 17, 2018 14:38
Show Gist options
  • Save guillaumegarcia13/402c260249bd5f194f7d76690eac0afc to your computer and use it in GitHub Desktop.
Save guillaumegarcia13/402c260249bd5f194f7d76690eac0afc to your computer and use it in GitHub Desktop.
Angular Responsive Decorator
/* Disclaimer:
* This snippet is provided “AS IS” and could contain technical inaccuracies, typographical errors and out-of-date information.
* Use of the information is therefore at your (very) own risk.
*/
/*_____________________________________________________________________________________________________________________
* Aim
* Provide some solution in case of complex constructs to manage layout from an Angular point-of-view (ex: ngx-datatable)
* See: https://github.com/swimlane/ngx-datatable/issues/423
*
* Obviously, in most cases, you can rely on CSS, Media queries, apply a Bootstrap 'hidden-xs' class or whatever
*
* Limitations (I know, this is disgraceful...)
* o Not AOT-compatible (since properties are added "dynamically" during ngOnInit)
* o Workaround is to declare the 2 properties in your component
* // @FcomResponsive() -> following declarations are required for AOT compilation
* public LAYOUT: any;
* public layout: number;
*...................................................
* Controller (my.component.ts)
* @Component({...)
* @MyResponsive()
* export class MyComponent implements OnInit {
* ...
* }
*...................................................
* View (my.component.html)
* <div *ngIf="layout > LAYOUT?.XS">...</div>
*
*_____________________________________________________________________________________________________________________
*/
import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout';
import { SharedModule } from 'app/shared/shared.module'; // <- see: https://medium.com/@NetanelBasal/this-is-what-i-did-this-c4c15064fefe
export function MyResponsive(): ClassDecorator {
return function (target: any) {
const LAYOUT = {
XS : 768,
SM : 992,
MD : 1200,
LG : 1600,
XL : 1920,
XXL: 2560, // <- see: bootstrap-xlgrid at https://github.com/arnisp/bootstrap-xlgrid
};
const ngOnInit = target.prototype['ngOnInit'];
target.prototype['ngOnInit'] = function (...args) {
if (!ngOnInit) { return; }
this.LAYOUT = LAYOUT;
this.breakpointObserver = SharedModule.injector.get(BreakpointObserver);
// Setting up breakpoint mechanism
const breakpoints = Object.keys(this.LAYOUT).map(k => this.LAYOUT[k]);
breakpoints.forEach((maxWidth, index) => {
const minWidth = (index > 0) ? breakpoints[index - 1] : 0;
this.breakpointObserver
.observe([`(min-width: ${ minWidth }px) and (max-width: ${ maxWidth - 1 }px)`])
.subscribe((state: BreakpointState) => {
if (!state.matches) { return; }
this.layout = maxWidth;
console.log(`Layout: %c ${ this.layout }`, `color: #00ADEF; font-weight: bold`);
});
});
ngOnInit.apply(this, args);
}
}
}
/*
* Reminder: class decorators only operate on prototype level
* so that:
* Object.defineProperty(target.prototype, '_LAYOUT', { value: {
* XS : 768,
* SM : 992,
* MD : 1200,
* LG : 1600,
* XL : 1920,
* XXL: 2560,
* }});
* result in:
* - this.__proto__._LAYOUT
*
* That is why we use Aspect-Oriented Programming on ngOnInit
* to inject new properties into the instance (through the 'this' keyword)
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment