AngularJS-如何以编程方式创建新的隔离范围?


81

我想用Angular.factory创建一个AlertFactory。我定义了一个HTML模板,如下所示

var template = "<h1>{{title}}</h1>";

标题由调用控制器提供,并按以下方式应用

var compiled = $compile(template)(scope);
body.append(compiled);

那么,如何将隔离范围从控制器传递到工厂?我在控制器中遵循代码

AlertFactory.open($scope);

但是$ scope是全局控制器作用域变量。我只想为带有title属性的工厂传递一个小的范围。

谢谢。

Answers:


107

您可以手动创建新的作用域。

您可以从$rootScope注入的范围创建新的范围,也可以从控制器范围创建新的范围-这无关紧要,因为您将其隔离了。

var alertScope = $scope.$new(true);
alertScope.title = 'Hello';

AlertFactory.open(alertScope);

此处的关键是传递true$new,该接受的一个参数isolate,从而避免从父级继承范围。

可以在以下位置找到更多信息:http : //docs.angularjs.org/api/ng.$ro​​otScope.Scope#$new


10
如果您手动创建新的作用域,则可能还必须手动销毁它。通常最好不要手动创建范围。
Mark Rajcok

我已经做了测试,但是没有用。请看看stackoverflow.com/questions/15565462/...
总理

3
您提到@MarkRajcok,通常最好不要手动创建范围。但是,如果您需要动态创建html并想在该html中使用angular指令,该怎么办?
lostintranslation 2015年

救生员!必须这样做,因为我正在为Angular Bootstrap Modal编写包装器。
乔纳森

9
创建子范围(隔离或不隔离)时,Angular在销毁其父级时会自动销毁它。因此,在此示例中,何时$scope销毁alertScope也会自动销毁。所以@MarkRajcok这是一个完全有效的用例,并且非常安全。
jkjustjoshing

22

如果只需要插值,请使用$ interpolate服务而不是$ compile,则不需要范围:

myApp.factory('myService', function($interpolate) {
    var template = "<h1>{{title}}</h1>";
    var interpolateFn = $interpolate(template);
    return {
        open: function(title) {
            var html = interpolateFn({ title: title });
            console.log(html);
            // append the html somewhere
        }
    }
});

测试控制器:

function MyCtrl($scope, myService) {
    myService.open('The Title');
}

小提琴


2
$ compile和$ interpolate有什么区别?$ interpolate只能替换文本吗?
2013年

3
@总理,这是我的理解。另请参见stackoverflow.com/a/13460295/215945 如果您的模板包含指令,则$ interpolate将不起作用-为此,您需要使用$ compile。
Mark Rajcok 2013年

好的谢谢。我的任务还不够,我需要一个具有完整范围的控制器。
2013年

1
@总理,我建议您尝试创建一个小提琴或小品。目前尚不清楚您的隔离范围来自何处。
Mark Rajcok

哦,是的,我已经做了一个stackoverflow.com/questions/15565462/...
总理

2

以下是步骤:

  1. 通过使用将HTML添加到DOM var comiledHTML = angular.element(yourHTML);
  2. 如果需要,创建一个新的范围 var newScope = $rootScope.$new();
  3. 调用$ comile(); 返回链接功能的功能var linkFun = $compile(comiledHTML);
  4. 通过调用linkFun绑定新作用域 var finalTemplate = linkFun(newScope);
  5. 将finalTemplate附加到您的DOM YourHTMLElemet.append(finalTemplate);

1
var linkFun = $compile(comiledHTML);第2步开始
iamdevlinph,

2

看看我的朋克。我正在以编程方式生成带有render指令的widget指令。

https://plnkr.co/edit/5T642U9AiPr6fJthbVpD?p=preview

angular
  .module('app', [])
  .controller('mainCtrl', $scope => $scope.x = 'test')
  .directive('widget', widget)
  .directive('render', render)

function widget() {
  return {
    template: '<div><input ng-model="stuff"/>I say {{stuff}}</div>'
  }
}

function render($compile) {
  return {
    template: '<button ng-click="add()">{{name}}</button><hr/>',
    link: linkFn
  }

  function linkFn(scope, elem, attr) {
    scope.name = 'Add Widget';
    scope.add = () => {
      const newScope = scope.$new(true);
      newScope.export = (data) => alert(data);
      const templ = '<div>' +
                      '<widget></widget>' +
                      '<button ng-click="export(this.stuff)">Export</button>' +
                    '</div>';
      const compiledTempl = $compile(templ)(newScope);
      elem.append(compiledTempl);
    }
  }
}

1

我假设当您谈论隔离范围时,您在谈论的是指令。

这是一个如何做的例子。 http://jsfiddle.net/rgaskill/PYhGb/

var app = angular.module('test',[]);

app.controller('TestCtrl', function ($scope) {
    $scope.val = 'World';
});

app.factory('AlertFactory', function () {

    return {
        doWork: function(scope) {
            scope.title = 'Fun';    
            //scope.title = scope.val;  //notice val doesn't exist in this scope
        }
    };

});

app.controller('DirCtrl', function ($scope, AlertFactory) {
    AlertFactory.doWork($scope);  
});

app.directive('titleVal',function () {
    return {
        template: '<h1>Hello {{title}}</h1>',
        restrict: 'E',
        controller: 'DirCtrl',
        scope: {
            title: '='
        },
        link: function() {

        }
    };

});

基本上,将控制器附加到已定义隔离范围的指令。注入到指令控制器中的作用域将是一个隔离作用域。在指令控制器中,您可以将AlertFactory注入其中,并将隔离范围传递给它。


grrr..plnkr.co现在似乎已离线。希望该链接在返回时仍然有效。
rgaskill

嗯,我认为这对我来说不是一个好的解决方案,我不需要指令。我需要一个能够显示模式警报对话框的工厂。所以我需要在dom覆盖中附加html模板,并使用控制器来管理警报视图中的数据。
2013年

2
我会说你不应该在工厂里操纵dom。您正在将视图逻辑与业务逻辑混合在一起。您可以完全按照您应该在其中进行dom操作的指令中的描述进行操作。
rgaskill

参见布拉德·格林(Brad Green)对安迪(Andy)的答复,内容涉及将服务用于模式而不是指令:blog.angularjs.org/2012/11/about-those-directives.html
Mark Rajcok 2013年

...但是对于这种特殊的引导情况,我认为最好用指令解决。 plnkr.co/edit/z4J8jH?p=preview
rgaskill
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.