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

2023-11-30

我正在寻找如何绑定到 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 。

$范围.$观察

可以在此处查看并运行以下代码: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/$on 第一个广播不会被捕获控制器,但广播的其他调用会在控制器中触发。如果您知道解决 $rootscope.$broadcast 问题的方法,请提供答案。

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


Update

这个问题最初是在 2013 年 4 月提出并回答的。2014 年 5 月,Gil Birman 提供了一个新答案,我将其更改为正确答案。由于吉尔·伯曼的答案很少有赞成票,我担心阅读这个问题的人会忽视他的答案,而选择其他有更多票数的答案。在您决定最佳答案是什么之前,我强烈推荐 Gil Birman 的答案。


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

  • 0 {{lastUpdated}}代替{{timerData.lastUpdated}},这也可以很容易地{{timer.lastUpdated}},我可能会认为它更具可读性(但我们不要争论......我给这一点一个中立的评级,所以你自己决定)

  • +1控制器充当标记的一种 API 可能会很方便,这样如果数据模型的结构以某种方式发生变化,您可以(理论上)更新控制器的API 映射不触及 html 部分。

  • -1然而,理论并不总是实践,我通常发现自己必须修改标记and需要更改时的控制器逻辑,anyway。因此,编写 API 的额外工作抵消了它的优势。

  • -1此外,这种方法不是很 DRY。

  • -1如果你想将数据绑定到ng-model你的代码变得更加不干燥,因为你必须重新打包$scope.scalar_values在控制器中进行新的 REST 调用。

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

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

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

综上所述,一切不必解耦。就将标记完全与数据模型解耦而言,弊大于利。


控制器,一般不应该乱扔$scope = injectable.data.scalar的。相反,它们应该撒上$scope = injectable.data's, promise.then(..)'s, and $scope.complexClickAction = function() {..}'s

作为实现数据解耦和视图封装的替代方法,唯一可以实现的地方将视图与模型分离确实很有意义 is 带有指令。但即使在那里,也不$watch中的标量值controller or link功能。这不会节省时间,也不会提高代码的可维护性和可读性。它甚至不会让测试变得更容易,因为Angular 中的稳健测试通常会测试生成的 DOM。相反,在指令要求中,您data API以对象形式,并赞成仅使用$watch创建者:ng-bind.


Example 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>

UPDATE:我终于回到这个问题并补充说,我认为这两种方法都不是“错误的”。最初我写过乔什·大卫·米勒的答案是不正确的,但回想起来他的观点是完全正确的,特别是他关于关注点分离的观点。

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

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

  1. 关注点分离:组件通过 props 消耗所有数据,并且几乎不依赖全局单例(例如 Angular 服务),并且对发生的情况一无所知above它在视图层次结构中。

  2. 可变性:所有道具都是不可变的,这消除了数据无意突变的风险。

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

AngularJS:绑定到服务属性的正确方法 的相关文章

  • 角度 ui 路由器的动态参数

    我想知道在更改状态并发送请求以从后端获取模板时如何包含参数 这是我的应用程序 angular module questionnaireApp ngAnimate ui router ui bootstrap config stateProv
  • Angularjs 抛出 TypeError:无法读取未定义的属性“indexOf”

    我正在尝试调试上面的代码 我觉得这非常有用 gt 我什至找不到代码中的问题 也不知道从哪里开始 因为 Angularjs 对我来说仍然很新 我正在尝试本地化 Angularjs 应用程序 我知道为了获得帮助而缺少很多上下文 但我正在尝试查看
  • ng-include 跨域帮助 angularjs

    我正在尝试为加载到 ng include 跨域的 url 实现白名单 这是一场噩梦 我有一个在本地运行良好的包含 div div 然后我像这样添加白名单 angular module myApp ngRoute ngResource con
  • 访问指令的范围与嵌入内容隔离

    我不确定这是否真的可能 但我本质上想要 AngularJS 中 隔离范围的反转 这里有一个Plunkr http plnkr co edit 3xL5MrdJSfYH22ivkYJS展示 基本上 我设置了一个自定义指令来提供一些可重用的 H
  • 使用 TemplateColumns 将 WPF DataGrid 绑定到 DataTable

    我已经尝试了一切但一无所获 所以我希望有人能给我一个顿悟的时刻 我根本无法获得成功提取数据网格中数据的绑定 我有一个包含 MyDataType 的多列的 DataTable public class MyData string nameDa
  • 在模态中打开模态

    我有一个有角度的 ui 模态 其中有一个按钮 单击此按钮时 我想在 Angular ui 中打开另一个模式 我该怎么做 scope open function var modalInstance modal open templateUrl
  • 将行推入使用 ng-repeat 以角度呈现的表格中

    当客户端单击该行时 我想在表中插入额外的行 不应预取数据 因为我预计最多有 30 行 但每行都有关联的数据 在一次获取中获取这些数据是不合理的 到目前为止 我的方法是使用 ng repeat 迭代我的集合并渲染表格 当客户端按下该行时 客户
  • 在 AngularJs 中动态更改按钮文本

    我正在使用 AngularJS CSS 和 HTML 这就是我想做的 根据某个函数的输出禁用按钮isPublished 我需要将鼠标悬停在按钮上 就像禁用按钮时 将鼠标悬停在文本上可能是 I m disabled 当它没有被禁用时 悬停在文
  • 当我的网页上有一个持续时间计数器时,AngularJS 有什么帮助吗?

    我有一个使用 Angular ui router 的应用程序 当路由器设置为某种状态时 我希望将计时器设置为例如 2 小时 当它设置为另一个状态时 我想让计数器倒计时 我希望在屏幕上显示剩余时间 有谁有关于如何实现此功能的代码示例吗 如果有
  • 在 History popstate 事件中获取 AngularJs $scope?

    我是 angularjs 开发新手 我有 var app angular module myapp app controller ProductCtrl scope sce function scope sce scope products
  • Angularjs 模式的复选框表现得很奇怪

    我有一个有角度的应用程序plunker http plnkr co edit rac8w9g8L0eX8mlXKuVn p preview 当我们单击该按钮时 它会打开一个包含项目列表的模式对话框 其中 2 项是根据复选框表输入中的条件进行
  • 以角度选择项目后保持菜单打开

    单击我的菜单后 我的菜单将关闭toggleShare按钮 我怎样才能防止这种情况 我将 angularJS 与 Angular 材料一起使用 这是我的代码
  • 将 WPF 快捷键绑定到 ViewModel 中的命令

    我有一个使用 MVVM 模式的 WPF 应用程序 将按钮连接到 VM 非常简单 因为它们实现了 ICommand 我有一个工作原理类似的上下文菜单 下一步是为上下文菜单创建快捷键 我不知道如何让快捷键调用命令 这是一个例子
  • 当请求新页面时,如何将 AngularJS 路由与 Express (Node.js) 结合使用?

    我正在使用 Express 它从静态目录加载 AngularJS 一般情况下我会要求http localhost 其中 Express 为我服务index html以及所有正确的 Angular 文件等 在我的 Angular 应用程序中
  • 复选框上的数据绑定

    我目前正在将数据从 SQL 数据库之一提取到我的应用程序中 我可以让它适用于我的文本框和其他项目 但是 我似乎无法让它适用于复选框 这是我正在使用的代码 DataTable dt new DataTable dt using SqlConn
  • CORS 在 jquery 中工作正常,但在 angularjs 中不行

    我的服务器端是php mysql 我正在另一个域的 Web 服务中进行 Ajax 调用 其中启用了 的访问控制 var postUrl http logical brains com elance clone test login php
  • 使用 Angular 指令禁用文本选择

    我正在学习 JavaScript 和 AngularJS 我想使用 Angular Directive 禁用文本选择 我有该函数的 JavaScript 代码 function clearSelection if document sele
  • WPF 数据绑定到复合类模式?

    我是第一次尝试 WPF 并且正在努力解决如何将控件绑定到使用其他对象的组合构建的类 例如 如果我有一个由两个单独的类组成的类 Comp 为了清楚起见 请注意省略的各种元素 class One int first int second cla
  • 仅当显式选择行时才关闭 ui-bootstrap typeahead

    我创建了这个jsBin http jsbin com livuqafe 2 edit来证明我遇到的问题 如果您转到此处 请尝试输入 五 并继续 你的自然反应是输入 五 然后按 Tab 如果你想要 五百 你可以向下箭头一次 但是 在这种情况下
  • 当共享相同的行和列时,将网格项设置为不重叠

    现在 当两个网格项共享相同的行和列时 它们会相互重叠 div class some grid container div Item 1 div div Item 2 div div 我如何让它们不重叠 当共享相同的行和列时 其行为可能类似于

随机推荐

  • 无法使用 ColdFusion 和 HMAC-SHA1 为 API 生成有效签名

    我已经阅读了许多关于这个主题的其他相关帖子 并且能够毫无问题地复制它们 但是 无论我尝试做什么 我都无法使用自己的数据获得预期的签名结果 我将非常感谢任何帮助 以下是 API 要求 将数据符号从 ASCII 字符串转换为字节数组 将您的秘密
  • 无法运行程序“make”:系统找不到指定的文件?

    这是第一次出现此错误 我将 Cygwin 与 Eclipse 3 5 一起使用 我的 Path 变量设置为 CommonProgramFiles Microsoft Shared Windows Live SystemRoot system
  • 使用 Android FFT 获取声音频率

    下面的代码仅显示一个图表 但我想要声音的频率 我正在尝试录制语音并获取实时频率 以便我可以弹奏钢琴或吉他声音并找到频率 public class AudioProcessing extends Activity implements OnC
  • setAttribute 和 htmlElement.attribute='value' 之间的区别

    两者之间有什么区别 b1 setAttribute id b1 and b1 id b1 其中一个比另一个更有效率吗 他们两个都会做完全相同的任务吗 在某些情况下它们会有所不同吗 setAttribute 和 htmlElement att
  • 在 XHTML 1.0 Strict 中,属性值是否需要用引号引起来?

    在 XHTML 1 0 Strict 中 属性值是否需要用引号引起来 例子
  • [显示(提示MVC3

    我正在尝试设置我的模型 以便我可以使用 Html EditorFor e gt e publicationTitle 并让它显示带有提示的水印 目前我正在做 Html LabelFor e gt e PublicationTitle Htm
  • Google BigQuery:滚动计数不同

    我有一个表 其中只是日期和用户 ID 的列表 未聚合 我们定义一个称为活跃用户对于给定日期 通过计算过去 45 天内出现的不同 ID 数量 我正在尝试在 BigQuery 中运行一个查询 该查询每天都会返回该天加上当天的活跃用户数 计算从
  • 如何扩展ZF2骨架应用程序-具有外键的实体

    我的 ZF2 骨架应用程序按照 Zend 用户指南运行良好 但现在我正在兜圈子 试图扩展应用程序 以便专辑的艺术家不再是字符串 而是我的数据库中艺术家表的外键 我已经创建了所有必要的模型 控制器 视图来创建 编辑和查看艺术家 这也工作得很好
  • Instagram API:我想根据标签获取最近的图像,但我只收到我自己的

    我想用Instagram API根据特定标签获取最新图像 当我使用时 https api instagram com v1 tags tag name media recent access token ACCESS TOKEN 我只收到用
  • python print 语句中出现意外 None

    我正在尝试打印连接到其他节点的节点列表 以便我可以查看它们以调试一些围绕图形的 python 代码 我这样做是为了练习 所以我自己设置节点 边 组 我尝试使用 for every type 循环打印出与 myNode 类内部的函数的连接 但
  • Webpack 对 Gatsby 网站上内置模块的重大更改

    我尝试将我的 Gatsby 站点部署到 Netlify 但每当我尝试部署时 我总是收到各种节点模块的这些错误 我尝试制作一个 webpack config js 文件并包含两个建议的解决方案 但均无济于事 我还尝试使用别名而不是后备 将浏览
  • 如何在Windows命令行中运行这个java类?

    package com test01 public class test01 public static void main String args System out println hi 我认为java应用程序启动器非常愚蠢 我已经指
  • 使用 FDM 的 Matlab 2D 波动方程

    以下是我使用 FDM 模拟以高斯源为中心的二维波动方程的 Matlab 代码 我使用 imagesc 函数来输出波 波浪似乎从中心向外扩散 但速度非常缓慢 好像我在某个地方搞砸了 并且输出非常像素化 我究竟做错了什么 clc close a
  • 如何在 flutter 中使用自定义 Clipper 制作弯曲的应用程序栏

    嗨 我是颤振新手 I am trying to make this app bar this is my final goal 我尝试按照一些教程制作弯曲的应用程序栏 但我无法得到与我想要的相同的结果 after some googling
  • INVALID_ARGUMENT:应用程序凭据标头无效。请修复客户端以传递有效的应用程序凭据标头

    当尝试运行简单的 Android Instant App 时 我在控制台中收到此错误 并且应用程序无法打开 此错误是什么意思以及如何传递有效的凭据标头 有一个已知问题 即不允许模拟器与即时应用程序后端通信 从而导致此错误 如果您尝试使用模拟
  • 使用字符串变量作为变量名[重复]

    这个问题在这里已经有答案了 我有一个分配有字符串的变量 我想根据该字符串定义一个新变量 foo bar foo something else What I actually want is bar something else 您可以使用e
  • Plotly:如何检查和更改绘图图形?

    相关问题已经被问过 例如 如何搜索绘图图形特定属性的选项 Plotly 如何检查基本图形结构 版本 4 但这些问题的答案受到以下事实的限制 并非所有参数都可以通过 Python 获得 这意味着真正的答案隐藏在 JavaScript 中的某个
  • 如何合并两个priority_queue?

    我有两个priority queue with float像这样 std priority queue
  • 无法将 Null 值分配给可为 Null 的 Int32?通过绑定

    无法通过 TextBox 绑定将 null 值分配给 Int32 如果 TextBox 为空 则不会调用 Int32Null Set TexBox 周围有红色边框 表示验证异常 这作为 Int32 没有意义 可以为空 如果用户从 TextB
  • AngularJS:绑定到服务属性的正确方法

    我正在寻找如何绑定到 AngularJS 中的服务属性的最佳实践 我已经通过多个示例来了解如何绑定到使用 AngularJS 创建的服务中的属性 下面我有两个示例说明如何绑定到服务中的属性 他们都工作 第一个示例使用基本绑定 第二个示例使用