簡體   English   中英

在angular中的指令內添加屬性指令

[英]Add attribute directive inside directive in angular

我正在以角度創建驗證指令,我需要在指令綁定的元素中添加工具提示。

通過網絡閱讀我發現這個解決方案設置了一個高優先級和終端指令,但由於我使用的是ngModel,這對我不起作用。 這就是我現在正在做的事情:

return {
        restrict: 'A',
        require: 'ngModel',
        replace: false,
        terminal: true,
        priority: 1000,
        scope: {
            model: '=ngModel',
            initialValidity: '=initialValidity',
            validCallback: '&',
            invalidCallback: '&'
        },
        compile: function compile(element, attrs) {
            element.attr('tooltip', '{{validationMessage}');
            element.removeAttr("validator");
            return {
                post: function postLink(scope, element) {
                  $compile(element)(scope);
                }
            };
        },
}

但這對我不起作用。 它會引發以下錯誤:

錯誤:[$ compile:ctreq]無法找到指令'validator'所需的控制器'ngModel'!

這是我正在使用該指令的HTML:

<input id="username" name="username" data-ng-model="user.username" type="text" class="form-control" validator="required, backendWatchUsername" placeholder="johndoe" tabindex="1" >

關於如何解決這個問題的任何想法?

謝謝。

原因是您的指令priorityterminal選項的組合。 這意味着ngModel指令根本不會呈現。 由於您的指令優先級( 1000 )大於ng-model( 0 ),並且terminal選項的存在不會呈現任何其他具有較低優先級(超過1000)的指令。 所以一些可能的選擇是:

  • 從指令中刪除終端選項或
  • 將指令的優先級降低到0或-1(小於或等於ngModel)或
  • 從指令中刪除ng-model要求,並可能使用雙向綁定,例如ngModel:"=" (基於適合您的要求)。
  • 您可以在指令中使用transclusion並使用指令模板,而不是添加tooltip屬性並重新編譯元素。

terminal - 如果設置為true,則當前優先級將是將執行的最后一組指令(當前優先級的任何指令仍將執行,因為未定義相同優先級的執行順序)。 請注意,指令模板中使用的表達式和其他指令也將從執行中排除。

演示

 angular.module('app', []).directive('validator', function($compile) { return { restrict: 'A', require: 'ngModel', replace: false, terminal: true, scope: { model: '=ngModel', initialValidity: '=initialValidity', validCallback: '&', invalidCallback: '&' }, compile: function compile(element, attrs) { element.attr('tooltip', '{{validationMessage}'); element.removeAttr("validator"); return { post: function postLink(scope, element) { $compile(element)(scope); } }; }, } }) 
 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> <div ng-app="app"> <input validator ng-model="test"> </div> 

正如我在評論中所解釋的那樣,您不需要重新編譯元素和所有這些內容,只需設置一個元素並將其附加到目標元素之后(在您的特定情況下,輸入)。

這是驗證指令的修改版本(我沒有實現任何驗證細節,我相信你應該能夠輕松連接)。

所以你需要的是為工具提示設置自定義觸發器,你可以使用$tooltipprovider 因此,當您想要顯示/隱藏工具提示時,請設置一個事件對。

.config(function($tooltipProvider){
    $tooltipProvider.setTriggers({'show-validation':'hide-validation'});
});

現在,在您的指令中,只需使用工具提示屬性設置工具提示元素即可。 僅編譯工具提示元素,將其追加after的目標元素(可以ofcourse管理與CSS定位)。 當你有驗證失敗時,只需獲取tooltip element reference (這是對工具提示元素的引用,而不是復制每次使用選擇器時都可以選擇的引用)並執行$tooltipEl.triggerHandler('show-validation')和隱藏$tooltipEl.triggerHandler('show-validation')

示例實現,顯示2秒后的工具提示,並在5秒后隱藏它(因為驗證不在此問題的范圍內,您應該能夠連接它):

.directive('validator', function($compile, $timeout){

  var tooltiptemplate = '<span class="validation" tooltip="{{validationMessage}}" tooltip-trigger="show-validation" tooltip-placement="bottom"></span>';
  var tooltipEvents = {true:'show-validation', false:'hide-validation'};

  return {
        restrict: 'A',
        require: 'ngModel',
        replace: false,
        priority: 1000,
        scope: {
            model: '=ngModel',
            initialValidity: '=initialValidity',
            validCallback: '&',
            invalidCallback: '&'
        },
        compile: function compile(element, attrs) {


            return {
                post: function postLink(scope, element) {

                  var $tooltipEl= getTooltip();


                  init();

                  function init(){
                   scope.$on('$destroy', destroy);
                   scope.validationMessage ="Whoops!!!";

                   $timeout(function(){
                    toggleValidationMessage(true);
                   },2000);

                   $timeout(function(){
                     toggleValidationMessage(false);
                   },5000);
                 }

                 function toggleValidationMessage(show){
                   $tooltipEl.triggerHandler(tooltipEvents[show]);
                 }



                 function getTooltip(){
                     var elm = $compile(angular.element(tooltiptemplate))(scope);
                     element.after(elm);
                     return elm;
                 }

                 function destroy(){
                    $tooltipEl= null;
                 }

                }
            };
        },
  }

});

Plnkr

內聯演示

 var app = angular.module('plunker', ['ui.bootstrap']); app.controller('MainCtrl', function($scope) { $scope.user = { username: 'jack' }; }).directive('validator', function($compile, $timeout) { var tooltiptemplate = '<span class="validation" tooltip="{{model}}" tooltip-trigger="show-validation" tooltip-placement="bottom"></span>'; var tooltipEvents = { true: 'show-validation', false: 'hide-validation' }; return { restrict: 'A', require: 'ngModel', replace: false, priority: 1000, scope: { model: '=ngModel', initialValidity: '=initialValidity', validCallback: '&', invalidCallback: '&' }, compile: function compile(element, attrs) { return { post: function postLink(scope, element) { var $tooltipEl = getTooltip(); init(); function init() { scope.$on('$destroy', destroy); scope.validationMessage = "Whoops!!!"; $timeout(function() { toggleValidationMessage(true); }, 2000); $timeout(function() { toggleValidationMessage(false); }, 5000); } function toggleValidationMessage(show) { $tooltipEl.triggerHandler(tooltipEvents[show]); } function getTooltip() { var elm = $compile(angular.element(tooltiptemplate))(scope); element.after(elm); return elm; } function destroy() { elm = null; } } }; }, } }).config(function($tooltipProvider) { $tooltipProvider.setTriggers({ 'show-validation': 'hide-validation' }); }); 
 /* Put your css in here */ .validation { display: block; } 
 <!DOCTYPE html> <html ng-app="plunker"> <head> <meta charset="utf-8" /> <title>AngularJS Plunker</title> <link data-require="bootstrap-css@3.1.*" data-semver="3.1.1" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" /> <script> document.write('<base href="' + document.location + '" />'); </script> <script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.12/angular.js" data-semver="1.3.12"></script> <script data-require="ui-bootstrap@*" data-semver="0.12.0" src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.12.0.min.js"></script> </head> <body ng-controller="MainCtrl"> <br/> <br/>{{user.username}} <input id="username" name="username" data-ng-model="user.username" type="text" class="form-control" validator="required, backendWatchUsername" placeholder="johndoe" tabindex="1"> </body> </html> 

您不應該在指令中創建一個新的隔離范圍:這將搞亂其他指令(在這種情況下不會共享ngModel)。

return {
    restrict: 'A',
    require: 'ngModel',
    compile: function compile(element, attrs) {
        element.attr('tooltip', '{{validationMessage}');
        element.removeAttr("validator");
        return {
            post: function postLink(scope, element) {
              $compile(element)(scope);
            }
        };
    },
}

我邀請您查看Angular-UI庫,特別是他們如何實現他們的ui.validate指令: http ://angular-ui.github.io/ui-utils/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM