2016-12-27 34 views
5

我想升级要在ng2组件内使用的ng1组件。NgUpgrade:升级Angular1组件时无法使用templateUrl

如果我只使用ng1组件的模板字符串进行升级,它将起作用。但是,如果我切换到使用一个templateUrl相反,应用程序崩溃,给我这个错误:

angular.js:13920 Error: loading directive templates asynchronously is not supported 
at RemoteUrlComponent.UpgradeComponent.compileTemplate (upgrade-static.umd.js:720) 
at RemoteUrlComponent.UpgradeComponent (upgrade-static.umd.js:521) 
at new RemoteUrlComponent (remote-url.component.ts:11) 
at new Wrapper_RemoteUrlComponent (wrapper.ngfactory.js:7) 
at View_AppComponent1.createInternal (component.ngfactory.js:73) 
at View_AppComponent1.AppView.create (core.umd.js:12262) 
at TemplateRef_.createEmbeddedView (core.umd.js:9320) 
at ViewContainerRef_.createEmbeddedView (core.umd.js:9552) 
at eval (common.umd.js:1670) 
at DefaultIterableDiffer.forEachOperation (core.umd.js:4653) 

下面是一个展示普拉克我的问题:

https://plnkr.co/edit/2fXvfc?p=info

我跟着角1 - > 2升级指南,似乎这个代码应该工作。我不太确定它为什么不起作用。

回答

3

我发现了一个相当便宜的解决方案。

只需使用template: require('./remote-url.component.html')而不是templateUrl: './remote-url.component.html',它应该工作得很好!

+0

我试过你的方法,但我得到这个错误,而不是:您即将从您的角度指令升级,例如templateUrls的 '未捕获的ReferenceError:要求未在VM586 remoting-定义 url.component.js:8' – Houa

+0

要使用'require'you必须使用正确的模块加载程序,在这种情况下,我认为使用commonJS的更多细节.. https://stackoverflow.com/questions/19059580/client-on-node-uncaught-referenceerror-需要 - 是 - 不定义 – Florian

2

这实在令人沮丧,因为Angular升级文档特别指出可以使用templateUrl。从来没有提到这个异步问题。我已经通过使用$ templateCache找到了解决方法。我不想更改我的angular 1指令,因为它使用了我的angular 1应用程序,并且还会被角度4的应用程序使用。所以我必须找到一种方法来即时修改它。我使用$ delegate,$ provider和$ templateCache。我的代码如下。我也使用它来删除replace属性,因为它已被弃用。

function upgradeDirective(moduleName, invokedName) { 
    /** get the invoked directive */ 
    angular.module(moduleName).config(config); 

    config.$inject = ['$provide']; 
    decorator.$inject = ['$delegate', '$templateCache']; 

    function config($provide) { 
     $provide.decorator(invokedName + 'Directive', decorator); 
    } 

    function decorator($delegate, $templateCache) { 
     /** get the directive reference */ 
     var directive = $delegate[0]; 

     /** remove deprecated attributes */ 
     if (directive.hasOwnProperty('replace')){ 
      delete directive.replace; 
     } 

     /** check for templateUrl and get template from cache */ 
     if (directive.hasOwnProperty('templateUrl')){ 
      /** get the template key */ 
      var key = directive.templateUrl.substring(directive.templateUrl.indexOf('app/')); 

      /** remove templateUrl */ 
      delete directive.templateUrl; 

      /** add template and get from cache */ 
      directive.template = $templateCache.get(key); 
     } 

     /** return the delegate */ 
     return $delegate; 
    } 
} 

upgradeDirective('moduleName', 'moduleDirectiveName'); 
1

一个漂亮的低技术解决这个问题是加载您的模板在你的index.html,并为它们分配符合指令正在寻找templateUrls该标识,即:

<script type="text/ng-template" id="some/file/path.html"> 
    <div> 
    <p>Here's my template!</p> 
    </div> 
</script> 

Angular然后自动将模板放入$ templateCache中,这是UpgradeComponent的compileTemplate正在查找模板的开始位置,因此,如果不更改指令中的templateUrl,则事情将工作,因为id与templateUrl匹配。

如果你检查UpgradeComponent的源代码(见下面),你可以看到注释掉的代码处理获取url,所以它必须在工作中,但是暂时这可能是一个可行的解决方案,并且甚至可以编写脚本。

private compileTemplate(directive: angular.IDirective): angular.ILinkFn { 
    if (this.directive.template !== undefined) { 
     return this.compileHtml(getOrCall(this.directive.template)); 
    } else if (this.directive.templateUrl) { 
     const url = getOrCall(this.directive.templateUrl); 
     const html = this.$templateCache.get(url) as string; 
     if (html !== undefined) { 
     return this.compileHtml(html); 
     } else { 
     throw new Error('loading directive templates asynchronously is not supported'); 
     // return new Promise((resolve, reject) => { 
     // this.$httpBackend('GET', url, null, (status: number, response: string) => { 
     //  if (status == 200) { 
     //  resolve(this.compileHtml(this.$templateCache.put(url, response))); 
     //  } else { 
     //  reject(`GET component template from '${url}' returned '${status}: ${response}'`); 
     //  } 
     // }); 
     // }); 
     } 
    } else { 
     throw new Error(`Directive '${this.name}' is not a component, it is missing template.`); 
    } 
    } 
0

我已经创建了一个方法实用程序来解决这个问题。 基本上它添加模板URL内容到角的templateCache, 使用requireJS和“text.js”:

initTemplateUrls(templateUrlList) { 
    app.run(function ($templateCache) { 
     templateUrlList.forEach(templateUrl => { 
     if ($templateCache.get(templateUrl) === undefined) { 
      $templateCache.put(templateUrl, 'temporaryValue'); 
      require(['text!' + templateUrl], 
      function (templateContent) { 
       $templateCache.put(templateUrl, templateContent); 
      } 
     ); 
     } 
     }); 
    }); 

你应该做的是把在appmodule.ts例如这种方法实用工具,然后创建一个列表

const templateUrlList = [ 
     '/app/@[email protected]/common/directives/grid/pGrid.html', 
    ];