AngularJs - 重新绑定ng模型

时间:2015-08-13 13:33:32

标签: javascript angularjs

所以我的用例是:

cols = [{field="product.productId"},{field="product.productPrice"}];

data = {products:[{product:{productId:1,productPrice:10}, {product:{productId:2, productPrice:15}}]}

我想做的是:

<div ng-repeat="product in data.products">
<div ng-repeat="col in cols">
<input type="text" ng-model="product[col.field]"></>
</div>
</div>

现在如果col.field只是'someField'而不是'some.deep.field',那么这将有效。因为该字段有许多元素,所以如果我不想要通用并且允许我的数据和列更改,那么执行ng-model的正确方法将是“product [some] [deep] [field]”。我尝试过这种方法,它适用于非通用用例。

我试图让它变得通用:

  1. 重新编译我的'input'元素。这就创造了完美的HTML E.G它有ng-model =“product ['some'] ['deep'] ['field']”就可以了,但绝不会受到任何限制。也许我在这里编写错误的范围?我已经尝试过在这一点上添加属性ng-init =“hello ='嘿'”ng-model =“hello”并且它正常工作和绑定...所以我觉得我在这里缺少关于范围的东西。

    compile: function (templateElement) {
        templateElement[0].removeAttribute('recursive-model');
        templateElement[0].removeAttribute('recursive-model-accessor');
        return {
            pre: function (scope, element, attrs) {
                function convertDotToMultiBracketNotation(dotNote) {
                    var ret = [];
                    var arrayOfDots = dotNote.split('.');
                    for (i = 0; i < arrayOfDots.length; i++) {
                        ret.push("['" + arrayOfDots[i] + "']");
                    }
                    return ret.join('');
                }
    
                if (attrs.recursiveModel && attrs.recursiveModelAccessor) {
                    scope[scope.recursiveModel] = scope.ngModel;
                    element[0].setAttribute('ng-model', scope.recursiveModel + convertDotToMultiBracketNotation(scope.recursiveModelAccessor));
                    var res = $compile(element[0])(scope);
                    console.info('new compiled element:', res);
                    return res;
                }
            }
        }
    }
    
  2. 使用NgModelController进行格式化和解析。在这种情况下,我将整个'row'对象放入ng-model中,然后使用formatter / parser来处理我感兴趣的1字段。这一直有效,直到您清除该字段。在那一点上,它似乎完全消灭了modelCtrl。$ modelValue。 换句话说 - 我的console.log说:

  3.   

    将字段设置为行[object]

    上的val'Text'      

    在[object]

    行上将字段设置为val'Tex'      

    在[object]

    行上将字段设置为val'Te'      

    在[object]

    行上将字段设置为val'T'      

    在行[object]

    上将字段设置为val''      

    将字段设置为'未定义行

    上的'A'
        link: function (scope, element, attrs, ctrls) {
            if(ctrls[2] && scope.recursiveModelAccessor){
         var modelCtrl = ctrls[2];
                modelCtrl.$formatters.push(function (inputValue) {
                    function getValue(object, string){
                        var explodedString = string.split('.');
                        for (i = 0, l = explodedString.length; i < l; i++) {
                            object = object[explodedString[i]];
                        }
                        return object;
                    };
    
                    function getValueRecursive (row, field) {
                        if (field instanceof Array) {
                            var ret = [];
                            for (var i = 0; i < col.field.length; i++) {
                                ret.push(getValue(row, field[i]));
                            }
                            return ret.join('/');
                        } else {
                            return getValue(row, field);
                        }
                    };
    
                    return getValueRecursive(modelCtrl.$modelValue, scope.recursiveModelAccessor);
                });
                modelCtrl.$parsers.push(function (inputValue) {
                    function setValueRecursive (row, field, newValue) {
                        if (field instanceof Array) {
                            var firstField = field.shift();
                            if(field.length==1){
                                field = field[0];
                            }
                            setValueRecursive(row[firstField], field, newValue);
                        } else {
                            console.log("Setting "+field+" to val:"+newValue+" on row:"+row);
                            row[field]=newValue;
                        }
                    };
    
                    setValueRecursive(modelCtrl.$modelValue, scope.recursiveModelAccessor.split('.'), modelCtrl.$viewValue);
    
                    return modelCtrl.$modelValue;
                });
    

1 个答案:

答案 0 :(得分:1)

长话短说(浪费了8个小时) - 不要把ng-model =&#34;&#34;&#34;在您的对象上,如果您计划在修改ng-model属性后重新编译。

重新绑定ngModel的工作指令(只是不要在你的对象上拥有该属性!)

<div ng-repeat="product in data.products">
<div ng-repeat="col in cols">
<input type="text" recursive-model="product" recursive-model-accessor="some.deep.field"></input>
</div>
</div>

确保你没有ng-model =&#34;&#34;。

当然 - 如果存在ng-model属性,100%完美的解决方案会抛出异常:)

module.directive('rebindModel',  ['$compile','$parse',function($compile,$parse){
return {
    restrict:'A',
    compile: function (templateElement) {
        templateElement[0].removeAttribute('recursive-model');
        templateElement[0].removeAttribute('recursive-model-accessor');

        return {
            post: function (scope, element, attrs) {
                function convertDotToMultiBracketNotation(dotNote) {
                    var ret = [];
                    var arrayOfDots = dotNote.split('.');
                    for (i = 0; i < arrayOfDots.length; i++) {
                        ret.push("['" + arrayOfDots[i] + "']");
                    }
                    return ret.join('');
                }

                if (attrs.recursiveModel && attrs.recursiveModelAccessor) {
                    var parsedModelAccessor = $parse(attrs.recursiveModelAccessor)
                    var modelAccessor = parsedModelAccessor(scope);

                    element[0].setAttribute('ng-model', attrs.recursiveModel + convertDotToMultiBracketNotation(modelAccessor));
                    var res = $compile(element[0])(scope);
                    return res;
                }
            }
        }
    },
}
}]);