AngularJS: Make isolate scope directive template bind to parent scope
<p>I've been struggling with Angular's isolate scope for over 24hrs now. Here's my scenario: I have an <code>ng-repeat</code> iterating over an array of objects from which I want to use a custom directive to either generate a <code>&lt;select&gt;</code> or <code>&lt;input&gt;</code> based on the <code>field_type</code> property of the current object being iterated. This means I'll have to generate the template and <code>$compile</code> in the post-link function of the directive since I have no access to the iterated object in the template function.</p>

<p>Everything works as expected, apart from the actual binding of the generated template to the controller (vm) in my outer scope. I think my approach (adding this in the template string: <code>ng-model="vm.prodAttribs.' + attr.attribute_code +'"</code>) may be wrong, and would appreciate pointers in the right direction. Thanks!</p>

<p>See sample code below:</p>

<p><strong>directives:</strong></p>

<pre><code>directives.directive('productAttributeWrapper', ['$compile',  function($compile){
    //this directive exists solely to provide 'productAttribute' directive access to the parent scope
    return {
        restrict: 'A',
        scope: false,
        controller: function($scope, $element, $attrs){
            this.compile = function (element) {
                $compile(element)($scope);
                console.log('$scope.prodAttribs in directive: ', $scope.prodAttribs);
            };
        }
    }
}]);

directives.directive('productAttribute', ['$compile',  function($compile){
    return {
        restrict: 'A',
        require: '^productAttributeWrapper', //use the wrapper's controller
        scope: {
            attribModel: '=',
            prodAttribute: '=productAttribute', //binding to the model being iterated by ng-repeat
        },
        link: function(scope, element, attrs, ctrl){
            var template = '';
            var attr = scope.prodAttribute;
            if(!attr) return;

            switch(attr.attribute_field_type.toLowerCase()){
                case 'textfield':
                    template = 
                        '&lt;input type="text" id="'+attr.attribute_code+'" ng-model="vm.prodAttribs.' + attr.attribute_code +'"&gt;';
                    break;
                case 'dropdown':
                    template = [
                        '&lt;select class="cvl" id="'+attr.attribute_code+'" ng-model="vm.prodAttribs.' + attr.attribute_code +'"&gt;',
                            '#cvl_option_values',
                        '\n&lt;/select&gt;'
                    ].join('');
                    var options = '\n&lt;option value=""&gt;Select One&lt;/option&gt;';
                    for(var i=0; i&lt;attr.cvl_option_values.length; i++) {
                        var optionVal = attr.cvl_option_values[i].value;
                        options += '\n&lt;option value="'+optionVal+'"&gt;' + attr.cvl_option_values[i].value + '&lt;/option&gt;';
                    }
                    template = template.replace('#cvl_option_values', options);
                    break;
            }
            element.html(template);
            ctrl.compile(element.html());  //try to bind template to outer scope
        }
    }
}]);
</code></pre>

<p><strong>html:</strong></p>

<pre><code>&lt;div ng-controller="ProductController as vm"&gt;
    &lt;div product-attribute="attrib" ng-repeat="attrib in vm.all_attribs"&gt;&lt;/div&gt;
&lt;/div&gt;
</code></pre>

<p><strong>controller:</strong></p>

<pre><code>app.controller('ProductDetailsController', function(){
    var vm = this;
    //also added the property to $scope to see if i could access it there
    $scope.prodAttribs = vm.prodAttribs = {
            name: '',
            description: '',
            price: [0.0],
            condition: null
    }
    vm.all_attributes = [
        {
          "attribute_id": 1210,
          "attribute_display_name": "Product Type",
          "attribute_code": "product_type",
          "attribute_field_type": "Textfield",
          "cvl_option_values": [],
          "validation_rules": {}
        },
        {
          "attribute_id": 902,
          "attribute_display_name": "VAT",
          "attribute_code": "vat",
          "attribute_field_type": "dropdown",
          "cvl_option_values": [
            {
              "option_id": "5",
              "value": "5%"
            },
            {
              "option_id": "6",
              "value": "Exempt"
            }
          ],
          "validation_rules": {}
    }];
})
</code></pre>