AngularJS에서 격리 된 범위없이 지시문에서 컨트롤러 함수 호출


95

격리 된 범위를 사용하지 않고 지시문 내에서 부모 범위의 함수를 호출하는 방법을 찾을 수없는 것 같습니다. 격리 된 범위를 사용하는 경우 격리 된 영역에서 "&"를 사용하여 부모 범위의 함수에 액세스 할 수 있지만 필요하지 않은 경우 격리 된 범위를 사용하면 결과가 발생한다는 것을 알고 있습니다. 다음 HTML을 고려하십시오.

<button ng-hide="hideButton()" confirm="Are you sure?" confirm-action="doIt()">Do It</button>

이 간단한 예제에서는 JavaScript 확인 ​​대화 상자를 표시하고 확인 대화 상자에서 "확인"을 클릭하는 경우에만 doIt ()을 호출하려고합니다. 격리 된 범위를 사용하면 간단합니다. 지시문은 다음과 같습니다.

.directive('confirm', function () {
    return {
        restrict: 'A',
        scope: {
            confirm: '@',
            confirmAction: '&'
        },
        link: function (scope, element, attrs) {
            element.bind('click', function (e) {
                if (confirm(scope.confirm)) {
                    scope.confirmAction();
                }
            });
        }
    };
})

그러나 문제는 격리 된 범위를 사용하고 있기 때문에 위의 예제에서 ng-hide는 더 이상 부모 범위에 대해 실행되지 않고 격리 된 범위에서 실행 됩니다 (모든 지시문에서 격리 된 범위를 사용하면 해당 요소의 모든 지시문이 격리 된 범위 사용). 다음은 ng-hide가 작동하지 않는 위 예제 의 jsFiddle 입니다. (이 바이올린에서는 입력 상자에 "예"를 입력 할 때 버튼이 숨겨져 야합니다.)

대안은 격리 된 범위를 사용하지 않는 것입니다.이 지시문의 범위를 격리 할 필요가 없기 때문에 실제로 여기에서 원하는 것입니다. 내가 가진 유일한 문제는 격리 된 범위에서 전달하지 않으면 부모 범위에서 메서드를 어떻게 호출 합니까?

여기에 격리 된 범위를 사용하지 않고 ng-hide가 잘 작동 하는 jsfiddle 이 있지만 물론 confirmAction () 호출이 작동하지 않으며 작동하는 방법을 모릅니다.

내가 정말로 찾고있는 대답은 격리 된 범위를 사용하지 않고 외부 범위에서 함수를 호출하는 방법입니다. 이 확인 대화를 다른 방식으로 작동시키는 데 관심이 없습니다.이 질문의 요점은 외부 범위를 호출하는 방법을 알아 내고 부모 범위에 대해 다른 지시문이 작동하도록하는 것입니다.

또는 다른 지시문이 부모 범위에 대해 여전히 작동하는 경우 격리 된 범위를 사용하는 솔루션에 대해 듣고 싶지만 이것이 가능하다고 생각하지 않습니다.


지나가는 사람들을 위해 Dan Wahlin은 격리 범위 및 함수 매개 변수를 설명하는 매우 좋은 기사를 작성했습니다. weblogs.asp.net/dwahlin/…
tanguy_k

답변:


117

지시문은 함수 만 호출하기 때문에 (속성에 값을 설정하려고하지 않음) $ parse 대신 $ eval을 사용할 수 있습니다 (분리되지 않은 범위 포함).

scope.$apply(function() {
    scope.$eval(attrs.confirmAction);
});

또는 더 나은 방법은 $ apply를 사용 하면 $ eval ()이 범위에 대해 인수를 계산합니다.

scope.$apply(attrs.confirmAction);

깡깡이


몰랐습니다. 감사합니다. 나는 항상 $ parse 메소드가 너무 장황하다고 생각했습니다.
Clark Pan

2
그 함수에 매개 변수를 어떻게 설정 하시겠습니까?
CMCDragonkai 2013 년

2
@CMCDragonkai, 함수에 인수가있는 경우 HTML에 인수를 지정한 confirm-action="doIt(arg1)"다음 scope.arg1$ eval을 호출하기 전에 설정할 수 있습니다. 그러나 $ parse를 사용하는 것이 더
깨끗할

scope. $ eval (attrs.doIt ({arg1 : 'blah'}) ;?
CMCDragonkai

3
@CMCDragonkai, 아니, scope.$eval(attrs.confirmAction({arg1: 'blah'})작동하지 않습니다. 해당 구문에 $ parse를 사용해야합니다.
Mark Rajcok 2013 년

17

AngularJS에서 $ parse 서비스를 사용하고 싶습니다.

따라서 귀하의 예를 들어 :

.directive('confirm', function ($parse) {
    return {
        restrict: 'A',

        // Child scope, not isolated
        scope : true,
        link: function (scope, element, attrs) {
            element.bind('click', function (e) {
                if (confirm(attrs.confirm)) {
                    scope.$apply(function(){

                        // $parse returns a getter function to be 
                        // executed against an object
                        var fn = $parse(attrs.confirmAction);

                        // In our case, we want to execute the statement in 
                        // confirmAction i.e. 'doIt()' against the scope 
                        // which this directive is bound to, because the 
                        // scope is a child scope, not an isolated scope. 
                        // The prototypical inheritance of scopes will mean 
                        // that it will eventually find a 'doIt' function 
                        // bound against a parent's scope.
                        fn(scope, {$event : e});
                    });
                }
            });
        }
    };
});

$ parse를 사용하여 속성을 설정하는 것과 관련이 있지만 여기에 오면 그 다리를 건너도록하겠습니다.


고마워, 클락 내가 찾던 바로 그거야 나는 $ parse를 사용해 보았지만 범위를 전달하지 못했기 때문에 작동하지 않았습니다. 이것은 완벽 해요.
Jim Cooper

이 솔루션이 범위 없이도 작동한다는 사실에 놀랐습니다. 내 이해는 범위 : true는 지시문의 범위가 부모 범위에서 프로토 타입으로 상속되도록 만드는 것입니다. 왜 이것이 그것 없이도 여전히 작동하는지 아십니까?
Jim Cooper

2
scope:true지시문이 새 범위를 전혀 만들지 않기 때문에 자식 범위 (삭제 )가 작동하지 않으므로 함수 scope에서 참조 하는 속성 link은 이전의 '부모'범위와 정확히 동일한 범위입니다.
Clark Pan

이 경우 $ apply로 충분합니다 (내 답변 참조).
Mark Rajcok 2013

1
$ 이벤트는 무엇입니까?
CMCDragonkai 2013 년

12

hideButton부모 범위를 명시 적으로 호출 합니다.

여기 바이올린이 있습니다 : http://jsfiddle.net/pXej2/5/

업데이트 된 HTML은 다음과 같습니다.

<div ng-app="myModule" ng-controller="myController">
    <input ng-model="showIt"></input>
    <button ng-hide="$parent.hideButton()" confirm="Are you sure?" confirm-action="doIt()">Do It</button>
</div>

작동하는 솔루션의 경우 +1. 나는 실제로 $ parent 사용을 시도했지만 작동하지 않을 때 포기했습니다. 귀하의 솔루션을 본 후 자세히 살펴 보았는데 전달하는 매개 변수에 $ parent를 추가하지 못한 것으로 나타났습니다 (원래 바이올린에는 표시되지 않음). 예를 들어 showIt을 hideButton () 함수에 전달하려면 $ parent.hideButton ($ parent.showIt)을 사용해야하고 두 번째 $ parent가 누락되었습니다. 그러나이 솔루션은 내 지시의 사용자가 $ parent를 추가해야한다는 것을 알 필요가 없기 때문에 Clark의 대답을 받아 들일 것입니다. 통찰력에 감사드립니다!
Jim Cooper

1

내가 가진 유일한 문제는 격리 된 범위에 전달하지 않으면 부모 범위에서 메서드를 어떻게 호출합니까?

여기에 격리 된 범위를 사용하지 않고 ng-hide가 잘 작동하는 jsfiddle이 있지만 물론 confirmAction ()에 대한 호출이 작동하지 않으며 작동하는 방법을 모릅니다.

먼저 작은 요점 :이 경우 외부 컨트롤러의 범위는 지시문 범위의 상위 범위가 아닙니다. 외부 컨트롤러의 범위 지시문의 범위입니다. 즉, 지시문에 사용 된 변수 이름은 컨트롤러의 범위에서 직접 조회됩니다.

다음으로, 이 버튼 attrs.confirmAction()은 쓰기 가 작동하지 않습니다 attrs.confirmAction.

<button ... confirm-action="doIt()">Do It</button>

"doIt()"문자열이며, 예를 들어 문자열을 호출 할 수 없습니다 "doIt()"().

귀하의 질문은 실제로 다음과 같습니다.

이름이 문자열 인 경우 함수를 어떻게 호출합니까?

JavaScript에서는 주로 다음과 같이 점 표기법을 사용하여 함수를 호출합니다.

some_obj.greet()

그러나 배열 표기법을 사용할 수도 있습니다.

some_obj['greet']

인덱스 값이 어떻게 문자열 인지 주목하십시오 . 따라서 지시문에서 간단히 다음과 같이 할 수 있습니다.

  link: function (scope, element, attrs) {

    element.bind('click', function (e) {

      if (confirm(attrs.confirm)) {
        var func_str = attrs.confirmAction;
        var func_name = func_str.substring(0, func_str.indexOf('(')); // Or func_str.match(/[^(]+/)[0];
        func_name = func_name.trim();

        console.log(func_name); // => doIt
        scope[func_name]();
      }
    });
  }

+1 함수를 구문 분석하는 아이디어가 까다로 웠고 비슷하지만 또 다른 문제로 나를 도왔습니다. 감사!
Anmol Saraf
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.