【问题标题】:Making data templated in available to ng-model使模板化的数据可用于 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 模型在客户端上绑定该值一次?

【问题讨论】:

    标签: 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-10
      • 1970-01-01
      • 1970-01-01
      • 2014-09-30
      • 2016-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多