gpt4 book ai didi

AngularJS : The correct way of binding to a service properties

转载 作者:行者123 更新时间:2023-12-01 22:59:36 27 4
gpt4 key购买 nike

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

我已经通过多个示例了解如何绑定(bind)到使用 AngularJS 创建的服务中的属性。

下面我有两个示例,说明如何绑定(bind)到服务中的属性;他们都工作。第一个示例使用基本绑定(bind),第二个示例使用 $scope.$watch 绑定(bind)到服务属性

在绑定(bind)到服务中的属性时,这些示例中的任何一个是首选,还是有其他我不知道的选项会被推荐?

这些示例的前提是服务应该每 5 秒更新一次其属性“lastUpdated”和“calls”。更新服务属性后, View 应反射(reflect)这些更改。这两个示例都成功运行;我想知道是否有更好的方法来做到这一点。

基本绑定(bind)

以下代码可以在这里查看和运行: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>

我解决绑定(bind)到服务属性的另一种方法是在 Controller 中使用 $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 并在 Controller 中使用 $root.$on,但在我创建的其他示例中,使用 $broadcast/$on 第一个广播不被捕获 Controller ,但在 Controller 中触发了广播的其他调用。如果您知道解决 $rootscope.$broadcast 问题的方法,请提供答案。

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

更新

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

最佳答案

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

  • 0 {{lastUpdated}}而不是 {{timerData.lastUpdated}} ,这很容易成为 {{timer.lastUpdated}} ,我可能认为它更具可读性(但我们不要争论......我给这一点一个中立的评级,所以你自己决定)
  • +1 Controller 充当标记的一种 API 可能很方便,这样如果数据模型的结构以某种方式发生变化,您可以(理论上)更新 Controller 的 API 映射,而无需触及 html 部分。
  • -1 然而,理论并不总是实践,我通常发现自己必须在需要更改时修改标记和 Controller 逻辑,无论如何。因此,编写 API 的额外努力抵消了它的优势。
  • -1 此外,这种方法不是很 DRY。
  • -1 如果要将数据绑定(bind)到ng-model您的代码变得更不干燥,因为您必须重新打包 $scope.scalar_values在 Controller 中进行新的 REST 调用。
  • -0.1 有一个很小的性能损失,会产生额外的观察者。此外,如果数据属性附加到不需要在特定 Controller 中观察的模型,它们将为深度观察者创造额外的开销。
  • -1 如果多个 Controller 需要相同的数据模型怎么办?这意味着您有多个 API 可以随着每次模型更改而更新。
  • $scope.timerData = Timer.data;现在开始听起来很诱人……让我们深入研究最后一点……我们在谈论什么样的模型变化?后端(服务器)上的模型?还是只在前端创建并存在的模型?无论哪种情况,本质上数据映射 API 都属于前端服务层( angular.factory 或服务)。 (请注意,您的第一个示例——我的偏好——在服务层中没有这样的 API,这很好,因为它足够简单,不需要它。)

    总结 ,一切都不必解耦。就将标记完全与数据模型解耦而言,弊大于利。

    Controller ,一般不应该到处都是 $scope = injectable.data.scalar的。相反,它们应该撒上 $scope = injectable.data的, promise.then(..)的,和 $scope.complexClickAction = function() {..}

    作为实现数据解耦从而实现 View 封装的替代方法,唯一的地方 将 View 与模型分离真的很有意义 带有指令 .但即使在那里,也不要 $watch controller 中的标量值或 link功能。这不会节省时间或使代码更具可维护性或可读性。它甚至不会使测试更容易,因为 angular 中的健壮测试通常无论如何都会测试生成的 DOM。相反,在指令中要求您的数据 API 为对象形式,并倾向于仅使用 $watch创建者 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 的回答是不正确的,但回想起来,他的观点是完全有效的,尤其是他关于关注点分离的观点。

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

    这个问题真正突出的是典型 Angular 应用程序(以及任何 JavaScript 应用程序)的架构缺陷:关注点的紧密耦合和对象可变性。我最近迷上了使用 React 和不可变数据结构构建应用程序。这样做可以很好地解决以下两个问题:
  • 关注点分离 :一个组件通过 props 消耗它的所有数据并且几乎不依赖全局单例(例如 Angular 服务),并且对 View 层次结构中它上面发生的事情一无所知。
  • 可变性 :所有 Prop 都是不可变的,这消除了不知情的数据突变的风险。

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

    关于AngularJS : The correct way of binding to a service properties,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15800454/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com