I'm writing a Directive (using AngularJS 1.2.0-rc2, if that matters) that adds a "clear" button (think of the "x" button that the browser adds for <input type="search">
elements) to an <input>
.
As the "clear" button is injected from the Directive and is positioned absolutely, I'd like to contain both the existing <input>
and the newly added "clear" button in a wrapper element that has position: relative
to ensure proper positioning of the "clear" button.
The declared HTML looks like this:
<input type="text" id="myField" data-ng-model="someModel" data-search>
The Directive I have so far:
angular.module('myApp', []).directive('search', function() {
var
clear = angular.element('<a href role="button" class="btn x" style="display:none">×</a>'),
wrapper = angular.element('<div style="position: relative"></div>');
return {
restrict: 'A',
link: function( scope, element, attrs ) {
element.wrap(wrapper.append(clear));
// more code that's not relevant to my question
}
};
});
The HTML I end up with is
<div style="position: relative">
<a href role="button" class="btn x" style="display: none">×</a>
<input type="text" id="myField" data-ng-model="someModel" data-search>
</div>
which is what I'm after, but I'd like to ideally template the two new elements and abstract the DOM manipulation out of my link
function.
I feel like there's probably a better way to go about this using either or both replace
/template
and transclude
options, but I'm not sure how to retain and use the source element (with all of its attributes and data bindings) with either of those options.
Also note that even though my sample has an ng-model
defined on the source element, that should be considered optional. I'd also like to keep the Directive restricted to attributes (restrict: 'A'
).
Transclusion is probably what you're looking for. Here is some updated code.
Template:
<div style="position: relative">
<a href role="button" class="btn x" style="display: none">×</a>
<div ng-transclude></div>
</div>
Directive:
angular.module('myApp', []).directive('search', function() {
return {
restrict: 'A',
replace: true,
transclude: true,
// template: '', // string template of the HTML above, or better yet
templateUrl: '', // relative URL of an HTML file containing the above template
};
});
HTML:
<div data-search>
<input type="text" id="myField" data-ng-model="someModel">
</div>
You should only use one of either template or templateUrl in the directive, I would lean towards templateURL because I hate string templates.
You can still include a link function if you need more logic.
The replace property will replace the existing DOM element you apply the element to entirely, while leaving this property out will preserve the element and put your template inside of it. Up to you how you would want this configured.
Thinking about it some more, if you did this:
transclude: 'element'
You could just do this in your HTML:
<input type="text" id="myField" data-ng-model="someModel" data-search>
In my opinion, a better way to design a reusable component is isolate scope and directive controller. In your case, I don't see your logic, so I will make it simple using just isolate scope.
Your template file:
<div style="position: relative">
<a href role="button" class="btn x" style="display: none">×</a>
<input type="text" id="myField" data-ng-model="model">
</div>
JS:
angular.module('myApp', []).directive('search', function() {
return {
restrict: 'E',
scope:{
model:"=model"
},
link: function( scope, element, attrs ) {
// more code that's not relevant to my question
},
templateUrl:url-to-your-template
};
});
Use it:
<search model="someModel"/>
Or just:
<search />
If you need to use it as an attribute, try:
JS:
angular.module('myApp', []).directive('search', function() {
return {
restrict: 'A',
scope:{
model:"=model"
},
replace:true,
link: function( scope, element, attrs ) {
// more code that's not relevant to my question
},
templateUrl:url-to-your-template
};
});
Use it:
<div search model="someModel"/>
or just:
<div search />
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With