$ templateCache未定义虽然我在$ http调用中设置了``cache:$ templateCache}`

时间:2015-02-12 20:29:39

标签: javascript html angularjs angularjs-directive angular-template

我有两个html页面,snippet1.html& snippet2.html。我想在我的指令中使用它们。因为我打算使用单指令添加多个模板。

我通过在<script>标记&amp;中添加html模板来尝试此操作。像{下面这样给他们type="text/ng-template"

<script type="text/ng-template" id="snippet1.html">
    <div>Here is Snippet one</div>
</script>

<script type="text/ng-template" id="snippet2.html">
    <div>Here is Snippet two</div>
</script>

然后我使用$templateCache.get('snippet1.html')。这个实现工作正常。

但在我的情况下,我需要从html本身加载它们,所以我决定通过ajax加载模板并使$http cache: $templateCache

Working JSFiddle

运行阻止

myApp.run(['$templateCache','$http', function($templateCache, $http){ 
  $http.get('snippet1.html',{ cache : $templateCache }); 
  $http.get('snippet2.html',{ cache : $templateCache }); 
}]);

但我的控制器$templateCache.get('snippet1.html')内部未定义。

我的问题是,当我在<script>' tag & Why it don't work when I html inside $ templateCache while making $ http` ajax调用中声明模板时,为什么它正在工作?

Plunkr With Problem

任何人都可以帮我解决这个问题吗?或者我在代码中遗漏了任何东西。

帮助非常感谢。感谢。

2 个答案:

答案 0 :(得分:6)

这是一个有趣的问题,我可以提供一个有趣的解决方法和我对正在发生的事情的看法。我认为可能存在更好的解决方案,但找到这样的解决方案也证明是一项挑战。尽管如此,我认为主要问题仅在于console.log($templateCache.get('snippet1.html'))正在返回undefined,因为竞争条件导致$http.get未首先解决。

检查$templateCache的api,我找不到任何有用的方法来了解何时通过ajax请求模板解析。要查看简单问题,请在您的指令中运行此操作,以查看有关$templateCache

中当前存储内容的一些基本信息
console.log($templateCache.info())

结果

  

对象{id:&#34;模板&#34;,尺寸:0}

为了观察问题的核心,在指令中运行相同的JS,但是超时是这样的

setTimeout(function() {
    console.log($templateCache.info())
}, 1000);

结果

  

对象{id:&#34;模板&#34;,尺寸:2}

有趣,所以他们在那里......但是掌握它们现在是一个挑战。我精心设计了以下解决方法,至少为我们提供了一些东西。将$q$rootScope注入您的.run函数

myApp.run(['$templateCache', '$http', '$q', '$rootScope', function($templateCache, $http, $q, $rootScope){ 
    $q.all([
        $http.get('snippet1.html',{ cache : $templateCache }),
        $http.get('snippet2.html',{ cache : $templateCache }) 
    ]).then(function(resp){
        $rootScope.templateCache = resp
    })
  }]
); 

检查这一点,您会注意到我var $rootScope $rootScope.templateCache $watch $templateCache $rootScope.templateCache {{}}}指示。然后在我们的指令中,当我们知道$q上有值时,让我们调用link: function(scope, element, attrs) { scope.$parent.$parent.$watch('templateCache', function(n, o) { if(n) { element.append($compile($templateCache.get('snippet1.html')[1])(scope)); } }); } ,表明scope.$parent.$parent服务已经解决了我们的承诺

scope

嘿,看!我们的模板指令被正确呈现。 hacky look $rootScope是因为在这个指令中,我们已经隔离了var providers = {}; var $injector = angular.injector(['ng']); var myApp = angular.module('myApp', []); $injector.invoke(function($http, $q, $templateCache, $document) { $q.all([ $http.get('snippet1.html',{ cache : $templateCache }), $http.get('snippet2.html',{ cache : $templateCache }) ]).then(function(resp){ providers.cacheProvider = $templateCache; angular.bootstrap($document, ['myApp']); }); }); myApp .controller('test',function() { }) .directive('myTemplate', function ($templateCache, $compile) { return { restrict: 'EA', scope: { snippets: '=' }, link: function(scope, element, attrs) { element.append($compile(providers.cacheProvider.get('snippet1.html')[1])(scope)); } }; }); ,现在需要爬上一些梯子来获得{{1}}上定义的值。

我希望我们能找到一种更清洁更简洁的方式吗?当然!但是,希望这可以确定为什么正在发生这种情况,以及现在可能的启动和运行方法。下面提供了工作的plunker。

Plunker Link

修改

这是一种完全不同的解决方法,涉及手动引导

{{1}}

Updated Plunker

答案 1 :(得分:3)

这是预期的行为。当您在脚本标记内包含模板时,angular会在引导过程中找到它,并在任何代码运行之前将其添加到缓存中。这就是为什么它在你的指令中可用。

当你使用$ templateCache.put()(或使用$ http.get来检索代码中指定的html文件时,angular必须使用ajax来解析模板。当请求是“在飞行中”时,模板缓存对此一无所知 - 该文件仅在收到响应后才添加到模板缓存中。

由于您的指令作为第一个摘要周期(启动时)的一部分运行,因此缓存中永远不会有任何远程文件,因此您会收到错误。

执行您尝试执行的操作的“正确”方法是不直接使用$ templateCache,而是使用$ http服务来请求远程模板。如果原始响应已返回,$ http将为您调用$ templateCache.get。如果没有,它将返回原始$ http请求生成的相同承诺。

这样做,不需要使用$ timeout或$ watch。模板将在使用promises时立即编译。

myApp.controller('test',function(){})
    .directive("myTemplate", function ($http, $compile) {
    return {
        restrict: 'EA',
        scope: {
            template: '&?myTemplate',
            src: '&?'
        },
        link: function(scope, element, attrs) {
            $http.get(scope.template() || scope.src()).then(function(result) {
                element.append($compile(result.data)(scope));
            });
        }
    };
});

<my-template src="snippet1.html"></my-template>

<div my-template="snippet1.html"></div>

Here is a working Plunk

编辑:替代没有$ compile和$ http

myApp.controller('test',function(){})
    .directive("myTemplate", function ($http, $compile) {
    return {
        restrict: 'EA',
        scope: {
            snippets: '='
        },
        template: 'snippet1.html',
        link: function(scope, element, attrs) {

        }
    };
});

关于你的最后一个问题(为什么你必须使用[1]来获取html - $ http服务不仅仅在缓存中存储html - 它存储一个可能包含promise或元素的数据结构(如果已加载)从一个脚本标签)。因为它知道它放入了什么,它知道如何把它拿出来。当你短路的东西,你只是猜测。

长话短说 - 不要使用$ templateCache自己解析模板。

编辑:来自$ http的代码,演示可能存储在缓存中的不同类型的数据。

if (cache) {
    cachedResp = cache.get(url);
    if (isDefined(cachedResp)) {
      if (isPromiseLike(cachedResp)) {
        // cached request has already been sent, but there is no response yet
        cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult);
      } else {
        // serving from cache
        if (isArray(cachedResp)) {
          resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
        } else {
          resolvePromise(cachedResp, 200, {}, 'OK');
        }
      }
    } else {
      // put the promise for the non-transformed response into cache as a placeholder
      cache.put(url, promise);
    }
  }