Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2/4 component with dynamic template or templateUrl

I have been trying to find a solution for this everywhere.

I have a project with different 'skins', which are basically different sets of templates/Css.

I am trying to have my components use the skin based on a variable THEME_DIR.

Unfortunately, I cannot find how to make that happens. I looked into the Dynamic Component Loader on angular.io without success.

I also looked at a few answers here without success either.

Does anyone have an idea?

This is what I tried so far:

import { ComponentFactoryResolver, ViewContainerRef } from '@angular/core';

// @Component({
//     templateUrl: '../../assets/theme/'+THEME_DIR+'/login.template.html',
// })

export class LoginComponent implements, AfterViewInit {


    private log = Log.create('LoginPage');

    constructor(private mzksLsRequestService: MzkLsRequestService,
                private componentFactoryResolver: ComponentFactoryResolver,
                public viewContainerRef: ViewContainerRef) {
    }



    ngAfterViewInit() {
        let componentFactory = this.componentFactoryResolver.resolveComponentFactory(new Component({
            templateUrl: '../../assets/theme/default/login.template.html',
        }));
        let viewContainerRef = this.viewContainerRef;
        viewContainerRef.clear();
        let componentRef = viewContainerRef.createComponent(componentFactory);

    }

}
like image 297
millerf Avatar asked Jul 28 '17 14:07

millerf


People also ask

What is the difference between template and templateUrl in Angular 2?

According to Angular, when you have a complex view (i.e. a view with more than 3 lines), then go with templateUrl (use external file); otherwise, use the template (inline HTML) properly of the component decorator.

What is the difference between template and templateUrl in component parameters?

When we define the template in an external file and then after we link with our component is said to be an external template. In other words, The External templates define the HTML code in a separate file and we can refer to that file using templateURL property of Component decorator.

Can Angular component have multiple templates?

You can simply extend your base component and overwrite the template. This allows you to have different components with the exact same functionality, but different templates.

What is difference between component and template?

Components meaning a piece of data that can be used in multiple places and can be rendered anywhere on the page. Essentially a free way of designing a web page without needing a developer's intervention. Page Templates meaning a much more rigid design of the pages that will prevent possible design complications.


2 Answers

I had the problem when trying to load dynamicaly templates from the server (i wanted to make security check, translation on server side before serving html.

I've solved it after changing webpack config. In fact, after doing ng eject, it created a webpack.config.js which contains a .ts loader @ngtools/webpack and :

new AotPlugin({
  "mainPath": "main.ts",
  "replaceExport": false,
  "hostReplacementPaths": {
    "environments\\environment.ts": "environments\\environment.ts"
  },
  "exclude": [],
  "tsConfigPath": "src/main/front/tsconfig.app.json",
  "skipCodeGeneration": true
})

This last one, is the origin of the problem. It concerns the AOT (Ahead Of Time). According to the documentation : ngtools on the options section, it's mentionned :

skipCodeGeneration. Optional, defaults to false. Disable code generation and do not refactor the code to bootstrap. This replaces templateUrl: "string" with template: require("string")

If you dont want your templateUrl to be compiled AOT, i recommand you to remove the AotPlugin, and to use of the ts-loader instead of @ngtools/webpack see :

ts-loader

The rule for ts will look like this :

{
    test: /\.tsx?$/,
    loader: 'ts-loader'
}

Now you can load fresh templates from a relative URL on demand. Example :

@Component({
    selector : "custom-component",
    templateUrl : "/my_custom_url_on_server"
})
export class CustomComponent {
}

See Issue

like image 109
Yacine Avatar answered Oct 08 '22 14:10

Yacine


As of Ivy (I think) we can use static variables (for example enviroment) in templateUrl. for example:

    import { environment } from 'src/environments/environment';
    @Component({
        selector: 'home',
        templateUrl: `./skins/${environment.skin}/home.page.html`,
        styleUrls: ['./skins/${environment.skin}/home.page.scss']
    })
like image 43
hex Avatar answered Oct 08 '22 14:10

hex