AngularJs -重新绑定ng-model

AngularJs - Rebinding ng-model

本文关键字:绑定 ng-model -重 新绑定 AngularJs      更新时间:2023-09-26

所以我的用例是:

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>

现在如果color .field只是'someField'而不是'some.deep.field'这将工作。因为字段有许多元素,如果我不想通用并允许我的数据和列更改,那么执行ng-model的正确方法是"product[some][deep][field]"。我已经尝试过这种方法,它适用于一个非通用的用例。

我试图使它通用:

  1. 重新编译'input'元素。这创造了一个完美的HTML例子,它有ng-model="product['some']['deep']['field']",但无论如何都没有字段绑定。也许我在这里编译错误的范围?我已经尝试添加属性ng-init="hello='Hey'" 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来格式化和解析。在这种情况下,我将整个'行'对象放入ng-model中,然后使用格式化器/解析器仅与我感兴趣的1字段混淆。在你清理场地之前,这都是有效的。在这一点上,它似乎抹去了modelCtrl。完全modelValue美元。换句话说-我的console.log说:

在行[object]上设置字段为val 'Text'

在行[object]上设置字段为val 'Tex'

将字段设置为行[object]上的值

在行[object]上设置字段为val 'T'

设置字段为val " on row [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;
            });

长话短说(在这上面浪费了8个小时)——如果你打算在修改ng-model属性后重新编译,就不要把ng-model="something"放在你的对象上。

一个用于重新绑定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="something"。

当然-如果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;
                }
            }
        }
    },
}
}]);