AngularJS:使隔离范围指令模板绑定到父范围 [英] AngularJS: Make isolate scope directive template bind to parent scope

查看:83
本文介绍了AngularJS:使隔离范围指令模板绑定到父范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在努力争取Angular的隔离范围超过24小时。这是我的场景:我有一个 ng-repeat 迭代一个对象数组,我想从中使用自定义指令来生成<根据当前对象的 field_type 属性选择> < input> 迭代。这意味着我必须在指令的post-link函数中生成模板和 $ compile ,因为我无法访问模板函数中的迭代对象。 / p>

除了生成的模板与外部作用域中的控制器(vm)的实际绑定之外,一切都按预期工作。我认为我的方法(在模板字符串中添加: ng-model =vm.prodAttribs。'+ attr.attribute_code +')可能是错误的,并且会很感激指向正确的方向。谢谢!



请参阅下面的示例代码:



指令:

  directives.directive('productAttributeWrapper',['$ compile',function($ compile){
//此指令仅存在提供'productAttribute'指令访问父范围
return {
restrict:'A',
范围:false,
控制器:函数($ 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',//使用包装器的控制器
范围:{
attribModel:'=',
prodAttribute:'= productAttribute',//绑定到由ng-迭代的模型重复
},
link:function(scope,element,attrs,ctrl){
var template ='';
var attr = scope.prodAttribute;
if (!attr)return;

switch(attr.attribute_field_type.toLowerCase()){
case'textfield':
template =
'< input type = textid ='+ attr.attribute_code +'ng-model =vm.prodAttribs。'+ attr.attribute_code +'>';
break;
case'downdown':
template = [
'< select class =cvlid ='+ attr.attribute_code +'ng-model =vm.prodAttribs。'+ attr.attribute_code +'>',
'#cvl_option_values',
'\ n< / select>'
] .join('');
var options ='\ n< option value =>选择一个< / option>';
for(var i = 0; i< attr.cvl_option_values.length; i ++){
var optionVal = attr.cvl_option_values [i] .value;
options + ='\ n< option value ='+ optionVal +'>'+ attr.cvl_option_values [i] .value +'< / option>';
}
template = template.replace('#cvl_option_values',options);
休息;
}
element.html(模板);
ctrl.compile(element.html()); //尝试将模板绑定到外部范围
}
}
}]);

html:

 < div ng-controller =ProductController as vm> 
< div product-attribute =attribng-repeat =attrib in vm.all_attribs>< / div>
< / div>

控制器:

  app.controller('ProductDetailsController',function(){
var vm = this;
//还将属性添加到$ scope以查看是否我可以在那里访问它
$ scope.prodAttribs = vm.prodAttribs = {
name:'',
description:'',
price:[0.0],
condition:null
}
vm.all_attributes = [
{
attribute_id:1210,
attribute_display_name:产品类型,
attribute_code:product_type,
attribute_field_type:Textfield,
cvl_option_values:[],
validation_rules:{}
},
{
attribute_id:902,
attribute_display_name:增值税,
attribute_code:增值税,
attribute_field_type:下拉列表,
cvl_option_val ues:[
{
option_id:5,
value:5%
},
{
option_id :6,
值:免税
}
],
validation_rules:{}
}];
})


解决方案

问题可能在这里:

  element.html(template); 
ctrl.compile(element.html()); //尝试将模板绑定到外部作用域

element.html()将html作为字符串返回,不是ACTUAL dom的内容,所以你插入到你的指令元素中的内容实际上从未按角度编译,解释你的(缺席)行为。

  element.append(ctrl.compile(模板)); 

应该更好。



For指令需要父控制器,我也会更改你的ctrl.compile方法(在这里重命名为insertAndCompile)

  ctrl.insertAndCompile = function(内容){
$ compile(内容)($ scope,function(clone){
$ element.append(clone);
}
}

你只需要这样称呼它:

  ctrl.insertAndCompile(template); 

而不是我给出的2行第一个答案。


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

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: ng-model="vm.prodAttribs.' + attr.attribute_code +'") may be wrong, and would appreciate pointers in the right direction. Thanks!

See sample code below:

directives:

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

html:

<div ng-controller="ProductController as vm">
    <div product-attribute="attrib" ng-repeat="attrib in vm.all_attribs"></div>
</div>

controller:

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": {}
    }];
})

解决方案

issue is probably here :

element.html(template);
ctrl.compile(element.html());  //try to bind template to outer scope

element.html() returns a html as a string, not the ACTUAL dom content, so what you inserted into your directive's element is never actually compiled by angular, explaining your (absence of) behaviour.

element.append(ctrl.compile(template));

should work way better.

For directive requiring parent controller, I would also change your ctrl.compile method (renamed to insertAndCompile here)

ctrl.insertAndCompile = function(content) {
    $compile(content)($scope, function(clone) {
        $element.append(clone);
    }
}

You would just have to call it this way :

ctrl.insertAndCompile(template);

instead of the 2 lines I gave as first answer.

这篇关于AngularJS:使隔离范围指令模板绑定到父范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆