Last active
July 17, 2018 14:38
-
-
Save guillaumegarcia13/402c260249bd5f194f7d76690eac0afc to your computer and use it in GitHub Desktop.
Angular Responsive Decorator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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