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

격리 된 범위를 사용하지 않고 지시문 내에서 부모 범위의 함수를 호출하는 방법을 찾을 수없는 것 같습니다. 격리 된 범위를 사용하는 경우 격리 된 영역에서 “&”를 사용하여 부모 범위의 함수에 액세스 할 수 있지만 필요하지 않은 경우 격리 된 범위를 사용하면 결과가 발생한다는 것을 알고 있습니다. 다음 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 () 호출이 작동하지 않으며 작동하는 방법을 모릅니다.

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

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



답변

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

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

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

scope.$apply(attrs.confirmAction);

깡깡이


답변

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를 사용하여 속성을 설정하는 것과 관련이 있지만 여기에 오면 그 다리를 건너도록하겠습니다.


답변

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>


답변

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

여기에 격리 된 범위를 사용하지 않고 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]();
      }
    });
  }


답변