我在尝试自己解决这个问题时遇到了这个答案,但我从来不喜欢我必须从 HTML 规范需要的字段部分移动信息。我觉得这不是正确的方法。
有一段时间,我最终利用 Angular 位于 jQuery 之上的事实(或者如果完整的 jQuery 不可用,则使用嵌入式 jqLite 子集)来解决这个问题,而无需移动内容,甚至不接触 ng-init。具体来说,您可以在控制器初始化阶段使用( Angular/jqLite 版本的)标准 jQuery 方法访问 textarea 的内容。
所以我只是做了
var doc = angular.element(document.documentElement);
$scope.data = doc.find('textarea').eq(0).val();
在我的控制器中,正是我将初始化任何其他范围变量的地方。(或者,这是修改后的 jsFiddle ...)
有了完整的 jQuery 库,代码就更简单了,因为此时您可以访问完整的jQuery 选择器并且可以直接跳转到$('textarea').eq(0).val()
(或者甚至添加一个 id 到该字段并在该字段上选择:)$('#data-textarea').val()
。
这种方法的好处是它适用于任何表单元素,尽管因为其中大部分是<input>
标签,并且 jqLite 不支持选择器,所以找到您想要的确切的选择器可能有点棘手。那时我会简单地包含完整的 jQuery 库并利用选择器,但这就是我。
这种方法还有一个主要缺点,就是将 DOM 感知代码放置在控制器中,这完全打破了 Angular 约定(The Angular Way (TM))和MVC/MVVM 编程范式。不是最好的解决方案。
更新:所以我最终意识到我需要一个更长期的解决方案,一个不违反这么多最佳实践的解决方案。答案实际上来自 Angular 最重要的元素,没有它,其余的都不会起作用(你可以争辩说对于其他组件,但对于这个组件来说更是如此):指令。进一步来说:
app.directive('input', ['$parse', function ($parse) {
return {
restrict: 'E',
require: '?ngModel',
link: function (scope, element, attrs) {
if(attrs.value) {
$parse(attrs.ngModel).assign(attrs.value, scope);
}
}
};
}]);
这有许多优点。首先,它不会破坏有助于加强 MVC/MVVM 的 Angular 约定。其次,它甚至不涉及 jqLite/jQuery,也不涉及底层的 DOM 函数。第三,它具有保留用于定义默认值的 HTML 约定的预期效果,允许(或至少简化)Angular 与其他现有技术(例如服务器端模板引擎)的使用。
为什么Angular默认不这样做?好吧,如果没有更多的研究,我不知道实际的答案,但一个可能的答案是 HTML 约定有利于静态页面内容,而 Angular 是为动态页面内容而设计的。这意味着在许多地方打破 HTML 约定,而不是让它限制 Angular 应用程序的可能性。由于控制器被期望承担初始化模型的责任(并且在大多数情况下这样的期望是正确的),Angular 团队将有动机忽略value
属性的内容(以及它在其他表单标签中的类似物)。
当然,使用这种方法,对于在控制器初始化之前已经存在的任何适用元素,控制器 init可以覆盖该value
属性。然而,这种行为在整个应用程序中并不一致,因为新元素将触发指令评估,而不是控制器初始化阶段。(具有自己的控制器的部分也具有这种行为 - 在部分的控制器 init 之前存在的元素可以被所述 init 覆盖,但之后添加的其他元素不会重新触发 init。)
有许多其他方法可以编写这样的指令,并且它也可以扩展为执行任意数量的其他事情,但希望这种方法可以帮助其他人。