所以我的用例是:
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]"。我已经尝试过这种方法,它适用于一个非通用的用例。
我试图使它通用:
重新编译'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; } } } }
用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;
}
}
}
},
}
}]);