Reputation: 88
I'm still pretty new to Angular and there are so many ways of doing things so it's hard to figure out how to do something best. In short, I'm trying to create a directive in Angular that conditionally renders either an input[type="text"] or a textarea. In my templateUrl I was originally doing this:
<div class="row">
<label ng-if="label" for="{{inputId}}" class="input-label">{{label}}</label>
<input ng-if="inputType !== 'textarea'" id="{{inputId}}" type="text" class="input" ng-model="$parent.model">
<textarea ng-if="inputType === 'textarea'" id="{{inputId}}" class="input" ng-model="$parent.model"></textarea>
</div>
But this created a lot of problems, as you can see that I had to use $parent.model which feels messier. Also, the input/textarea was not available yet in my link function unless I did an ugly $timeout (which then propagated an async issue to my unit tests). I then decided to change the ng-if's to ng-show:
<div class="row">
<label ng-if="label" for="{{inputId}}" class="input-label">{{label}}</label>
<input ng-show="inputType !== 'textarea'" id="{{inputId}}" type="text" class="input" ng-model="model">
<textarea ng-show="inputType === 'textarea'" id="{{inputId}}" class="input" ng-model="model"></textarea>
</div>
This is mostly fine but I didn't like having a hidden textarea/input for every single directive I rendered. It just felt wrong. I'm currently toying with the idea of using the compile function to conditionally create the input/textarea and inserting it after the label:
<div class="row">
<label ng-if="label" for="{{inputId}}" class="input-label">{{label}}</label>
</div>
Then in my directive (sorry, Coffeescript haters):
compile: (tElem, tAttrs) ->
inputId = tAttrs.inputId
if tAttrs.inputType is 'textArea'
html = "<input id=\"#{inputId}\" type=\"text\" class=\"input\" ng-model=\"model\">"
else
html = "<textarea id=\"#{inputId}\" class=\"input\" ng-model=\"model\"></textarea>"
tElem.find('label').after(angular.element(html))
I'm also pretty critical of this approach since I've essentially split up my template into 2 different places and it can be confusing trying to figure out where stuff is coming from. I'm open to inserting a dummy element and replacing it in the compile function too.
Does one approach stand out over all the others? Anything fundamentally wrong with my thinking? Thanks!
Upvotes: 1
Views: 228
Reputation: 32357
You can use template as a function to produce the template:
app.directive 'myDirective' , ()->
template: (tElem, tAttrs)->
if tAttrs.inputType is 'textArea'
"""
<div class="row">
<label ng-if="label" for="{{inputId}}" class="input-label">{{label}}</label>
<input id="{{inputId}}" type="text" class="input" ng-model="model">
"""
else
"""
<div class="row">
<label ng-if="label" for="{{inputId}}" class="input-label">{{label}}</label>
<textarea id="{{inputId}}" class="input" ng-model="model"></textarea>
</div>
"""
Upvotes: 1