Open fabioformosa opened 6 years ago
Here's the hack.
I only want the UserBox' HTML template to be
<div class='user-body'>
{{ currentUser.email }}
</div>
To achieve this, I had to go really deep into Angular internals.
First, you have to add a very invasive piece of code to main.ts
.
You have to override the so called DirectResolver class used in Angular.
Second, you have to provide a customised DirectiveResolver, which when loading all components, modifies the HTML template of the component, whose selector is.userBox
.
This is all done in custom-directive.resolver.ts
, see below.
main.ts
now becomes like this:
import { enableProdMode } from '@angular/core';
import { DirectiveResolver, CompileReflector } from '@angular/compiler';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
import { CustomDirectiveResolver } from './custom-directive.resolver';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(
AppModule, {
providers: [
{
provide: DirectiveResolver,
useClass: CustomDirectiveResolver,
deps: [
CompileReflector
]
},
]
})
.then(ref => {
// Ensure Angular destroys itself on hot reloads.
if (window['ngRef']) {
window['ngRef'].destroy();
}
window['ngRef'] = ref;
// Otherise, log the boot error
})
.catch(err => console.error(err));
Finally custom-directive.resolver.ts
, only replaces HTML code; it could also modify CSS configuration.
Luckily, by this point, each component's template attribute contains the content of the file pointed to by templateUrl.
This is its content for my purposes:
import { Directive, Type, Component } from '@angular/core';
import { DirectiveResolver } from '@angular/compiler';
// import { environment } from '../environments/environment';
export class CustomDirectiveResolver extends DirectiveResolver {
resolve (type: Type<any>, throwIfNotFound?: boolean): Directive {
const view: Component = super.resolve(type, throwIfNotFound);
if (!view) {
return view;
}
// use this to inspect all components, it is quite interesting
// console.log(JSON.stringify(view));
if (view.selector === '.userBox') {
view.template = `
<div class='user-body'>
{{ currentUser.email }}
</div>
`;
view.templateUrl = null;
}
return view;
}
}
I wish there was a much simpler way.
A very clever solution, thank you to have shared. You achieved your goal without to touch the library, but I think:
ngx-admin-lte
can't have in the userBox the hard-coded string 'web developer', the registration date in timestamp or a series of button (follower, etc) unhandled and not customizable.@TwanoO67 it's better a structural change to ngx-admin-lte
, isn't?
What about a new attribute in app-header to pass the userBox template?
This would be the proper way.
<ng-content></ng-content>
The fundamental problem with ngx-admin-lte
is that it mixes many things into one.
A. It wants to be an Angular Library for AminLTE, offering natural Angular Components, Services, Pipes etc. This is what I call "core library".
B. It also wants to showcase AdminLTE, so as the beginner developer gets something up quickly. This is what I call "Demo" use case.
C. It does want to keep compatibility to very old APIs, such as before Angular 4. It also includes keeping the TypeScript language level way too low. This is what I call legacy.
It is high time the list gets reconsidered.
My plan is to concentrate on A and defining a lower boundary for Angular, addressing C. My preference is Angular 4+.
B is best addressed in a separate project, say ngx-admin-lte-demo
or ngx-admin-lte-showcase
or Bootstrapping Ngx-Admin-Lte.
ngx-admin-lte can't have in the userBox the hard-coded string 'web developer', the registration date in timestamp or a series of button (follower, etc) unhandled and not customizable. @TwanoO67 it's better a structural change to ngx-admin-lte, isn't?
I totally agree! Hard coded string shouldn't be in here (or at least in the translation files), and all parts of the app should be customisable.
What about a new attribute in app-header to pass the userBox template?
I would rather set a service for that, in the same way that menu, or control-sidebar works
I also agree with @catull, ngx-admin-lte have to stick to purpose A. Purpose B is adressed by https://github.com/TwanoO67/bootstraping-ngx-admin-lte, so we could move part of the project to that one.
I also agree with stopping backward compatibility to Angular4 level for this package version >2
@TwanoO67 Then please, in the README.md state that this project is for "Angular 4+", drop "~2~".
@TwanoO67 Is the UserBox Layout Customization change in plan? Or for now is better to use the hack @catull shared?
It needs to allow the customization of userBox.
Before to work to this issue, has someone done something about? Here @catull spoke about a hack...