简体   繁体   中英

How is the best way to update $scope after fetching data from service in AngularJS

I'm working in a small app in angularJS that gets, displays and manipulates data using calls to an API service.

At the beginning everything was smooth and simple, but when I had to show the same data in different parts of the app under different controllers I started moving all the API calls to a factory to share that data and control to not make another request if there is no need for it.

But with that, came a different problem: requests are made, data is put in the proper $scope, but no changes are reflected in the view until I manually click somewhere to interact with the view.

I've been trying using $scope.$apply and $scope.$watch; and I managed to make it work, but now I find myself using delays in a lot of places which seems very unnatural for me.

I'll show you for example the code for the user profile to see what I'm speaking about.

HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">

<title>Demo</title>
</head>
<body ng-app="app" ng-controller="DashboardCtrl">

<div ng-init="getOwnProfile()">
  <h1>My account</h1>

  <form class="inline-form" role="form">
      <input type="hidden" value="2" name="id"/>

      <div class="form-group has-error">
          <ul class="input-grp-2">
              <li><input name="first_name" type="text" ng-model="profile.first_name" placeholder="First name" /></li>
              <li><input name="last_name" type="text" ng-model="profile.last_name" placeholder="Last name" /></li>
          </ul>
      </div>
      <input name="phone" type="text" ng-model="profile.phone" placeholder="Phone number"/>

      <textarea name="information" rows="7">{{ profile.information }}</textarea>

      <a href="#" class="button btn-add-photo"><span class="glyphicon glyphicon-camera"></span> Add Photo</a>
      <input style="display: none" type="file" name="image" class="upload-photo" id="input_upload" accept="image/*"/>
  </form>
  <a href="" target="_self" class="button btn-green" ng-click="updateProfile(profile)">Submit Changes</a>

</div>

<script src="/js/app.js"></script>
<script src="/js/controllers/dashboard.js"></script>
<script src="/js/api.js"></script>
</body>
</html>

My the dashboard controller I use:

$scope.profile = null;

$scope.getOwnProfile = function () {
    $scope.$watch( 'profile', function() {
        setTimeout(function () {
            $scope.$apply(function () {
                $scope.profile = API.getOwnProfile();
            });
        }, 100);
    })
};

And the API service sets the profile as:

var APIService = {};

var ownProfile;

APIService.resetRenterProfile = function() {
    ownProfile = undefined;
};

APIService.getOwnProfile = function() {
    if (typeof ownProfile === 'undefined') {
        retrieveOwnProfile();
    }
    return ownProfile;
};

retrieveOwnProfile = function() {
    return Restangular.one('profile', null).get()  // GET: /profiles
        .then(function (profile) {
            ownProfile = profile;
        });
};

return APIService;

As I said, this works, but I'm having two problems.

1)Data is fetched and put into the right var in the right scope for every controller, but none of this $scope data is shown in the view until the user makes something that has some impact on the view, like clicking in a dropdown menu, in a tab, etc.

2) I have to specify a delay in miliseconds, and if by any reason, the API call to the backend takes more time than that delay, the $scope data is not shown until user manually interacts with the view.

Despites it work, I have the impression that I'm doing it in the wrong way, so I'd like if anyone can point me in on how to avoid or improve this kind of problems.

Thank you very much.

$scope.getOwnProfile = function () {
    $scope.profile = API.getOwnProfile();
};

retrieveOwnProfile = function() {
    ownProfile = $resource('profile').get();
};

Code above will work as u want... why? Go to debug in browser and see what happens when u execute: var result = $resource().get(); You can see that 'result' will not be usual object. And angularjs itself will update view as soon as 'result' updates.

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