AngularJS-프로그래밍 방식으로 격리 된 새 범위를 어떻게 만들 수 있습니까?


81

Angular.factory로 AlertFactory를 만들고 싶습니다. 다음과 같은 html 템플릿을 정의했습니다.

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

제목은 컨트롤러를 호출하여 제공되며 다음과 같이 적용됩니다.

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

그렇다면 컨트롤러에서 공장으로 격리 된 범위를 어떻게 전달할 수 있습니까? 컨트롤러에서 코드를 사용하고 있습니다.

AlertFactory.open($scope);

그러나 $ scope는 전역 컨트롤러 범위 변수입니다. 제목 속성만으로 공장에 대한 작은 범위를 전달하고 싶습니다.

감사합니다.

답변:


107

새 범위를 수동으로 만들 수 있습니다.

새 스코프 $rootScope를 삽입하는 경우 또는 컨트롤러 스코프에서 생성 할 수 있습니다. 이것은 격리 될 것이기 때문에 중요하지 않습니다.

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

AlertFactory.open(alertScope);

여기서 핵심은에 대한 하나의 매개 변수를 허용 하는에 전달 true하는 것입니다 $new. 이는 isolate상위로부터 범위를 상속하지 않도록합니다.

자세한 내용은 http://docs.angularjs.org/api/ng.$rootScope.Scope#$new 에서 찾을 수 있습니다.


10
새 범위를 수동으로 생성하는 경우 수동으로 제거해야 할 수도 있습니다. 일반적으로 범위를 수동으로 생성하지 않는 것이 좋습니다.
Mark Rajcok 2013 년

테스트를했지만 작동하지 않습니다. 제발 봐 stackoverflow.com/questions/15565462/...
프리미어

3
@MarkRajcok 당신은 일반적으로 범위를 수동으로 생성하지 않는 것이 더 낫다고 언급했습니다. 그러나 html을 동적으로 작성하고 해당 html 내에서 각도 지시문을 사용하려는 경우 대안은 무엇입니까?
lostintranslation

생명의 은인! Angular Bootstrap Modal에 대한 래퍼를 작성하면서 이렇게해야했습니다 .
Jonathan

9
자식 범위를 만들면 (격리 또는 분리하지 않음) Angular는 부모가 소멸 될 때 자동으로 소멸합니다. 따라서이 예에서는 언제 $scope파괴 alertScope되는지도 자동으로 파괴됩니다. 그래서 @MarkRajcok 이것은 완벽하게 유효한 사용 사례이며 완벽하게 안전합니다.
jkjustjoshing jul.

22

보간 만 필요한 경우 $ compile 대신 $ interpolate 서비스를 사용하면 범위가 필요하지 않습니다.

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는 텍스트 만 교체합니까?
프리미어

3
@Premier, 그것이 내 이해입니다. stackoverflow.com/a/13460295/215945를 참조 하십시오. 템플릿에 지시문이 포함되어 있으면 $ interpolate가 작동하지 않습니다.이를 위해 $ compile을 사용해야합니다.
Mark Rajcok 2013 년

네, 감사합니다. 내 작업으로는 충분하지 않습니다. 완전한 범위의 컨트롤러가 필요합니다.
Premier

1
@Premier, 나는 당신이 시도하는 것을 바이올린이나 플 런커를 만드는 것이 좋습니다. 격리 범위의 출처가 명확하지 않습니다.
Mark Rajcok 2013 년

아, 네, 내가 한 짓을했는지 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. DOM에 finalTemplate 추가 YourHTMLElemet.append(finalTemplate);

1
에서 var linkFun = $compile(comiledHTML);2 단계에
iamdevlinph

2

내 plunkr를 확인하십시오. 렌더링 지시문을 사용하여 프로그래밍 방식으로 위젯 지시문을 생성하고 있습니다.

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 2013 년

저에게 좋은 해결책이 아니라고 생각합니다. 지시는 필요하지 않습니다. 모달 경고 대화 상자를 표시 할 수있는 공장 기능이 필요합니다. 그래서 dom 오버레이에 템플릿 html을 첨부하고 컨트롤러를 사용하여 경고보기에서 데이터를 관리해야합니다.
Premier

2
나는 당신이 공장에서 돔을 조작해서는 안된다고 주장합니다. 뷰 로직을 비즈니스 로직과 혼합하고 있습니다. dom 조작이 발생해야하는 지시문에서 설명한대로 정확하게 수행 할 수 있습니다.
rgaskill 2013 년

지시문이 아닌 모달 용 서비스 사용에 관한 Andy에 대한 Brad Green의 답변을 참조하십시오. blog.angularjs.org/2012/11/about-those-directives.html
Mark Rajcok 2013 년

...하지만이 특정 부트 스트랩 케이스의 경우 지시문으로 해결하는 것이 가장 좋다고 생각합니다. plnkr.co/edit/z4J8jH?p=preview
rgaskill
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.