AngularJS:动态样式表链接标签过早触发请求

9
我面临的问题类似于(但不完全相同,请耐心等待)在Conditionally-rendering css in html head中所描述的问题。
我也在“懒惰地”加载样式表,从一个作用域变量中获取文件名,该变量在控制器的最开始初始化:
<link rel="stylesheet" data-ng-href="css/{{ filename }}.css" />

我正在使用ng-href(这里是以data-形式)的方式,确实避免了不必要的请求,例如:
http://localhost/css/%7B%7B%20filename%7D%7D.css

但是它仍然太早触发,几乎每次我都会得到这样的结果:
http://localhost/css/.css

这似乎意味着请求在Angular删除自己的标记和替换正确值(稍后执行,并且然后我的样式表正确加载)之间触发。我认为这甚至不可能...!?
我想我可能是为filename作用域变量提供值太晚了,但是正如我所说,这是我控制器中的第一件事情:
angular.module('myControllers', [])
    .controller('TestCtrl', ['$scope', function($scope) {
        $scope.filename = 'test';

        // some more code...
    }]);

我正在使用 Angular 1.1.5;有什么我可以做的吗?虽然这不是很大的问题,但如果我能解决它会更好。

编辑:根据要求,这里是完整的代码。我不会包含页面模板,因为它们与问题无关。

index.html:

<!DOCTYPE html>
<html lang="en" data-ng-app="myapp">

<head>
    <meta charset="utf-8" />
    <title>My App</title>
    <link rel="stylesheet" data-ng-href="/assets/css/{{ filename }}.css" />
</head>

<body>
    <div id="app" class="app" style="display: none;" data-ng-view></div>

    <script src="/assets/js/lib/angular/angular.min.js"></script>
    <script src="/assets/js/app/app.js"></script>
    <script src="/assets/js/app/controllers.js"></script>
</body>

</html>

app.js:

var app = angular.module('myapp', ['myControllers'])
    .config(['$locationProvider', '$routeProvider', function($locationProvider, $routeProvider) {
        $locationProvider.hashPrefix('!');
        $routeProvider

        .when('/', {
            templateUrl: 'path/to/my/template.html',
            controller: 'TestCtrl'
        })

        .otherwise({ redirectTo: '/' });
    }]);

app.run();

controllers.js:

angular.module('myControllers', [])
    .controller('TestCtrl', ['$scope', '$rootScope', function($scope, $rootScope) {
        $rootScope.filename = 'stylesheet';
    }]);

(是的,我尝试过使用一个空控制器,就像这个一样,出现了同样的问题。)

你的控制器作用域在哪里绑定在你的标记中? - André Dion
@AndréDion:你是指使用ngController吗?我的应用程序中有两个控制器,所以我没有使用这个指令(控制器通过$routeProvider绑定)。抱歉,我还在探索Angular,也许我的回答不太正确...? - neemzy
您可以使用 ng-controller 指令或从 $routeProvider 配置绑定控制器作用域。我对 Angular 也不是很熟悉,但我怀疑您的 <link> 元素实际上并不是控制器作用域的一部分。{{filename}} 是否被正确地展开了呢? - André Dion
你能否创建一个 jsfiddle / plunkr 来模拟这种行为? - Phix
这是一个 Plunkr,但我无法在其中重现此问题。它仅发生了一次,之后就没有再出现过,所以可能与加载有关。http://plnkr.co/edit/gCDRHEpsUQ0IUPtoW1AI?p=preview - neemzy
显示剩余4条评论
3个回答

7
我通过在link标签添加ngIf指令来解决它,这样直到filename不是假值时才会渲染出来。有点不规矩,但实际上很有效!
<link rel="stylesheet" data-ng-if="filename" data-ng-href="css/{{ filename }}.css" />

1

在小例子中对我有效。

算法如下:

attr.$observe(normalized, function(value) {
      if (!value)
         return;

      attr.$set(attrName, value);

      // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
      // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
      // to set the property as well to achieve the desired effect.
      // we use attr[attrName] value since $set can sanitize the url.
      if (msie) element.prop(attrName, attr[attrName]);
    });

如果该值为false,例如undefined,该函数将立即返回。

你能发布完整的代码吗?可能还有其他问题。

编辑:

通过Route-Provider绑定控制器只会将此控制器绑定到具有ng-view元素的元素。

你可以这样做:

HTML:

<head ng-controller="HeadCtrl">
<link rel="stylesheet" data-ng-href="{{ filename }}.css">
</head>

JS:

app.controller("HeadCtrl",function ($scope)
{
$scope.filename = 'apartment';
});

不错。问题是我可能会有多个控制器,每个控制器将带来自己的样式表(因为我在它们每个人中都给文件名变量赋了正确的值)。所以,在我的情况下,单独使用一个控制器来处理这个看起来并不好。但是作用域确实曾经是一个问题,这就是为什么我实际上正在使用$rootScope(请参见我通过编辑帖子添加的完整代码)。 - neemzy
如果是这种情况,请像Robin建议的那样保留HeadCtrl,并创建一个服务,控制器可以使用该服务来设置服务上的属性。请查看此视频:在控制器之间共享数据 - André Dion
@AndréDion 感谢提供链接!不过我仍然遇到了同样的问题,所以我并不认为这是作用域相关的(使用 $rootScope 可以避免这种问题,即使这确实是一种不太好的解决方法)。 - neemzy

0

顺便说一句

ng-cloak并不是"触发"来隐藏某些内容的。 你必须要为它添加一个CSS类。

http://docs.angularjs.org/api/ng.directive:ngCloak

[ng\:cloak], 
[ng-cloak], 
[data-ng-cloak], 
[x-ng-cloak], 
.ng-cloak, 
.x-ng-cloak {
   display: none !important;
}

请勿使用内联CSS :)

这是一个简单的指令,当Angular完成加载并开始解释指令时,它会删除ng-cloak属性。

然后,您的代码通过正常的浏览器渲染机制切换为可见状态。


哈哈,我也不喜欢内联CSS。我会直接使用类语法再试一次。 - neemzy
1
我再试了一次,但仍然不起作用。我的所有JS都在body底部,因此我的标记在执行之前就被呈现出来了,而ng-cloak类可能是原因吗? - neemzy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接