Ответ 1
Мы делаем что-то похожее на ваш ответ, у нас есть директива formSubmitted, которая привязывается к событию отправки, при запуске мы устанавливаем переменную $submit на контроллере формы. Таким образом, вы можете использовать его аналогично тому, как вы используете ShowValidationMessages, но его можно использовать повторно. Очень простая директива:
app.directive('formSubmitted', [function () {
return {
restrict: 'A',
require: 'form',
link: function (scope, element, attrs, ctrl) {
ctrl.$submitted = false;
element.on('submit', function () {
scope.$apply(function () {
ctrl.$submitted = true;
});
});
}
};
}]);
Вы применяете это в теге формы как атрибут.
Мы сделали еще пару шагов, наше требование состояло в том, чтобы показать ошибки проверки только в том случае, если выполняется следующее: этот элемент недействителен И либо форма была отправлена, либо элемент ввода размыт. Таким образом, мы закончили с другой директивой, которая требует ngModel, который устанавливает размытое состояние элемента на контроллере ngModel.
И наконец, чтобы избавиться от целого много повторяющегося кода котельной в html, чтобы проверить все эти вещи, например. ваш ng-show="frmMyForm.myField.$invalid && (!frmMyForm.myField.$pristine || MyObject.ShowValidationMessages)"
мы инкапсулировали это в директиву. Эта директива шаблона обертывает наши входные элементы с помощью бот-плиты Bootstrap, а также обрабатывает все элементы проверки. Итак, теперь все мои входы формы следуют этому шаблону:
<div data-bc-form-group data-label="Username:">
<input type="text" id="username" name="username" ng-model="vm.username" data-bc-focus required />
</div>
и директива bcFormGroup преобразуют ее в следующий загрузочный загрузочный html:
<div class="form-group" ng-class="{'has-error': showFormGroupError()}" data-bc-form-group="" data-label="Username:">
<label for="username" class="col-md-3 control-label ng-binding">Username:</label>
<div class="col-md-9">
<input type="text" id="username" name="username" ng-model="vm.username" data-bc-focus="" required="" class="ng-pristine form-control ng-valid ng-valid-required">
<span class="help-block ng-hide" ng-show="showRequiredError()">Required</span>
</div>
</div>
Это держит вещи DRY и обеспечивает большую гибкость в том, какие типы входов поддерживаются.
Update:
Вот основной список директивы bcFormGroup. Шаблон по умолчанию использует горизонтальную форму бутстрапа, но может быть адаптирован по своему вкусу.
app.directive('bcFormGroup', ['$compile', '$interpolate', function ($compile, $interpolate) {
return {
restrict: 'A',
template:
'<div class="form-group" ng-class="{\'has-error\': showFormGroupError()}">' +
'<label for="{{inputId}}" class="col-md-3 control-label">{{label}}</label>' +
'<div class="col-md-9">' +
'<bc-placeholder></bc-placeholder>' +
'</div>' +
'</div>',
replace: true,
transclude: true,
require: '^form',
scope: {
label: '@',
inputTag: '@'
},
link: function (scope, element, attrs, formController, transcludeFn) {
transcludeFn(function (clone) {
var placeholder = element.find('bc-placeholder');
placeholder.replaceWith(clone);
});
var inputTagType = scope.inputTag || 'input';
var inputElement = element.find(inputTagType);
var fqFieldName = formController.$name + '.' + inputElement.attr('name');
var formScope = inputElement.scope();
if (inputElement.attr('type') !== 'checkbox' && inputElement.attr('type') !== 'file') {
inputElement.addClass('form-control');
}
scope.inputId = $interpolate(inputElement.attr('id'))(formScope);
scope.hasError = false;
scope.submitted = false;
formScope.$watch(fqFieldName + '.$invalid', function (hasError) {
scope.hasError = hasError;
});
formScope.$watch(formController.$name + '.$submitted', function (submitted) {
scope.submitted = submitted;
});
if (inputElement.attr('data-bc-focus') != null || inputElement.attr('bc-focus') != null) {
scope.hasBlurred = false;
formScope.$watch(fqFieldName + '.$hasBlurred', function (hasBlurred) {
scope.hasBlurred = hasBlurred;
});
}
if (inputElement.attr('required')) {
scope.hasRequiredError = false;
formScope.$watch(fqFieldName + '.$error.required', function (required) {
scope.hasRequiredError = required;
});
inputElement.after($compile('<span class="help-block" ng-show="showRequiredError()">Required</span>')(scope));
}
if (inputElement.attr('type') === 'email') {
scope.hasEmailError = false;
formScope.$watch(fqFieldName + '.$error.email', function (emailError) {
scope.hasEmailError = emailError;
});
inputElement.after($compile('<span class="help-block" ng-show="showEmailError()">Invalid email address</span>')(scope));
}
scope.showFormGroupError = function () {
return scope.hasError && (scope.submitted || (scope.hasBlurred === true));
};
scope.showRequiredError = function () {
return scope.hasRequiredError && (scope.submitted || (scope.hasBlurred === true));
};
scope.showEmailError = function () {
return scope.hasEmailError && (scope.submitted || (scope.hasBlurred === true));
};
}
};
}]);
Update:
Следующая директива устанавливает $focus и $hasBlurred:
app.directive('bcFocus', [function () {
var focusClass = 'bc-focused';
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ctrl) {
ctrl.$focused = false;
ctrl.$hasBlurred = false;
element.on('focus', function () {
element.addClass(focusClass);
var phase = scope.$root.$$phase;
if (phase == '$apply' || phase == '$digest') {
ctrl.$focused = true;
} else {
scope.$apply(function () {
ctrl.$focused = true;
});
}
}).on('blur', function () {
element.removeClass(focusClass);
var phase = scope.$root.$$phase;
if (phase == '$apply' || phase == '$digest') {
ctrl.$focused = false;
ctrl.$hasBlurred = true;
} else {
scope.$apply(function () {
ctrl.$focused = false;
ctrl.$hasBlurred = true;
});
}
});
}
};
}]);