当前位置: 首页 > 面试题库 >

AngularJS:绑定到服务属性的正确方法

东方夕
2023-03-14
问题内容

我正在寻找有关如何绑定到AngularJS中的服务属性的最佳实践。

我已经研究了多个示例,以了解如何绑定到使用AngularJS创建的服务中的属性。

下面有两个关于如何绑定到服务中的属性的示例。他们都工作。第一个示例使用基本绑定,第二个示例使用$ scope。$ watch绑定到服务属性

当绑定到服务中的属性时,这些示例是首选还是建议使用其他我不知道的选项?

这些示例的前提是服务应每5秒更新其属性“ lastUpdated”和“
calls”。服务属性更新后,视图应反映这些更改。这两个示例都可以成功运行;我想知道是否有更好的方法。

基本绑定

可以在下面的代码中查看和运行以下代码:http :
//plnkr.co/edit/d3c16z

<html>
<body ng-app="ServiceNotification" >

    <div ng-controller="TimerCtrl1" style="border-style:dotted"> 
        TimerCtrl1 <br/>
        Last Updated: {{timerData.lastUpdated}}<br/>
        Last Updated: {{timerData.calls}}<br/>
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
    <script type="text/javascript">
        var app = angular.module("ServiceNotification", []);

        function TimerCtrl1($scope, Timer) {
            $scope.timerData = Timer.data;
        };

        app.factory("Timer", function ($timeout) {
            var data = { lastUpdated: new Date(), calls: 0 };

            var updateTimer = function () {
                data.lastUpdated = new Date();
                data.calls += 1;
                console.log("updateTimer: " + data.lastUpdated);

                $timeout(updateTimer, 5000);
            };
            updateTimer();

            return {
                data: data
            };
        });
    </script>
</body>
</html>

解决绑定服务属性的另一种方法是在控制器中使用$ scope。$ watch。

$ scope。$ watch

可以在此处查看和运行以下代码:http :
//plnkr.co/edit/dSBlC9

<html>
<body ng-app="ServiceNotification">
    <div style="border-style:dotted" ng-controller="TimerCtrl1">
        TimerCtrl1<br/>
        Last Updated: {{lastUpdated}}<br/>
        Last Updated: {{calls}}<br/>
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
    <script type="text/javascript">
        var app = angular.module("ServiceNotification", []);

        function TimerCtrl1($scope, Timer) {
            $scope.$watch(function () { return Timer.data.lastUpdated; },
                function (value) {
                    console.log("In $watch - lastUpdated:" + value);
                    $scope.lastUpdated = value;
                }
            );

            $scope.$watch(function () { return Timer.data.calls; },
                function (value) {
                    console.log("In $watch - calls:" + value);
                    $scope.calls = value;
                }
            );
        };

        app.factory("Timer", function ($timeout) {
            var data = { lastUpdated: new Date(), calls: 0 };

            var updateTimer = function () {
                data.lastUpdated = new Date();
                data.calls += 1;
                console.log("updateTimer: " + data.lastUpdated);

                $timeout(updateTimer, 5000);
            };
            updateTimer();

            return {
                data: data
            };
        });
    </script>
</body>
</html>

我知道我可以在服务中使用$ rootscope。$ broadcast并在控制器中使用$ root。$ on,但是在我创建的其他示例中,第一次广播中使用$
broadcast / $并不能捕获控制器,但是在控制器中触发了广播的其他呼叫。如果您知道解决$ rootscope。$
broadcast问题的方法,请提供答案。

但是要重申我之前提到的内容,我想知道如何绑定到服务属性的最佳实践。

更新资料

最初在2013年4月提出并回答了这个问题。2014年5月,Gil Birman提供了一个新答案,我将其更改为正确答案。由于吉尔·伯曼(Gil
Birman)的回答几乎没有票数,因此我担心的是,阅读此问题的人会无视他的回答,而赞成其他票数更多的回答。在您决定最佳答案之前,我强烈建议您使用Gil
Birman的答案。


问题答案:

考虑 第二种方法的 一些 优缺点

  • 0 {{lastUpdated}}而不是{{timerData.lastUpdated}},这很容易被接受{{timer.lastUpdated}},我可能会认为它更具可读性(但请不要争论……我给这一点是中性评级,以便您自己决定)

  • +1 控制器作为标记的一种API可能很方便,这样,如果数据模型的结构发生某种变化,您就可以(理论上)更新控制器的 API映射, 而无需触摸html局部。

  • -1 然而,理论并不总是练习,我经常发现自己不得不修改标记 控制器逻辑更改时呼吁, 反正 。因此,编写API的额外努力抵消了它的优势。

  • -1 而且,这种方法不是很干。

  • -1 如果要将数据绑定到ng-model代码,则DRY变得更少,因为必须将其重新打包$scope.scalar_values在控制器中以进行新的REST调用。

  • -0.1 创建额外的观察器对性能 几乎 没有影响。此外,如果不需要在特定控制器中监视的数据属性附加到模型,它们将为深度监视者增加额外的开销。

  • -1 如果多个控制器需要相同的数据模型怎么办?这意味着您需要在每个模型更改时更新多个API。

$scope.timerData = Timer.data;正在开始发出巨大的诱惑……让我们更深入地探讨最后一点……我们在谈论什么样的模型更改?后端(服务器)上的模型?还是仅在前端创建并创建的模型?在这两种情况下,
数据映射API 本质上都属于 前端服务层 (角度工厂或服务)。(请注意,您的第一个示例(我的偏好)在 服务层 中没有这样的API
,这很好,因为它很简单,不需要它。)

总而言之 ,一切都不必分离。就将标记与数据模型完全脱钩而言,弊大于利。

一般而言,控制器 不应乱用$scope = injectable.data.scalar。相反,他们应该被洒$scope = injectable.data的,promise.then(..)‘s和$scope.complexClickAction = function() {..}

作为实现数据解耦和视图封装的另一种方法, 将视图与模型分离的 唯一 有意义的 地方是 使用伪指令
。但即使在那儿,也不要$watchcontrolleror
link函数中标量值。那将不会节省时间,也不会使代码更具可维护性和可读性。它甚至都不会使测试变得容易,因为 角度的强大测试通常会测试最终的DOM
。相反,在指令中,要求您以对象形式提供 数据API ,并且只喜欢使用$watch由创建的er ng-bind

示例
http://plnkr.co/edit/MVeU1GKRTN4bqA3h9Yio

<body ng-app="ServiceNotification">
    <div style="border-style:dotted" ng-controller="TimerCtrl1">
        TimerCtrl1<br/>
        Bad:<br/>
        Last Updated: {{lastUpdated}}<br/>
        Last Updated: {{calls}}<br/>
        Good:<br/>
        Last Updated: {{data.lastUpdated}}<br/>
        Last Updated: {{data.calls}}<br/>
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
    <script type="text/javascript">
        var app = angular.module("ServiceNotification", []);

        function TimerCtrl1($scope, Timer) {
            $scope.data = Timer.data;
            $scope.lastUpdated = Timer.data.lastUpdated;
            $scope.calls = Timer.data.calls;
        };

        app.factory("Timer", function ($timeout) {
            var data = { lastUpdated: new Date(), calls: 0 };

            var updateTimer = function () {
                data.lastUpdated = new Date();
                data.calls += 1;
                console.log("updateTimer: " + data.lastUpdated);

                $timeout(updateTimer, 500);
            };
            updateTimer();

            return {
                data: data
            };
        });
    </script>
</body>

更新 :我终于回到这个问题,补充说,我认为这两种方法都不是“错误的”。最初我写的是乔什·戴维·米勒(Josh David
Miller)的回答是错误的,但回想起来,他的观点是完全正确的,尤其是他关于关注点分离的观点。

除了关注点分离(但与切向相关)外,我没有考虑 防御性复制
的另一个原因。这个问题主要涉及直接从服务读取数据。但是,如果团队中的开发人员决定控制器需要在视图显示之前以某种简单的方式转换数据呢?(控制器是否应该完全转换数据是另一个讨论。)如果她不首先复制该对象,则可能会不经意地导致另一个使用相同数据的视图组件发生回归。

这个问题真正突出的是典型的角度应用程序(以及实际上任何JavaScript应用程序)的体系结构缺陷:关注点紧密耦合以及对象可变性。最近,我迷上了使用React
不可变数据结构设计应用程序的方法。这样做可以很好地解决以下两个问题:

  1. 关注点分离 :通过道具的组件消耗所有它的数据,并拥有小到无的全球单身人士(如角服务)的依赖,并一无所知发生什么 上面 视图层次结构中它。

  2. 可变性 :所有道具都是不可变的,从而消除了不知不觉间数据突变的风险。

Angular 2.0现在有望从React大量借鉴以实现上述两点。



 类似资料:
  • 问题内容: 目的是使产品名称出现在缩略图的工具提示中。浏览器不会根据“ ng-title”或“ ng-attr-title”创建工具提示。 我们正在使用AngularJS 1.0.7版。您可以在任何属性前面加上“ ng-”或“ ng- attr”,Angular会进行相应的绑定。但是,它似乎没有“绑定”到HTML“ A”标签的标题上。 例如 1。 码: 预期结果: 实际结果:工具提示中出现不必要的

  • servlet 可以按名称绑定对象属性到 HttpSession 实现,任何绑定到会话的对象可用于任意其他的 servlet,其属于同一个 ServletContext 且处理属于相同会话中的请求。 一些对象可能需要在它们被放进会话或从会话中移除时得到通知。这些信息可以从 HttpSessionBindingListener 接口实现的对象中获取。这个接口定义了以下方法,用于标识一个对象被绑定到会

  • 我有一个JavaFX 8应用程序,希望允许一个任务修改两个不同的UI元素。据我所知,如果我有一个标签要修改,我可以用mylabel绑定到标签。textProperty()。绑定(mytask.messageProperty())并在任务中使用updateMessage()。 如何使用两种不同的任意类型执行此操作?我已经查看了并发和JavaFX文档中的示例,但对我来说,它们并没有很好地解释这一点。

  • 问题内容: 我有一个带有文本字段和按钮的简单fxml。如果文本字段为空,我想禁用按钮。所以我在控制器中插入如下内容: ..那很好。问题是当我添加第二个文本字段时,如果其中一个文本字段为空,希望禁用我的按钮。那该怎么办?我尝试了以下操作,但这不起作用: 问题答案: 可以通过以下方式绑定到布尔表达式:

  • 我有一个带有文本字段和按钮的简单fxml。如果文本字段为空,我想禁用按钮。所以我在我的控制器中插入如下内容: ..这很好用。问题是,当我添加第二个文本字段时,如果其中一个文本字段为空,我希望禁用我的按钮。那怎么办呢?我尝试了以下方法,但不起作用:

  • 我正在尝试创建一个基于Spring 4的restful服务。服务应该使用json和xml。我创建了一个xsd,并使用xjc将xsd编译成绑定类。 这里是xsd 以下是运行xjc后的java类: 服务请求。JAVA 服务输出。JAVA ListOfValues.java 控制类 web.xml mvc调度servlet。xml 发帖请求: 图:eclipse调试断点 这些是罐子 公共记录。jar j