0

使用服务器端模板和客户端 angularjs 时,我无法让 angularjs 识别我在服务器上模板化的值。

例如(或在 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(null) 的值。我想要的是$scope.data在应用程序引导上采用“模板化”的值,然后从那里正常继续。

如何从服务器模板中输入一个值,然后让 angularjs 模型在客户端上绑定该值一次?

4

2 回答 2

4

使用ng-init

<textarea ng-model="data" placeholder="Enter a name here"
 ng-init="data='Templated in'"></textarea>

另请参阅AngularJS - 使用 ng-model 时忽略输入文本框上的值属性?
rails + angularjs 在编辑时将值加载到文本字段中

于 2013-01-23T21:21:38.947 回答
2

我在尝试自己解决这个问题时遇到了这个答案,但我从来不喜欢我必须从 HTML 规范需要的字段部分移动信息。我觉得这不是正确的方法。

有一段时间,我最终利用 Angular 位于 jQuery 之上的事实(或者如果完整的 jQuery 不可用,则使用嵌入式 jqLit​​e 子集)来解决这个问题,而无需移动内容,甚至不接触 ng-init。具体来说,您可以在控制器初始化阶段使用( Angular/jqLit​​e 版本的)标准 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>标签,并且 jqLit​​e 不支持选择器,所以找到您想要的确切的选择器可能有点棘手。那时我会简单地包含完整的 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 约定。其次,它甚至不涉及 jqLit​​e/jQuery,也不涉及底层的 DOM 函数。第三,它具有保留用于定义默认值的 HTML 约定的预期效果,允许(或至少简化)Angular 与其他现有技术(例如服务器端模板引擎)的使用。

为什么Angular默认不这样做?好吧,如果没有更多的研究,我不知道实际的答案,但一个可能的答案是 HTML 约定有利于静态页面内容,而 Angular 是为动态页面内容而设计的。这意味着在许多地方打破 HTML 约定,而不是让它限制 Angular 应用程序的可能性。由于控制器被期望承担初始化模型的责任(并且在大多数情况下这样的期望是正确的),Angular 团队将有动机忽略value属性的内容(以及它在其他表单标签中的类似物)。

当然,使用这种方法,对于在控制器初始化之前已经存在的任何适用元素,控制器 init可以覆盖该value属性。然而,这种行为在整个应用程序中并不一致,因为新元素将触发指令评估,而不是控制器初始化阶段。(具有自己的控制器的部分也具有这种行为 - 在部分的控制器 init 之前存在的元素可以被所述 init 覆盖,但之后添加的其他元素不会重新触发 init。)

有许多其他方法可以编写这样的指令,并且它也可以扩展为执行任意数量的其他事情,但希望这种方法可以帮助其他人。

于 2013-06-21T22:51:51.190 回答