<input ng-model="user.password" ng-minlength="6" form-password form-error=" 6 ">
ng-model
ng-minlength
form-password
- replaces the input with its own template and changes the field type (password / text) when clicking on the eyeform-error
- shows error error if the password is not long enoughform-error-tooltip
- shows a tooltip with the specified text above the elementform-error-tooltip-template
- ancillary directive with a tooltip templatetooltip
is a directive from the Angular Bootstrap library that we will expand$tooltip
. Because of what the directive is defined as: .directive( 'tooltip', [ '$tooltip', function ( $tooltip ) { return $tooltip( 'tooltip', 'tooltip', 'mouseenter' ); }])
directiveName +'-popup '
(directiveName = tooltip in this case): '<div '+ directiveName +'-popup '+ 'title="'+startSym+'tt_title'+endSym+'" '+ 'content="'+startSym+'tt_content'+endSym+'" '+ 'placement="'+startSym+'tt_placement'+endSym+'" '+ 'animation="tt_animation" '+ 'is-open="tt_isOpen"'+ '>'+ '</div>';
.directive( 'tooltipPopup', function () { return { restrict: 'EA', replace: true, scope: { content: '@', placement: '@', animation: '&', isOpen: '&' }, templateUrl: 'template/tooltip/tooltip-popup.html' }; })
open
event on the element is clipped and disappear, if - close
app.directive('formErrorTooltip', function($tooltip) { return $tooltip('formErrorTooltip', 'formErrorTooltip', 'open'); });
open
and close
not supported, but it does not matter. Developers made it possible to add their own events. app.config(function($tooltipProvider) { $tooltipProvider.setTriggers({'open': 'close'}); });
form-error-tooltip
showing the form-error-tooltip
over the element. Let's make it so that it shows errors if few characters are entered (in this project it is not difficult to teach how to handle any errors, including server ones). We write a form-error
directive that expands the first: app.directive('formError', function($compile, $interpolate, $injector) { return { terminal: true, priority: 100, scope: true, compile: function compile(tElement, tAttrs) { var startSym = $interpolate.startSymbol(), endSym = $interpolate.endSymbol(), self = this; tElement.attr('form-error-tooltip', startSym + 'message' + endSym); angular.forEach(tAttrs.$attr, function(value, attr) { var ddo = $injector.has(attr + 'Directive') ? $injector.get(attr + 'Directive')[0] : {}; if (ddo.terminal && ddo.priority >= self.priority) { tElement.removeAttr(value); } }); return function(scope, element, attrs, controller) { $compile(element)(scope); var ngModelCtrl = element.controller('ngModel') element.on('input blur change', checkValidity); function checkValidity() { if (ngModelCtrl.$error.minlength) { setError(attrs.formError); } else if (element.scope() && element.scope().tt_isOpen) { //avoid tooltip bug element.triggerHandler('close'); } } function setError(message) { scope.message = message; scope.$digest(); //set message to tooltip element.triggerHandler('open'); } }; } }; });
form-error-tooltip
directive to the element and triggers open
and close
events on it, depending on whether there is an error or not. But how does she do it? It's all about priorities.terminal: true, priority: 100
no other non-terminal directives or directives with lower priority will be executed. In other words, before this directive, only ng-if, ng-repeat, ng-include
, etc., are executed, i.e. directives that determine whether to generally show the element.form-error-tooltip={{message}}
attribute, delete the attributes of directives with higher priority (which have already been executed), including the directive itself, so that it does not perform itself indefinitely, and recompile the element. Now all remaining directives will be executed, including the tooltip display directive, and there will be no conflicts. app.directive('formPassword', function($compile, $injector) { return { restrict: 'AE', terminal: true, priority: 200, templateUrl: 'passwordTemplate.html', replace: true, scope: true, compile: function(tElement, tAttrs) { var input = tElement.find('input')[0], self = this; angular.forEach(tAttrs.$attr, function(value, attr) { var ddo = $injector.has(attr + 'Directive') ? $injector.get(attr + 'Directive')[0] : {}; if (attr !== 'type' && attr !== 'class' && attr !== 'formPassword' && (!ddo.terminal || ddo.priority < self.priority)) { input.setAttribute(value, tAttrs[attr]); } if (attr !== 'class') { tElement.removeAttr(value); } }); return function(scope) { scope.show = false; } } }; });
tranclude
, but then you would have to wrap the element in a container or to tranclude
such a garden, which is better.ng-if
or ng-repeat
, therefore, this whole construct will be hidden, shown or reproduced as many times as desired and the directives will be friends with each other.Source: https://habr.com/ru/post/218385/
All Articles