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 更新视图

AngularJS:从模型数组拼接模型元素时,不会更新 ng-repeat 列表

模型更改时视图中的列表不会更新

onchange 不会改变 AngularJS 视图中的 $scope

Angularjs视图不更新

AngularJS:$ scope.array.push()不会更新视图,即使使用$ apply也是如此