我创建了一个指令,它根据服务器的json动态创建表单。我尝试将ng-model
属性添加到各种输入元素,以便在用户输入并单击提交后我能够使用输入值。似乎添加了ng-model
属性,但双向数据绑定不起作用。
编辑:我在链接功能中调用buildForm,如下所示:
function link(scope, elem, attr, ctrl) {
//asyc request to the server, data here is a json object from the server
getMovieDataStructure({
onSuccess: (data) => {
scope.mdb = data;
buildForm(scope.mdb, elem);
},
onFail: (res) => {
console.log("ERROR getting it");
}
});
}
以下是该指令中的一些代码:
//mdb is an array of objects describing the form requirments
function buildForm(mdb, formElement) {
for(var i=0; i < mdb.length; i++) {
if(mdb[i].type == 'string') {
if(mdb[i].maxLength && mdb[i].maxLength > 1024) {
//if maxLength > 1024 put a text area instead
formElement.append(createTextArea({
id: mdb[i].fieldName,
placeholder: mdb[i].fieldName
}));
} else {
//add input field to the form
formElement.append(createTextInput({
id: mdb[i].fieldName,
placeholder: mdb[i].fieldName
}));
}
} else if(){
//some more cases
}
formElement.append("<br>");
}
//...some more code...
}
//one of the functions to create an input element
function createTextInput(data) {
var elem = angular.element("<input>");
elem.attr("type", "text");
elem.attr("id", data.id);
elem.attr("ng-model", data.id);
elem.attr("placeholder", data.placeholder);
return elem;
}
例如,html页面上的输入元素的结果可能如下所示:
<input placeholder="movie_name" ng-model="movie_name" id="movie_name" type="text"> </input>
如果我将相同的标签直接放在html文件中,那么双向绑定效果很好。
这里缺少什么?有没有更好的方法来做到这一点,我只是过于复杂的事情?
答案 0 :(得分:1)
在您更新表单后的某个地方,您需要调用$ compile,否则angular将不会知道您的更改。见:
答案 1 :(得分:0)
尝试调用buildform方法后,可以调用$ rootScope.apply()。可能发生的事情是,在摘要周期完成后,您正在对DOM进行所有这些更改,而角度将不会知道您的更改,直到下一个周期发生。
所以在你的情况下它将是: buildForm(scope.mdb,elem); 。的范围$申请(); 强>
答案 2 :(得分:0)
事情是需要在你的情况下明确调用digest循环因为angular不知道所做的更改。
使用:
buildForm(scope.mdb, elem);
scope.$apply();
OR
但使用$ apply有更好的方法:
scope.$apply(buildForm(scope.mdb,elem));
不同之处在于,在第一个版本中,我们正在更新角度上下文之外的值,因此如果抛出错误,Angular将永远不会知道。
答案 3 :(得分:0)
正如wdanda所提到的,由于该指令添加了DOM元素,因此需要在之后编译以让angular知道更改
简短回答是,行buildForm(scope.mdb, elem);
已更改为$compile(buildForm(scope.mdb, elem).contents())(scope);
,并且'$compile'
已添加到指令的依赖项列表中。
长解释:
buildForm(scope.mdb,elem)
返回指令的元素(因此在$compile(elem.contents())(scope);
之后实际添加buildForm
将是等效的),.contents()
在角度包装元素上返回所有元素子元素
这意味着$compile(buildForm(scope.mdb, elem).contents())
告诉angular编译指令元素的所有子元素,在buildForm
添加了一些元素之后(其中一些元素有自己的指令。
.contents()
的来电很重要,因为:
我们只编译.childNodes,以便我们不会进入无限循环编译自己
(来自https://docs.angularjs.org/api/ng/service/ $ compile)
$compile()
函数返回一个链接函数,需要使用要链接的作用域调用。因此,在末尾添加(scope)
将调用返回的函数。
编写该代码的更清晰(虽然稍微不那么优雅)的方式是:
var element = buildForm(scope.mdb, elem); //buildForm returns an angular wraped element
var linking = $compile(element); // $compile returns a linking function
linking(scope); //linking is functions that takes a scope object
//and needs to be run after compilation