我如何使用AngularJS承诺确保获取的数据更新范围?

时间:2015-03-04 05:07:56

标签: angularjs promise

我正在努力将一些JSON请求从控制器中分离出来并转换为角度的工厂服务,并使其正常工作。目前,当我更新数据时(与新数据的请求一样),我必须提出两次请求以实际查看更新的数据。我认为,从我目前对Angular的有限知识来看,我错过了承诺方面。但是,我不确定如何最好地继续下去。代码如下:

(function(angular) {
  'use strict';

  var myApp = angular.module('weatherApp', [])
    
    .controller('MyWeatherController', ['$scope', '$http', '$log', 'weather', function($scope, $http, $log, weather) {
      $scope.city = 'Cincinnati';
      $scope.units = 'imperial';

      $scope.updateData = function() {
        weather.updateData($scope, $http, $log);
      };

      // Initial run to fetch weather data
      $scope.updateData();
    }])


    // Set up a service factory to fetch current and forecast data
    .factory('weather', ['$http', function($http) {
      var services = {};

      services.updateData = function(scope, http, log) {
        this.updateCurrent(scope, http, log);
      }

      // Get current data
      services.updateCurrent = function(scope, http, log) {
        // Fetch current weather data from api
        var url = 'http://api.openweathermap.org/data/2.5/weather';

        http.jsonp(url, {params: {
          q: scope.city,
          units: scope.units,
          callback: 'JSON_CALLBACK'
        }})
        .success(function(data, status, headers, config) {
          scope.main = data.main;
          scope.wind = data.wind;
          scope.description = data.weather[0].description;
        })
        .error(function(data, status, headers, config) {
          log.error('Could not retrieve data from '+url);
        });
      };

      return services;
    }]);

} (window.angular));
body {
  width: 50%;
  margin: 2em auto;
}    

h2 {
  background: green;
  color: white;
  padding: 10px;
  margin-bottom: 0;
}

input {
  margin-bottom: 1em;
}

.section {
  margin-bottom: 2em;
  background: #f0f0f0;
  padding: 10px;
}
<!DOCTYPE html>
<html>
  <head>
    <title>Weather checker</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.11/angular.min.js"></script>
    <script src="script.js"></script>

    <link type="text/css" rel="stylesheet" href="style.css" media="all" />
  </head>
  <body>
    <div class="container" ng-app="weatherApp">
      <div ng-controller="MyWeatherController">

        <h2>Current weather in {{city}}</h2>
        <div class="section current">
          <form name="weather-form">
            <label for="city">City, State / Zip code</label>
            <input 
              type="text" 
              ng-model="city" 
              ng-model-options="{updateOn: 'submit'}">
            <br>
            <label for="units">Units</label>
            <input type="radio" ng-model="units" value="metric"> Metric
            <input type="radio" ng-model="units" value="imperial"> Imperial<br>
            <button ng-click="updateData()">Update</button>
            <h3>{{data.name}}</h3>
            <p>{{description}}</p>
            <p>Temperature: {{main.temp}}</p>
            <p>Wind speed: {{wind.speed}}</p>
          </form>
        </div>
      </div>
    </div>
  </body>
</html>

如您所知,如果您运行此操作,则必须更新两次以获取要在视图中显示的新数据。对于某些示例的任何建议或对后续步骤的反馈将不胜感激!

由于

5 个答案:

答案 0 :(得分:1)

这是承诺的实施。

你的承诺代码看起来像这样,你不应该像$ scope,$ http,$ log这样的变量传递给服务,它们将通过注入依赖项在服务中轻松获得。

scope变量不应该使用服务进行修改,您应该从服务返回一个承诺,并且在promise成功或错误内部,您可以修改范围。

从服务我返回已经有承诺的$http.jsonp,所以你不需要关心返回promise,并且这个promise在.success函数内得到解决,你可以在{{1}内获得拒绝承诺功能

<强> CODE

.error

Fiddle

希望这对你有所帮助,谢谢。

答案 1 :(得分:1)

这是因为ng-model-options指令。

在我们提交表单之前,模型中的城市值不会更新。

因此,在更改城市后,当我们第一次点击时,将为旧城市提取值,这不会反映用户界面中的任何更改。由于这是提交操作,因此将更新模型。

当我们第二次点击时,会使用新的城市值获取值。

答案 2 :(得分:0)

(function(angular) {
  'use strict';

  var myApp = angular.module('weatherApp', [])
    
    .controller('MyWeatherController', ['$scope', '$http', '$log', 'weather', function($scope, $http, $log, weather) {
      $scope.city = 'Cincinnati';
      $scope.units = 'imperial';

      $scope.updateData = function() {
        weather.updateData($scope, $http, $log);
      };

      // Initial run to fetch weather data
      $scope.updateData();
    }])


    // Set up a service factory to fetch current and forecast data
    .factory('weather', ['$http', function($http) {
      var services = {};

      services.updateData = function(scope, http, log) {
        this.updateCurrent(scope, http, log);
      }

      // Get current data
      services.updateCurrent = function(scope, http, log) {
        // Fetch current weather data from api
        var url = 'http://api.openweathermap.org/data/2.5/weather';

        http.jsonp(url, {params: {
          q: scope.city,
          units: scope.units,
          callback: 'JSON_CALLBACK'
        }})
        .success(function(data, status, headers, config) {
          scope.main = data.main;
          scope.wind = data.wind;
          scope.description = data.weather[0].description;
          $scope.digest();
        })
        .error(function(data, status, headers, config) {
          log.error('Could not retrieve data from '+url);
        });
      };

      return services;
    }]);

} (window.angular));
body {
  width: 50%;
  margin: 2em auto;
}    

h2 {
  background: green;
  color: white;
  padding: 10px;
  margin-bottom: 0;
}

input {
  margin-bottom: 1em;
}

.section {
  margin-bottom: 2em;
  background: #f0f0f0;
  padding: 10px;
}
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" version="XHTML+RDFa 1.0">
  <head>
    <title>Weather checker</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.11/angular.min.js"></script>
    <script src="script.js"></script>

    <link type="text/css" rel="stylesheet" href="style.css" media="all" />
  </head>
  <body>
    <div class="container" ng-app="weatherApp">
      <div ng-controller="MyWeatherController">

        <h2>Current weather in {{city}}</h2>
        <div class="section current">
          <form name="weather-form">
            <label for="city">City, State / Zip code</label>
            <input 
              type="text" 
              ng-model="city" 
              ng-model-options="{updateOn: 'submit'}">
            <br>
            <label for="units">Units</label>
            <input type="radio" ng-model="units" value="metric"> Metric
            <input type="radio" ng-model="units" value="imperial"> Imperial<br>
            <button ng-click="updateData()">Update</button>
            <h3>{{data.name}}</h3>
            <p>{{description}}</p>
            <p>Temperature: {{main.temp}}</p>
            <p>Wind speed: {{wind.speed}}</p>
          </form>
        </div>
      </div>
    </div>
  </body>
</html>

答案 3 :(得分:0)

你有两种方式(好吧,可能还有更多)你可以去这里。 您可以创建一个promise并返回从promise中的http调用返回的数据,以便在控制器中解析。查看$ q here文档的第二个代码块,了解如何执行此操作。

但是,我建议您在服务中创建一个公共属性来保存数据。然后,您可以从控制器访问它。由于Angular的数据绑定,当服务器响应最终返回并且数据存储在服务中时,控制器将自动地&#34;参见&#34;更新后的价值。

&#13;
&#13;
(function(angular) {
  'use strict';

  var myApp = angular.module('weatherApp', [])
    
    .controller('MyWeatherController', ['$scope', '$http', '$log', 'weather', function($scope, $http, $log, weather) {
      //here you expose the service to your scope.  From here you can
      //get at all your data in the view by using weather.result
      $scope.weather = weather;
      
      $scope.city = 'Cincinnati';
      $scope.units = 'imperial';

      $scope.updateData = function() {
        weather.updateData($scope, $http, $log);
      };

      // Initial run to fetch weather data
      $scope.updateData();
    }])


    // Set up a service factory to fetch current and forecast data
    .factory('weather', ['$http', function($http) {
      var services = {};
      
      //make the server response data part of the service's public API
      services.details = {
          someDetail: "",
          someOtherThing: []
      }

      services.updateData = function(scope, http, log) {
        this.updateCurrent(scope, http, log);
      }

      // Get current data
      services.updateCurrent = function(scope, http, log) {
        // Fetch current weather data from api
        var url = 'http://api.openweathermap.org/data/2.5/weather';

        http.jsonp(url, {params: {
          q: scope.city,
          units: scope.units,
          callback: 'JSON_CALLBACK'
        }})
        .success(function(data, status, headers, config) {
          //here we assign the data to the service's result property.
          services.details.someDetail = data.someDetail;
          services.details.someOtherThing = data.someOtherThing;
        })
        .error(function(data, status, headers, config) {
          log.error('Could not retrieve data from '+url);
        });
      };

      return services;
    }]);

} (window.angular));
&#13;
<p>Some detail:{{weather.details.someDetail}}</p>
<p>Some other thing: {{weather.details.someOTherThing}}</p>
&#13;
&#13;
&#13;

答案 4 :(得分:0)

我从你的html中删除了ng-model-options="{updateOn: 'submit'}并且它运行良好:)

(function(angular) {
  'use strict';

  var myApp = angular.module('weatherApp', [])
    
    .controller('MyWeatherController', ['$scope', '$http', '$log', 'weather', function($scope, $http, $log, weather) {
      $scope.city = 'Cincinnati';
      $scope.units = 'imperial';

      $scope.updateData = function() {
        weather.updateData($scope, $http, $log);
      };

      // Initial run to fetch weather data
      $scope.updateData();
    }])


    // Set up a service factory to fetch current and forecast data
    .factory('weather', ['$http', function($http) {
      var services = {};

      services.updateData = function(scope, http, log) {
        this.updateCurrent(scope, http, log);
      }

      // Get current data
      services.updateCurrent = function(scope, http, log) {
        // Fetch current weather data from api
        var url = 'http://api.openweathermap.org/data/2.5/weather';

        http.jsonp(url, {params: {
          q: scope.city,
          units: scope.units,
          callback: 'JSON_CALLBACK'
        }})
        .success(function(data, status, headers, config) {
          scope.main = data.main;
          scope.wind = data.wind;
          scope.description = data.weather[0].description;
        })
        .error(function(data, status, headers, config) {
          log.error('Could not retrieve data from '+url);
        });
      };

      return services;
    }]);

} (window.angular));
body {
  width: 50%;
  margin: 2em auto;
}    

h2 {
  background: green;
  color: white;
  padding: 10px;
  margin-bottom: 0;
}

input {
  margin-bottom: 1em;
}

.section {
  margin-bottom: 2em;
  background: #f0f0f0;
  padding: 10px;
}
<!DOCTYPE html>
<html>
  <head>
    <title>Weather checker</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.11/angular.min.js"></script>
    <script src="script.js"></script>

    <link type="text/css" rel="stylesheet" href="style.css" media="all" />
  </head>
  <body>
    <div class="container" ng-app="weatherApp">
      <div ng-controller="MyWeatherController">

        <h2>Current weather in {{city}}</h2>
        <div class="section current">
          <form name="weather-form">
            <label for="city">City, State / Zip code</label>
            <input 
              type="text" 
              ng-model="city">
            <br>
            <label for="units">Units</label>
            <input type="radio" ng-model="units" value="metric"> Metric
            <input type="radio" ng-model="units" value="imperial"> Imperial<br>
            <button ng-click="updateData()">Update</button>
            <h3>{{data.name}}</h3>
            <p>{{description}}</p>
            <p>Temperature: {{main.temp}}</p>
            <p>Wind speed: {{wind.speed}}</p>
          </form>
        </div>
      </div>
    </div>
  </body>
</html>