简体   繁体   中英

View is not updating in Ajax request in Angular 1.x

I am getting data from the json file, for the first time data is getting retrieved from the json file but after that if json file is updated, the values does not get updated in the view. In other words, json file is not in sync with the view.

I am new to Angular and I am not able to understand, why is this happening and how to resolve this issue. Script that I am using.

var todoApp = angular.module("todoApp", []);
var model = {
    user: "Adam"
};
todoApp.run(function($http) {
    $http.get("todo.json").then(function(response) {
        model.items = response.data;

    });
});
todoApp.filter("checkedItems", function(){
  return function(items, showComplete){
    var resultArr = [];
    angular.forEach(items, function(item){
      if(item.done==false || showComplete==true){
        resultArr.push(item);
      }
    });
    return resultArr;
   }
});
todoApp.controller("Todoctrl", function($scope){
   $scope.todo = model;

   $scope.incompleteCount = function(){
     var count=0;
     angular.forEach($scope.todo.items, function(item){
       if(!item.done) {count++}
     });
     return count;
   }

   $scope.warningClass = function(){
     return ($scope.incompleteCount()<3 ? "label-success" : "label-warning");
   }

  $scope.newTodo = function(actionText){
    $scope.todo.items.push({action:actionText, done:false });
  }
});

todo.json file

[
    { "action": "Buy Flowers", "done": false },
    { "action": "Get Shoes", "done": false },
    { "action": "Collect Tickets", "done": true },
    { "action": "Study Geology", "done": false }
]

html code

<body ng-controller="Todoctrl">
<div class="page-header">
  <h1>{{ todo.user }}'s To Do List
    <span class="label label-default" ng-class="warningClass()"
      ng-hide="incompleteCount() == 0">
      {{incompleteCount()}}
    </span>
  </h1>
</div>
<div class="panel">
  <div class="input-group">
    <input class="form-control" ng-model="actionText">
    <span class="input-group-btn">
      <button class="btn btn-default" ng-click="newTodo(actionText)">Add</button>
    </span>
  </div>
  <table class="table table-striped">
    <thead>
      <tr>
        <th>Description</th>
        <th>Done</th>
      </tr>
    </thead>
    <tbody>
      <tr ng-repeat="item in todo.items | checkedItems:showComplete | orderBy: 'action'">
        <td>{{item.action}}</td>
        <td><input type="checkbox" ng-model="item.done"></td>
      </tr>
    </tbody>
  </table>
  <div class="checkbox-inline">
    <label><input type="checkbox" ng-model="showComplete"> Show Complete</label>
  </div>
</div>

$scope you can 't use inside .run() .

var todoApp = angular.module("todoApp", []);
var model = {
    user: "Adam"
};
todoApp.run(function ($http, $rootScope) {
    $http.get("todo.json").then(function (response) {
        model.items = response.data;
        $rootScope.model = model; // Use model in html page
    });
});

todoApp.controller("Todoctrl", function ($scope) {
    $scope.todo = {};
    $scope.$watch('model', function () {
        $scope.todo = $rootScope.model;
    });

    $scope.incompleteCount = function () {
        var count = 0;
        angular.forEach($scope.todo.items, function (item) {
            if (!item.done) {
                count++
            }
        });
        return count;
    }

    $scope.warningClass = function () {
        return ($scope.incompleteCount() < 3 ? "label-success" : "label-warning");
    }

    $scope.newTodo = function (actionText) {
        $scope.todo.items.push({
            action: actionText,
            done: false
        });
    }
});

in angular we use $scope variable to bind view elements to the values in the controller. But this $scope variable is not available in run . So instead we use $rootScope

$rootScope is the scope created on the HTML element that contains the ng-app directive.

The rootScope is available in the entire application.

var todoApp = angular.module("todoApp", []);
todoApp.run(function($http, $rootScope) {
    $rootScope.model = {
        user: "Adam",
        items: []
    };
    $http.get("todo.json").then(function(response) {
        $rootScopr.model.items = response.data;

    });
});

Firstly I don't think your Http.get function should be in your run but rather in your Todoctrl controller.Then you can use $rootScope to distribute the data elsewhere because at the moment you don't know if it works.

Secondly, if the get works and does not update try use this : http://jimhoskins.com/2012/12/17/angularjs-and-apply.html

Thirdly use chrome developer tools to debug line by line

You're doing it all wrong.

First : Use a service for your $http call.

angular.module('todoApp')
.service('JSONService', function($http){

    this.getItems = function(){
        $http.get("todo.json")
        .then(function(response) {
             return response.data;
        });

    }
});

This way, all you have to do is call getItems() again when JSON is updated.

Secondly : I see you're using run to set the model object, and then getting it through the controller. Don't do that.
Instead use a service for that too, which will get initialized in the start of your application, and be active throughout. Plus, it won't pollute the global namespace or $rootScope .

angular.module('todoApp')
.service('ModelService', function(JSONService){
    this.model = {
        user: "Adam",
        items: []
    };

    // code to fetch items; could put in a function as well
    JSONService.getItems()
    .then(function(items){
        this.model.items = items;
    }) 
});

Thirdly : Use your service created in the first point in your controller to populate the todo object. Whenever your JSON updates, send an event to update your service and controller.

// in your controller
$scope.todo = ModelService.model;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM