I would like to create a wrapper for my input field with an input-help tool tip inside of it.
I am using angular 1.0.7, if it's significant.
I'm using transclude: true, along with isolate scope in order to allow errors at several different fields simultaneously, and still maintain the ng-model reference to the external $scope.
The Problem:
when I use this directive on the input element, the input element doesn't clone('Transclude') into the directive template.
As a result of that I am getting an empty div element at the DOM, with an ng-transclude attribute.
plunk: http://plnkr.co/edit/vFB9ih6x2NBmwhAes3Qh?p=preview
code:
<input data-my-validate-input data-value-required="true" type="password" class="loginItem" placeholder="Password" name="password" data-ng-model="formData.password" data-display-name="Password">
However when I wrap this input element in a span or div, the child input element is transcended just fine, but then I don't get the a reference to the correct external ng-model(ctrl) at the directive.
<span data-my-validate-input data-value-required="true" data-display-name="Password">
<input type="password" class="loginItem" placeholder="Password" name="password" data-ng-model="formData.password" >
</span>
Full code(the logic inside the link function is not relevant to the problem, but I preferred to post my full code)
directive('myValidateInput', function() {
return {
require: 'ngModel',
restrict: 'A',
transclude: true,
scope: {
displayName: '@',
valueRequired: '@',
maxLength: '@',
minLength: '@',
minLetters: '@',
minNumbers: '@'
},
template: '<div class="validationContainer">\
<div ng-transclude></div>\
<div class="input-help">\
<h4>{{fieldErrorDisplay}}</h4>\
<ul>\
<li data-ng-repeat="rule in requirementSpec" ng-class="rule.class">\
{{rule.msg}}\
</li>\
</ul>\
</div>\
</div>',
replace: true,
link: function(scope, elm, attrs, ctrl) {
var validator = function(viewValue){
if(scope.valueRequired && viewValue.length == 0 && (!scope.maxLength && !scope.minLength && !scope.minLetters && !scope.minNumbers)){
scope.valid = false;
scope.fieldErrorDisplay = scope.fieldName + ' is required';
}
else{
scope.fieldErrorDisplay = scope.fieldName + ' must meet the following requirements: ';
scope.requirementSpec = [];
if(scope.minLength){
var itemValidity = viewValue.length >= scope.minLength;
scope.valid = !itemValidity ? false : scope.valid;
var item = {
'msg' : 'Must be at least ' + scope.minLength + ' characters long',
'class' : itemValidity ? 'valid' : undefined
};
scope.requirementSpec[nameStr].push(item);
}
else if(scope.valueRequired){
var itemValidity = viewValue && viewValue.length >= 1;
scope.valid = !itemValidity ? false : scope.valid;
var item = {
'msg' : 'This field must be filled',
'class' : itemValidity ? 'valid' : undefined
};
scope.requirementSpec[nameStr].push(item);
}
if(scope.maxLength){
var itemValidity = viewValue.length <= scope.maxLength;
scope.valid = !itemValidity ? false : scope.valid;
var item = {
'msg' : 'Must be ' + scope.maxLength + ' characters long at most ',
'class' : itemValidity ? 'valid' : undefined
};
scope.requirementSpec[nameStr].push(item);
}
if(scope.minLetters){
var itemValidity = (viewValue && /[A-z]/.test(viewValue));
scope.valid = !itemValidity ? false : scope.valid;
var item = {
'msg' : 'Must contain at least ' + scope.minLetters + ' letters',
'class' : itemValidity ? 'valid' : undefined
};
scope.requirementSpec[nameStr].push(item);
}
if(attrs.minNumbers){
var itemValidity = (viewValue && /\d/.test(viewValue));
scope.valid = !itemValidity ? false : scope.valid;
var item = {
'msg' : 'Must contain at least' + attrs.minNumbers + ' numbers',
'class' : itemValidity ? 'valid' : undefined
};
scope.requirementSpec[nameStr].push(item);
}
}
if(scope.valid) {
ctrl.$setValidity(nameStr, true);
return viewValue;
} else {
ctrl.$setValidity(nameStr, false);
return undefined;
}
}
scope.requirementSpec = {};
ctrl.$parsers.unshift(function(viewValue) {
return validator(viewValue);
});
ctrl.$formatters.unshift(function(viewValue) {
// var before = scope.$eval(attrs.validateBefore);
if(viewValue && viewValue != "" && viewValue.length > 0)
return validator(viewValue);
});
});
}
});