2016-12-27 37 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', 
    ];