AngularJS指令不会更新范围变量更改

Arm*_*min 66 javascript angularjs angularjs-directive angularjs-scope

我试图编写一个小指令,用其他模板文件包装其内容.

这段代码:

<layout name="Default">My cool content</layout>
Run Code Online (Sandbox Code Playgroud)

应该有这个输出:

<div class="layoutDefault">My cool content</div>
Run Code Online (Sandbox Code Playgroud)

因为布局"默认"具有以下代码:

<div class="layoutDefault">{{content}}</div>
Run Code Online (Sandbox Code Playgroud)

这里是指令的代码:

app.directive('layout', function($http, $compile){
return {
    restrict: 'E',
    link: function(scope, element, attributes) {
        var layoutName = (angular.isDefined(attributes.name)) ? attributes.name : 'Default';
        $http.get(scope.constants.pathLayouts + layoutName + '.html')
            .success(function(layout){
                var regexp = /^([\s\S]*?){{content}}([\s\S]*)$/g;
                var result = regexp.exec(layout);

                var templateWithLayout = result[1] + element.html() + result[2];
                element.html($compile(templateWithLayout)(scope));
            });
    }
}
Run Code Online (Sandbox Code Playgroud)

});

我的问题:

当我在模板中使用范围变量时(在布局模板中或布局标签内),例如.{{whatever}}它刚开始工作.如果我更新whatever变量,则指令不再更新.整个链接功能只会触发一次.

我认为,AngularJS不知道,该指令使用范围变量,因此不会更新.但我不知道如何解决这个问题.

Qua*_*arK 81

您应该创建一个绑定范围变量并观察其更改:

return {
   restrict: 'E',
   scope: {
     name: '='
   },
   link: function(scope) {
     scope.$watch('name', function() {
        // all the code here...
     });
   }
};
Run Code Online (Sandbox Code Playgroud)

  • 样式提示:正确的变量名称应该是`scope`而不是`$ scope`.在`link`函数中,范围是一个普通变量. (6认同)

Roy*_*der 41

我也需要这个问题的解决方案,我使用这个线程中的答案来提出以下内容:

.directive('tpReport', ['$parse', '$http', '$compile', '$templateCache', function($parse, $http, $compile, $templateCache)
    {
        var getTemplateUrl = function(type)
        {
            var templateUrl = '';

            switch (type)
            {
                case 1: // Table
                    templateUrl = 'modules/tpReport/directives/table-report.tpl.html';
                    break;
                case 0:
                    templateUrl = 'modules/tpReport/directives/default.tpl.html';
                    break;
                default:
                    templateUrl = '';
                    console.log("Type not defined for tpReport");
                    break;
            }

            return templateUrl;
        };

        var linker = function (scope, element, attrs)
        {

            scope.$watch('data', function(){
                var templateUrl = getTemplateUrl(scope.data[0].typeID);
                var data = $templateCache.get(templateUrl);
                element.html(data);
                $compile(element.contents())(scope);

            });



        };

        return {
            controller: 'tpReportCtrl',
            template: '<div>{{data}}</div>',
            // Remove all existing content of the directive.
            transclude: true,
            restrict: "E",
            scope: {
                data: '='
            },
            link: linker
        };
    }])
    ;
Run Code Online (Sandbox Code Playgroud)

包含在你的HTML中:

<tp-report data='data'></tp-report>
Run Code Online (Sandbox Code Playgroud)

该指令用于根据从服务器检索的数据集动态加载报告模板.

它在scope.data属性上设置监视,并且每当更新时(当用户从​​服务器请求新数据集时),它都会加载相应的指令以显示数据.


Pau*_*gel 16

您需要告诉Angular您的指令使用范围变量:

您需要将范围的某些属性绑定到您的指令:

return {
    restrict: 'E',
    scope: {
      whatever: '='
    },
   ...
}
Run Code Online (Sandbox Code Playgroud)

然后$watch呢:

  $scope.$watch('whatever', function(value) {
    // do something with the new value
  });
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅有关指令Angular文档.


Arm*_*min 8

我找到了一个更好的解决方案:

app.directive('layout', function(){
    var settings = {
        restrict: 'E',
        transclude: true,
        templateUrl: function(element, attributes){
            var layoutName = (angular.isDefined(attributes.name)) ? attributes.name : 'Default';
            return constants.pathLayouts + layoutName + '.html';
        }
    }
    return settings;
});
Run Code Online (Sandbox Code Playgroud)

我目前看到的唯一缺点是,被抄袭的模板有自己的范围.它们从父项获取值,但不是更改父项中的值,而是将值存储在自己的新子范围中.为了避免这种情况,我现在正在使用$parent.whatever而不是whatever.

例:

<layout name="Default">
    <layout name="AnotherNestedLayout">
        <label>Whatever:</label>
        <input type="text" ng-model="$parent.whatever">
    </layout>
</layout>
Run Code Online (Sandbox Code Playgroud)