AngularJS - Create a directive that adds a sibling element
Solution 1
That's because your div "2 hello" is outside the container where your scope is visible.
you can use element.append()
instead of element.after()
to have the scope available.
Directive
var app = angular.module('plunker', []);
app.directive('myValidate', function($compile) {
return {
template: '<span>1. Hello {{world}} my scope is {{$id}} (parent: {{$parent.$id}})<span/>',
replace: true,
restrict: 'A',
scope: true,
compile: function (element) {
element.append('<div>2. Hello {{ world }}, my scope is {{$id}} (parent: {{$parent.$id}})</div>');
return function(scope) {
scope.world = 'World';
//$compile()(scope);
};
}
};
});
HTML
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script data-require="[email protected]" data-semver="1.1.5" src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="app.js"></script>
</head>
<body>
<input my-validate="" />
</body>
</html>
http://plnkr.co/edit/dU3holBCePKe0ZAwQKh1?p=preview
Solution 2
I was reading and checking the example because I was in the same situation to display validation messages but under the input field and the message can change according to what kind of validation is required.
So I came up with this solution
var app = angular.module('app', []);
app.controller('ctrl', function($scope, CONSTANTS) {
$scope.title = "title";
$scope.CONSTANTS = CONSTANTS;
});
app.constant('CONSTANTS', {
LENGHT_1: 3,
LENGHT_2: 4
});
app.directive('dir', function($compile) {
return {
scope: true,
restrict: 'A',
require: '?ngModel',
link: function(scope, elem, attrs, ngModel) {
scope.maxLength = false;
scope.required = false;
scope.max = scope.$eval(attrs['ngMaxlength']);
var tpl = '<div ng-if="maxLength" ng-include="\'length.tpl.html\'"></div>' +
'<div ng-if="required" ng-include="\'required.tpl.html\'"></div>';
var el = $compile(tpl)(scope);
elem.after(el);
scope.$watch(attrs['ngModel'], function(newValue, oldValue, scope) {
if (ngModel.$error !== null && ngModel.$error.maxlength) {
scope.maxLength = true;
} else {
scope.maxLength = false;
}
if (ngModel.$error !== null && ngModel.$error.required && ngModel.$dirty) {
scope.required = true;
} else {
scope.required = false;
}
});
}
}
});
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="[email protected]" data-semver="1.4.7" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
<script type="text/ng-template" id="length.tpl.html">
max length {{max}}
</script>
<script type="text/ng-template" id="required.tpl.html">
required
</script>
</head>
<body ng-controller="ctrl">
<h1>Input Validation</h1> {{title}}
<br><br>
<form name="form" novalidate>
<input dir name="input_one" ng-model="bar" ng-maxlength="CONSTANTS.LENGHT_1" required>
<br>
input one: {{form.input_one.$error}}
<br>
<br>
<input dir name="input_two" ng-model="foo" ng-maxlength="CONSTANTS.LENGHT_2">
</form>
<br>
input two: {{form.input_two.$error}}
</body>
</html>
Hope it helps.
martinpaulucci
Updated on August 21, 2022Comments
-
martinpaulucci almost 2 years
I'm creating a
my-validate
directive that looks something like this<input my-validate="customValidation" ng-model="model" />
What I want to do is to attach a sybling element to the directive like this
Error template:
<ul class"errors"> <li ng-repeat="for error in errors">{{error}} not valid</li> </ul>
errors
is defined in the scope of the directive.I've added the error template in the
compile
function, but the problem I have is that thescope
in the link function is not the same as the attached template.Here is a plunker to illustrate the issue: http://plnkr.co/edit/ghdtdYruQaaO0Yxxlrt1?p=preview
'world' is seen in the directive template, but not on the added element :S.
-
martinpaulucci about 11 yearsThanks, the problem is I need it to be a sibling, not a child element.
-
Artur Udod about 11 yearsI suggest you to wrap it with div ( somewhat
'<div class='validatedInput'> <input ng-model="world" /> </div>'
) and useelement.append
-
martinpaulucci about 11 yearsTe problem now is that the original attributes will be in the div and not in the input: plnkr.co/edit/23iwRQsdB6MxMU16NlHP?p=preview
-
Artur Udod about 11 years@martinpaulucci, take a look at this plnkr.co/edit/ohDtJqBCrmB8vhygrVQw?p=preview
-
Josh Noe over 7 yearsThis doesn't address the question.
-
Pistos about 7 yearsThis definitely works, and that's nice, but it would be great to be able to specify a single template as a whole for the whole collection of siblings, instead of having to rely on JS-side DOM manipulation to append, prepend, or whatever.