使模板化的数据可用于 ng-model
Posted
技术标签:
【中文标题】使模板化的数据可用于 ng-model【英文标题】:Making data templated in available to ng-model 【发布时间】:2013-01-07 12:18:18 【问题描述】:当使用服务器端模板和客户端 angularjs 时,我无法让 angularjs 识别我在服务器上模板化的值。
例如(或on jsfiddle):
<div ng-app>
<div ng-controller="Ctrl">
<textarea ng-model="data" placeholder="Enter a name here">Templated in</textarea>
data
</div>
</div>
Angularjs 将始终将文本区域中的值替换为 $scope.data
的值(即为空)。我想要的是$scope.data
的值在应用程序引导上采用“模板化”,然后从那里正常继续。
如何从服务器模板中输入一个值,然后让 angularjs 模型在客户端上绑定该值一次?
【问题讨论】:
【参考方案1】:我在尝试自己解决这个问题时遇到了这个答案,但我不喜欢我必须从 html 规范需要的字段部分移动信息。我觉得这不是正确的方法。
有一段时间,我最终利用 Angular 位于 jQuery 之上的事实(如果完整的 jQuery 不可用,则使用嵌入式 jqLite 子集)来解决这个问题,而无需移动内容,甚至不触及 ng-在里面。具体来说,您可以在控制器初始化阶段使用(Angular/jqLite version of)standard jQuery methods 访问 textarea 的内容。
所以我就这么做了
var doc = angular.element(document.documentElement);
$scope.data = doc.find('textarea').eq(0).val();
在我的控制器中,正是我将初始化任何其他范围变量的地方。 (或者,这里是modified jsFiddle...)
有了完整的 jQuery 库,代码就更简单了,因为此时您可以访问完整的 jQuery selectors 并且可以直接跳转到 $('textarea').eq(0).val()
(或者甚至在字段中添加一个 id 并选择它: $('#data-textarea').val()
)。
这种方法的好处是它适用于任何表单元素,但由于其中大多数是<input>
标签,并且 jqLite 不支持选择器,因此找到您想要的确切选择器可能有点棘手。那时我会简单地包含完整的 jQuery 库并利用选择器,但这就是我。
这种方法还有一个主要缺点,就是将 DOM 感知代码放置在控制器中,这完全打破了 Angular 约定(The Angular Way (TM))和 MVC/MVVM 编程范式。不是最好的解决方案。
更新:所以我最终意识到我需要一个更长期的解决方案,一个不违反这么多最佳实践的解决方案。答案实际上来自 Angular 最重要的元素,没有它,它的其余部分都不会起作用(你可以争辩说对于其他组件,但对于这个组件来说更是如此):Directives。更具体地说:
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
属性的内容(以及其他表单标签中的类似物) )。
当然,通过这种方法,对于在控制器初始化之前已经存在的任何适用元素,控制器初始化可以覆盖value
属性。然而,这种行为在整个应用程序中并不一致,因为新元素将触发指令评估,但不是控制器初始化阶段。 (具有自己的控制器的部分也具有这种行为 - 在部分的控制器 init 之前存在的元素可以被所述 init 覆盖,但之后添加的其他元素不会重新触发 init。)
还有许多其他方法可以编写这样的指令,并且它还可以扩展为执行任意数量的其他事情,但希望这种方法对其他人有所帮助。
【讨论】:
虽然这可行,但我努力避免在我的控制器中包含任何类型的 jQuery 或 DOM 感知代码。 很公平。我试图让这种方法也适用于 ng-init,但还没有成功。 你确定同一个标签上还有一个 ng-model 吗?我很确定这是必需的。 是的,一旦模型初始化,至少双向绑定需要它,所以我肯定在尝试使用 ng-model。我怀疑在 ng-init 有机会之前正在处理 ng-model(这对我来说似乎违反直觉),所以当 ng-init 运行时,textarea 已经是空白的。不过,还有一些其他事情我想尝试排除以确保知道。【参考方案2】:使用ng-init
<textarea ng-model="data" placeholder="Enter a name here"
ng-init="data='Templated in'"></textarea>
另请参阅AngularJS - Value attribute on an input text box is ignored when there is a ng-model used? 和 rails + angularjs loading values into textfields on edit
【讨论】:
以上是关于使模板化的数据可用于 ng-model的主要内容,如果未能解决你的问题,请参考以下文章