使模板化的数据可用于 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 不可用,则使用嵌入式 jqLit​​e 子集)来解决这个问题,而无需移动内容,甚至不触及 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())。

这种方法的好处是它适用于任何表单元素,但由于其中大多数是&lt;input&gt; 标签,并且 jqLit​​e 不支持选择器,因此找到您想要的确切选择器可能有点棘手。那时我会简单地包含完整的 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 约定。其次,它甚至不涉及 jqLit​​e/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的主要内容,如果未能解决你的问题,请参考以下文章

将 pimpl 与 Templated Class 和显式实例化的模板一起使用

复习笔记——C++模板

使数据结构可用于类的所有实例?

使 WordPress 用户元数据可用于 Rest-API

数据库文章翻译

数据的新时代:可交互大屏展现数字孪生的奇妙效果