The view is not updated when the model updates in

2020-02-26 00:31发布

I have read threads on this issue such as: The view is not updated in AngularJS but I still can't understand how to apply it on my simple example.

I have this function:

function MyPageView($scope) {
  var myModel = new MyModel();
  $scope.myModel = myModel;
}

when myModel is updated elsewhere in the code (when user clicks, interacts, send XHR requests) it doesn't update my view. I understand I need to do something with $apply but I didn't understand where and how.

Can someone explain to me how do I solve this issue for this simple use-case?

My model looks something like this (if that is necessary for the question) - it has no AngularJS code inside of it:

var MyModel = function() {
  var _this = this;
  ...
  _this.load = function(){...};
  _this.updateModel = function(){...};
  ...
  return _this;
}

adding a JSfiddle example: http://jsfiddle.net/DAk8r/2/

4条回答
家丑人穷心不美
2楼-- · 2020-02-26 00:53

In Angular apps, models are normally sometimes implemented on $scope, not as a separate JavaScript object. Here is a rewrite of your app showing how to do that

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>

Here's a fiddle, with no jQuery, and it shows the "normal way" of setting up a fiddle for Angular.

查看更多
欢心
3楼-- · 2020-02-26 00:58

try $scope.$apply() inside your controller after you update your model

查看更多
祖国的老花朵
4楼-- · 2020-02-26 01:02

The crux of your problem is that you're trying to mix AngularJS with a very traditional, "jQuery-soup style" JavaScript pattern. In Angular, you should always use directives to do DOM manipulation and interaction (including clicks). In this case, your code should look more like the following:

<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;
}

Notice how, instead of setting up a manual click handler with jQuery, we use Angular's built-in ng-click directive. This allows us to tie in to the Angular scope lifecycle, and correctly update the view when the user clicks the link.

Here's a quote from the AngularJS FAQ; I've bolded a part that might help you break the habit.

Common Pitfalls

The Angular support channel (#angularjs on Freenode) sees a number of recurring pitfalls that new users of Angular fall into. This document aims to point them out before you discover them the hard way.

DOM Manipulation

Stop trying to use jQuery to modify the DOM in controllers. Really. That includes adding elements, removing elements, retrieving their contents, showing and hiding them. Use built-in directives, or write your own where necessary, to do your DOM manipulation. See below about duplicating functionality.

If you're struggling to break the habit, consider removing jQuery from your app. Really. Angular has the $http service and powerful directives that make it almost always unnecessary. Angular's bundled jQLite has a handful of the features most commonly used in writing Angular directives, especially binding to events.

Finally, here your example, working using this technique: http://jsfiddle.net/BinaryMuse/xFULR/1/

查看更多
走好不送
5楼-- · 2020-02-26 01:06

http://jsfiddle.net/zCC2c/

Your problem is twofold.

1) There was a syntax error in your jsfiddle, as DOMElements (such as the a returned by $(this) inside your clickhandler have no prevent default. You actually needed to pass an event. (Minor syntax issue).

2) By putting your variable definition within the controllers scope like so:

 function MyCtrl($scope){
     $scope.foo = foo;
 }

You ensure it gets run once per class instantiation.

What you want is:

 function MyCtrl($scope){
      $scope.someAngularClickHandler=function(){
         $scope.foo = foo;
      }
 }

And then on your link

   <a href="foo" id="bar" ng-click="someAngularClickHandler()">

For a more exhaustive codesample see the linked jsfiddle.

A good overview of the theory can be found in the first talk here:

http://www.youtube.com/watch?feature=player_embedded&v=VxuN6WO3tIA

查看更多
登录 后发表回答