Template as [removed] equivalent with angular 2

后端 未结 2 952
清歌不尽
清歌不尽 2021-02-05 17:27

Angularjs (e.g. angular 1) had this convenient behaviour of searching for a

相关标签:
2条回答
  • 2021-02-05 17:46

    I think a cleaner way for this would be if you provide your custom ViewResolver, inspired by the angular beta 17's source code, something in the lines of:

    import { Type, ViewMetadata, Reflector, Injectable, ComponentMetadata } from 'angular2/core';
    import { ViewResolver } from 'angular2/compiler';
    
    const SCRIPT_TYPE_NAME = 'text/ng2-template';
    
    @Injectable()
    export class CustomViewResolver extends ViewResolver 
    {
      constructor(private _r: Reflector){ super() }
      resolve(component: Type): ViewMetadata
      {
        let annotations = this._r.annotations(component);
        annotations.forEach( cm => 
        {
          if(cm instanceof ComponentMetadata && cm.templateUrl && typeof cm.templateUrl == 'string' )
          {
            let elemTpl = (<any>document).getElementById(cm.templateUrl);
            if( elemTpl && elemTpl.getAttribute('type') == SCRIPT_TYPE_NAME )
            {
              cm.template = elemTpl.innerHTML;
              elemTpl.remove();
              cm.templateUrl = undefined
            }
            else
              throw new Error(`template "${cm.templateUrl}" not found among html scripts`)
          }
        })
        return super.resolve(component)
      }
    }
    

    Plunker Link

    0 讨论(0)
  • 2021-02-05 17:59

    If anyone is interested, i found a simple workaround (a cleaner solution would be better, though)

    function template(url, viewdef) {
        var elt = document.getElementById(url);
        if (elt && elt.getAttribute('type') == 'text/ng-template') {
            viewdef.template = elt.innerHTML;
        } else
            viewdef.templateUrl = url;
        return viewdef;
    }
    
    @View(template('mytemplate.html', {
        directives: [NgIf /*required directives*/]
    }))
    class MyComponent{}
    

    But it assumes that the <script> is already present when this script is loaded.

    [EDIT] Better workaround

    I just came up with the simple idea to just override the @View decorator factory.

    1) Create a viewoverride.ts file

    import * as ng from 'angular2/core'
    let oldNgView = ng.View;
    function ViewOverride(viewDef) {
        if (typeof viewDef.templateUrl == "string") {
            let elt = document.getElementById(viewDef.templateUrl);
            if (elt && elt.getAttribute('type') == 'text/ng-template') {
                viewDef.template = elt.innerHTML;
                delete viewDef.templateUrl;
            }
        }
        return oldNgView(viewDef);
    }
    ng.View = <ng.ViewFactory>ViewOverride;
    

    nb: It's very important to put it in a separate and independant file, to force it to be executed before other imports

    2) And put this as the first line of your bootstrap file:

    import './viewoverride'
    

    3) That's it. The @View notation is now overriden

    @View({templateUrl:'mytemplate.template'}) class MyClass{} 
    

    will now seek for a script element which id is mytemplate.template

    0 讨论(0)
提交回复
热议问题