title: Angular Directive with Optional Attributes
body: <p>I have a custom dropdown directive that has common attributes such as <strong>class</strong> and <strong>ng-model</strong>. </p>
  
  <p>I have decided to extend this control for support for validation and now need to include optional attributes that should only get included in the output template if they are set by the programmer.</p>
  
  <p><strong>Sample</strong></p>
  
  <p><a href="https://i.stack.imgur.com/udgV7.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/udgV7.png" alt="Sample Directive Call"></a></p>
  
  <p>I have a partially working system in which I moved my code out of a template URL and into a string concatenation which I call in the post: function of the directives compile.</p>
  
  <p>I would have preferred to leave my directives HTML in a template, but could not get that working so I have this solution.</p>
  
  <p>Questions:</p>
  
  <ol>
  <li>Is this the best way to write a template with dynamic attributes?</li>
  <li>Could this be made to work while leaving the HTML in a template URL</li>
  <li>Should I be using the compile => post function or should this be done in the link function</li>
  </ol>
  
  <p><strong>Code for Directive</strong></p>
  
  <pre><code>'use strict';
  
  angular.module(APP)
    .directive('wkKeyLabelSelect', ["$compile",
      function($compile) {
        return {
          restrict: 'EA',
          replace: true,
          scope: {
            'class': '@',              // Permanent - One Way Attribute
            ngModel: '=',              // Permanent - Two Way Attribute (Angular)
            items: '=',                // Permanent - Two Way Attribute (Custom)
            id: '@',                   // Dynamic - One Way Attribute
            name: '@',                 // Dynamic - One Way Attribute
            ngRequired: '=',           // Dynamic - Two Way Attribute (Angular) 
        },
          //templateUrl: COMPONENTS_PATH + '/keyLabelSelect/keyLabelSelect.html',
          controller: 'KeyLabelSelectController',
          link: function (scope, element, attrs) {
            //$compile(element)(scope);
          },
          compile: function (element, attrs) {
  
            // name &amp; ngRequired are not available in the compile scope
            //element.replaceWith($compile(html)(scope));
  
            return {
              pre: function preLink(scope, iElement, iAttrs, controller) {
  
              },
              post: function postLink(scope, iElement, iAttrs, controller) {
  
                // Template goes here
                var html =
                  '&lt;select ' +
                    ' class="{{class}}"' +
                    (scope.id ? ' id="{{id}}"' : "") +
                    (scope.name ? ' name="{{name}}"' : "") +
                    (scope.ngRequired ? ' ng-required="true"' : "") +
                    ' ng-model="ngModel"' +
                    ' ng-options="item.key as item.label for item in items"' +
                    '&gt;' +
                  '&lt;/select&gt;';
  
                iElement.replaceWith($compile(html)(scope));
              }
            }
          }
        };
      }
    ]);
  </code></pre>
  
  <p><strong>Code for Directive Controller</strong></p>
  
  <pre><code>angular.module(APP)
  
  .controller('KeyLabelSelectController', ['$scope', function ($scope) {
  
    $scope.klass = typeof $scope.klass === 'undefined' ? 'form-control' : $scope.klass;
  
    console.log($scope.ngModel);
    console.log($scope.items);
  
  }]);
  </code></pre>
  
  <p><strong>HTML used to run the directive</strong></p>
  
  <pre><code>&lt;div class="form-group" ng-class="{ 'has-error': editForm.state.$touched &amp;&amp; editForm.name.$invalid }"&gt;
      &lt;label class="col-md-3 control-label"&gt;State&lt;/label&gt;
      &lt;div class="col-md-9"&gt;
          &lt;wk-key-label-select id="state" name="state"
                                  ng-required="true"
                                  ng-model="model.entity.state"
                                  class="form-control input-sm"
                                  items="model.lookups.job_state"&gt;
          &lt;/wk-key-label-select&gt;
  
          &lt;div class="help-block" ng-messages="editForm.state.$error"&gt;
              &lt;p ng-message="required"&gt;Job State is required.&lt;/p&gt;
          &lt;/div&gt;
      &lt;/div&gt;
  
  &lt;/div&gt;
  </code></pre>
  
  <p><strong>My Original Template URL content, not used currently</strong></p>
  
  <pre><code>&lt;!-- This is now deprecated in place of inline string --&gt;
  &lt;!-- How could I use a in place of string concatenation  --&gt;
  
  &lt;select class="{{klass}}"
          name="{{name}}"
          ng-model="ngModel"
          ng-options="item.key as item.label for item in items"&gt;&lt;/select&gt;
  </code></pre>
  
  <p><a href="https://i.stack.imgur.com/rKDvH.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/rKDvH.png" alt="Questions"></a></p>