source

directive link 함수에 ng-click을 동적으로 추가합니다.

ittop 2023. 3. 13. 20:54
반응형

directive link 함수에 ng-click을 동적으로 추가합니다.

요소를 클릭 가능 또는 클릭 불가능으로 정의할 수 있는 디렉티브를 작성하려고 합니다.이 디렉티브는 다음과 같습니다.

<page is-clickable="true">
    transcluded elements...
</page>

결과 HTML은 다음과 같습니다.

<page is-clickable="true" ng-click="onHandleClick()">
    transcluded elements...
</page>

이 명령어의 실장은 다음과 같습니다.

app.directive('page', function() {
    return {
        restrict: 'E',
        template: '<div ng-transclude></div>',
        transclude: true,
        link: function(scope, element, attrs) {
            var isClickable = angular.isDefined(attrs.isClickable) && scope.$eval(attrs.isClickable) === true ? true : false;

            if (isClickable) {
                attrs.$set('ngClick', 'onHandleClick()');
            }

            scope.onHandleClick = function() {
                console.log('onHandleClick');
            };
        }
    };
});

새로운 Atribute를 추가한 후 Angular는 이 Atribute에 대해ng-click, 따라서, 기동하고 있지 않습니다.추가하려고 했습니다.$compileAtribute가 설정된 후, 단, 무한 링크/패킷 루프가 발생합니다.

그냥 내부를 확인할 수 있어요onHandleClick()기능하다isClickable값은true근데 어떻게 해야 될지 궁금하네요.다이나믹하게 추가해서ng-click여러 개의 다른 이벤트와 함께 이 작업을 수행해야 할 수 있기 때문에 이벤트.ng-*불필요한 오버헤드를 추가하고 싶지 않습니다.좋은 생각 있어요?

뛰어난 솔루션 (신규):

Angular documents를 읽은 후 다음과 같은 사실을 알게 되었습니다.

템플릿을 나타내는 문자열 또는 tElement 및 tAttrs(아래 컴파일 함수 api에서 설명)의 2개의 인수를 사용하여 템플릿을 나타내는 문자열 값을 반환하는 함수로 템플릿을 지정할 수 있습니다.

그래서 저의 새로운 지시는 다음과 같습니다. (이것이 이런 종류의 일에 대해 적절한 "각적" 방법이라고 생각합니다.)

app.directive('page', function() {
    return {
        restrict: 'E',
        replace: true,
        template: function(tElement, tAttrs) {
            var isClickable = angular.isDefined(tAttrs.isClickable) && eval(tAttrs.isClickable) === true ? true : false;

            var clickAttr = isClickable ? 'ng-click="onHandleClick()"' : '';

            return '<div ' + clickAttr + ' ng-transclude></div>';
        },
        transclude: true,
        link: function(scope, element, attrs) {
            scope.onHandleClick = function() {
                console.log('onHandleClick');
            };
        }
    };
});

새로운 템플릿 기능에 주목해 주세요.이제 컴파일하기 전에 해당 함수 내에서 템플릿을 조작합니다.

대체 솔루션(구):

추가된replace: true명령어를 다시 컴파일할 때 무한 루프 문제를 제거합니다.링크 기능에서는 새로운 속성을 추가한 후 요소를 다시 컴파일합니다.한 가지 주의할 게 있는데ng-transclude두 번째 컴파일에서는 어떤 것도 제외하려고 하지 않기 위해 요소를 삭제해야 했습니다.왜냐하면 제외할 것이 없기 때문입니다.

현재 제 지시는 다음과 같습니다.

app.directive('page', function() {
    return {
        restrict: 'E',
        replace: true,
        template: '<div ng-transclude></div>',
        transclude: true,
        link: function(scope, element, attrs) {
            var isClickable = angular.isDefined(attrs.isClickable) && scope.$eval(attrs.isClickable) === true ? true : false;

            if (isClickable) {
                attrs.$set('ngClick', 'onHandleClick()');
                element.removeAttr('ng-transclude');
                $compile(element)(scope);
            }

            scope.onHandleClick = function() {
                console.log('onHandleClick');
            };
        }
    };
});

두 번째 템플릿을 다시 컴파일하는 것은 바람직하지 않다고 생각하기 때문에 첫 번째 템플릿을 컴파일하기 전에 아직 방법이 있다고 생각합니다.

언제든지 ng-click을 다음과 같이 변경할 수 있습니다.

ng-click="isClickable && someFunction()"

커스텀 디렉티브는 필요 없습니다:)

다음은 JSFiddle 데모입니다.http://jsfiddle.net/robianmcd/5D4VR/

갱신된 답변

"The Angular Way"는 수동 DOM 조작이 전혀 아닙니다.그래서 애트리뷰트 추가 및 삭제를 없애야 합니다.

DEMO

템플릿을 다음으로 변경합니다.

template: '<div ng-click="onHandleClick()" ng-transclude></div>'

'에서 'Directive Check'는 'Directive Check'입니다.isClickable속성을 클릭하여 수행할 작업을 결정합니다.

    link: function(scope, element, attrs) {
        var isClickable = angular.isDefined(attrs.isClickable) && scope.$eval(attrs.isClickable) === true ? true : false;

        scope.onHandleClick = function() {
            if (!isClickable) return;
            console.log('onHandleClick');
        };
    }

isClickable Atribute를 디렉티브스코프에 배치하여 동작을 동적으로 변경할 수도 있습니다.

구답(오답)

link는 템플릿 컴파일 후에 실행됩니다.controller" " " " " : "

app.directive('page', function() {
    return {
        restrict: 'E',
        template: '<div ng-transclude></div>',
        transclude: true,
        controller: function(scope, element, attrs) {
            // your code
        }
    };
});

HTML

<div page is-clickable="true">hhhh</div>

JS

app.directive('page', function($compile) {
                return {
                    priority:1001, // compiles first
                    terminal:true, // prevent lower priority directives to compile after it
                    template: '<div ng-transclude></div>',
                    transclude: true,
                    compile: function(el,attr,transclude) {
                        el.removeAttr('page'); // necessary to avoid infinite compile loop
                        var contents = el.contents().remove();
                        var compiledContents;
                        return function(scope){
                            var isClickable = angular.isDefined(attr.isClickable)?scope.$eval(attr.isClickable):false;
                            if(isClickable){
                                el.attr('ng-click','onHandleClick()');
                                var fn = $compile(el);
                                fn(scope);
                                scope.onHandleClick = function() {
                                    console.log('onHandleClick');
                                };
                            }
                            if(!compiledContents) {
                                compiledContents = $compile(contents, transclude);
                            }
                            compiledContents(scope, function(clone, scope) {
                                el.append(clone); 
                            });

                        };
                    },
                    link:function(scope){

                    }


                };
            });

에르스타드 덕분이야스티븐일란 프루머

브라우저가 'E'로 크래시된 BTW: (

이것은 속성 지원도 추가한 @DiscGolfer 솔루션 버전입니다.

.directive("page", function() {

  return {
    transclude: true,
    replace: true,
    template: function(tElement, tAttr) {

      var isClickable = angular.isDefined(tAttrs.isClickable) && eval(tAttrs.isClickable) === true ? true : false;

      if (isClickable) {
        tElement.attr("ng-click", "onHandleClick()");
      }
      tElement.attr("ng-transclude", "");
      if (tAttr.$attr.page === undefined) {
        return "<" + tElement[0].outerHTML.replace(/(^<\w+|\w+>$)/g, 'div') + ">";
      } else {
        tElement.removeAttr(tAttr.$attr.page);
        return tElement[0].outerHTML;
      }
    }

  };

보다 범용적이고 완전한 샘플이 제공됩니다.http://plnkr.co/edit/4PcMnpq59ebZr2VrOI07?p=preview

한 문제는 '이러한 문제'라는 것입니다.replace는 AngularAngular에서 더 사용되지 않습니다.JS.

이렇게 하는 게 좋을 것 같아요.

app.directive('page', function() {
    return {
        restrict: 'E',
        template: '<div ng-transclude></div>',
        transclude: true,
        link: function(scope, element, attrs) {
            var isClickable = angular.isDefined(attrs.isClickable) && scope.$eval(attrs.isClickable) === true ? true : false;

            if (isClickable) {
                angular.element(element).on('click', scope.onHandleClick);
            }

            scope.onHandleClick = function() {
                console.log('onHandleClick');
            };
        }
    };
});
module.factory("ibDirectiveHelpers", ["ngClickDirective", function (ngClick) {
        return {
            click: function (scope, element, fn) {
                var attr = {ngClick: fn};
                ngClick[0].compile(element, attr)(scope, element, attr);
            }
        };
    }]);

용도:

module.controller("demoController",["$scope","$element","ibDirectiveHelpers",function($scope,$element,ibDirectiveHelpers){

$scope.demoMethod=function(){console.log("demoMethod");};
ibDirectiveHelpers.click($scope,$element,"demoMethod()");//uses html notation
 //or
ibDirectiveHelpers.click($scope,$element,function(){$scope.demoMethod();});//uses inline notation
}]

언급URL : https://stackoverflow.com/questions/22116470/add-ng-click-dynamically-in-directive-link-function

반응형