AngularJS 中的模型更新时视图不会更新
Posted
技术标签:
【中文标题】AngularJS 中的模型更新时视图不会更新【英文标题】:The view is not updated when the model updates in AngularJS 【发布时间】:2012-12-31 17:14:12 【问题描述】:我已阅读有关此问题的主题,例如:The view is not updated in AngularJS,但我仍然无法理解如何将其应用于我的简单示例。
我有这个功能:
function MyPageView($scope)
var myModel = new MyModel();
$scope.myModel = myModel;
当myModel
在代码的其他地方更新时(当用户点击、交互、发送 XHR 请求时)它不会更新我的视图。我知道我需要用 $apply 做一些事情,但我不明白在哪里以及如何做。
有人可以向我解释如何解决这个简单用例的问题吗?
我的模型看起来像这样(如果问题需要这样做的话) - 它里面没有 AngularJS 代码:
var MyModel = function()
var _this = this;
...
_this.load = function()...;
_this.updateModel = function()...;
...
return _this;
添加 JSfiddle 示例: http://jsfiddle.net/DAk8r/2/
【问题讨论】:
这里没有足够的代码来准确地告诉您出了什么问题。您能否向我们展示一个导致模型更新而不是视图更新的交互示例?如果你有一个关于 jsFiddle 或类似的工作示例,那就更好了。 如果您可以发布您的视图代码的摘录,展示它如何与控制器交互以及它期望 myModel 的位置,那就太棒了。如果您可以在某种程度上充实 MyModel 函数,这也很有帮助。正如布兰登上面所说,你所拥有的并不足以告诉你发生了什么。 @BrandonTilley,我添加了一个 JSfiddle 示例:jsfiddle.net/DAk8r/1 @AbrahamP,我添加了一个 JSfiddle.. 我修复了一个问题 - 这是更新版本:jsfiddle.net/DAk8r/2 【参考方案1】:在 Angular 应用程序中,模型通常有时在 $scope 上实现,而不是作为单独的 javascript 对象。这是您的应用程序的重写,展示了如何做到这一点
function myModelCtrl($scope)
$scope.number = 0;
$scope.updateNumber = function ()
$scope.number += 1;
alert('new number should display ' + $scope.number);
html:
<div ng-controller="myModelCtrl">
<div>Number is number</div>
<a ng-click="updateNumber()">Update Number</a>
</div>
这是一个fiddle,没有 jQuery,它显示了为 Angular 设置小提琴的“正常方式”。
【讨论】:
AngularJS 最佳实践经常被引用 "Scope is not your model. Scope is what you attach your model to." 对于非常简单的控制器,这种事情可能没问题,但通常你会想要拥有自己的模型层。 @Brandon,感谢视频链接(我还没有看到那个)。我觉得我现在从Scope 页面中理解了这句话:“范围是引用应用程序模型的对象。”您是否将服务视为定义模型层的一种方式?如果没有,您建议在哪里定义模型?您是否知道任何具有单独模型层的 Angular 应用程序的好示例? 仅供其他读者参考,在与 Brandon 的其他评论交流中,我想他会说服务是定义模型的地方。例如,请参阅 Brandon 的 this answer。 哇,小世界! (抱歉,我再也没有回复过这条评论。)服务特别适合模型对象,因为它们可以被注入,因此很容易在测试中模拟。【参考方案2】:http://jsfiddle.net/zCC2c/
你的问题是双重的。
1) 您的 jsfiddle 中存在语法错误,因为 DOMElements(例如单击处理程序中 $(this) 返回的 a 没有阻止默认值。您实际上需要传递一个事件。(轻微的语法问题)。
2) 将变量定义放在控制器范围内,如下所示:
function MyCtrl($scope)
$scope.foo = foo;
您确保它在每个类实例化时运行一次。
你想要的是:
function MyCtrl($scope)
$scope.someAngularClickHandler=function()
$scope.foo = foo;
然后在你的链接上
<a href="foo" id="bar" ng-click="someAngularClickHandler()">
有关更详尽的代码示例,请参阅链接的 jsfiddle。
可以在此处的第一次演讲中找到对该理论的一个很好的概述:
http://www.youtube.com/watch?feature=player_embedded&v=VxuN6WO3tIA
【讨论】:
控制器不是单例。您可以在同一页面上多次实例化 MyCtrl。也许您将服务与控制器混淆了——服务是单例的。【参考方案3】:问题的症结在于您试图将 AngularJS 与非常传统的“jQuery-soup 风格”JavaScript 模式混合使用。在 Angular 中,您应该始终使用指令来进行 DOM 操作和交互(包括点击)。在这种情况下,您的代码应如下所示:
<div ng-controller="myModelCtrl">
<div>Number is myModel.number</div>
<a ng-click="myModel.updateNumber()">Update Number</a>
</div>
function myModelCtrl($scope)
var myModel = new MyModel();
$scope.myModel = myModel;
function MyModel()
var _this = this;
_this.number = 0;
_this.updateNumber = function()
_this.number += 1;
alert('new number should display ' + _this.number);
return _this;
请注意,我们不是使用 jQuery 手动设置 click
处理程序,而是使用 Angular 的内置 ng-click
指令。这允许我们绑定到 Angular 范围生命周期,并在用户单击链接时正确更新视图。
这是来自AngularJS FAQ 的引述;我已将可能帮助您改掉这个习惯的部分加粗。
常见的陷阱
Angular 支持频道(Freenode 上的#angularjs)发现了许多 Angular 新用户经常陷入的陷阱。本文档旨在在您发现它们之前指出它们。
DOM 操作
停止尝试使用 jQuery 修改控制器中的 DOM。真的。这包括添加元素、删除元素、检索它们的内容、显示和隐藏它们。使用内置指令,或在必要时编写自己的指令来进行 DOM 操作。有关复制功能,请参见下文。
如果您正在努力改掉这个习惯,请考虑从您的应用程序中删除 jQuery。真的。 Angular 拥有 $http 服务和强大的指令,几乎总是不需要它。 Angular 捆绑的 jQLite 具有一些最常用于编写 Angular 指令的特性,尤其是绑定到事件。
最后,这里是你的例子,使用这种技术:http://jsfiddle.net/BinaryMuse/xFULR/1/
【讨论】:
为什么需要var _this = this;
?【参考方案4】:
更新模型后在控制器中尝试 $scope.$apply()
【讨论】:
在我的控制器内部 $scope 没有定义,正如您在 jsfiddle.net/DAk8r/2 中看到的那样 这很好用。但是您能否解释一下为什么需要它。它应该默认反映为角度承诺two way data binding以上是关于AngularJS 中的模型更新时视图不会更新的主要内容,如果未能解决你的问题,请参考以下文章
AngularJS:从模型数组拼接模型元素时,不会更新 ng-repeat 列表