var app = angular.module('weatherApp', []);

app.controller('weatherCtrl', ['$scope', 'weatherService', function($scope, weatherService) {
  function fetchWeather(zip) {
    weatherService.getWeather(zip).then(function(data){
      $scope.place = data;
    }); 
  }
  
  fetchWeather('84105');
  
  $scope.findWeather = function(zip) {
    $scope.place = '';
    fetchWeather(zip);
  };
}]);

app.factory('weatherService', ['$http', '$q', function ($http, $q){
  function getWeather (zip) {
    var deferred = $q.defer();
    $http.get('https://query.yahooapis.com/v1/public/yql?q=SELECT%20*%20FROM%20weather.forecast%20WHERE%20location%3D%22' + zip + '%22&format=json&diagnostics=true&callback=')
      .success(function(data){
        deferred.resolve(data.query.results.channel);
      })
      .error(function(err){
        console.log('Error retrieving markets');
        deferred.reject(err);
      });
    return deferred.promise;
  }
  
  return {
    getWeather: getWeather
  };
}]);
<!DOCTYPE html>
<html ng-app="weatherApp">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <link data-require="bootstrap-css@3.1.1" data-semver="3.1.1" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" />
    <link data-require="jasmine@*" data-semver="2.0.0" rel="stylesheet" href="//cdn.jsdelivr.net/jasmine/2.0.0/jasmine.css" />
    <script data-require="jasmine@*" data-semver="2.0.0" src="//cdn.jsdelivr.net/jasmine/2.0.0/jasmine.js"></script>
    <script data-require="jasmine@*" data-semver="2.0.0" src="//cdn.jsdelivr.net/jasmine/2.0.0/jasmine-html.js"></script>
    <script data-require="jasmine@*" data-semver="2.0.0" src="//cdn.jsdelivr.net/jasmine/2.0.0/boot.js"></script>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="angular.js" data-semver="1.2.16" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script>
    <script data-require="angular-mocks" data-semver="1.2.16" src="https://code.angularjs.org/1.2.16/angular-mocks.js"></script>
    <script data-require="bootstrap@*" data-semver="3.1.1" src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
    <script src="app.js"></script>
    <script src="appSpec.js"></script>
    <script src="jasmineBootstrap.js"></script>
  </head>

  <body ng-controller="weatherCtrl">
    <form>
      <div class="form-group">
        <input class="form-control" type="number" ng-model="zip" placeholder="e.g. 84105" />
        <input class="btn btn-default" type="submit" value="Search" ng-click="findWeather(zip)" />
      </div>
    </form>
    <p ng-show="zip">Searching the forecasts for: {{zip}}</p>
    <div>
      <h1>Forecast For {{ place.location.city }}</h1>
      <a ng-click="findWeather('84106'); zip = ''">reset</a>
      <h3>
        <img class="img-thumbnail forecast-img" src="http://l.yimg.com/a/i/us/we/52/{{place.item.condition.code}}.gif" />
Current: {{ place.item.condition.text }} | {{ place.item.condition.temp }}°</h3>
      <div class="row">
        <div class="col-xs-6" ng-repeat="forecast in place.item.forecast">
          <div class="panel panel-primary">
            <div class="panel-heading">
              <h4>
                <img class="img-thumbnail forecast-img" src="http://l.yimg.com/a/i/us/we/52/{{forecast.code}}.gif" />
                <strong>{{ forecast.date }}</strong>
              </h4>
            </div>
            <div class="panel-body">
              <p>{{ forecast.text }}</p>
              <p>H: {{ forecast.high }}° | L: {{ forecast.low }}°</p>
            </div>
          </div>
        </div>
      </div>
    </div>
  </body>

</html>
/* Put your css in here */
body {
  padding: 10px;
}

a {
  cursor: pointer;
}

.form-control {
  float: left;
  margin-right: 10px;
  width: 70%;
}

.forecast-img {
  margin-right: 10px;
  width: 45px;
}
A small weather app using AngularJS $http requests. 
===================================================

See blog post at http://austinknight.net/weather-app-with-angular-js/

Austin Knight // [@austinknight](http://twiter.com/austinknight) // http://austinknight.net
(function() {
  var jasmineEnv = jasmine.getEnv();
  jasmineEnv.updateInterval = 250;

  /**
   Create the `HTMLReporter`, which Jasmine calls to provide results of each spec and each suite. The Reporter is responsible for presenting results to the user.
   */
  var htmlReporter = new jasmine.HtmlReporter();
  jasmineEnv.addReporter(htmlReporter);

  /**
   Delegate filtering of specs to the reporter. Allows for clicking on single suites or specs in the results to only run a subset of the suite.
   */
  jasmineEnv.specFilter = function(spec) {
    return htmlReporter.specFilter(spec);
  };

  /**
   Run all of the tests when the page finishes loading - and make sure to run any previous `onload` handler

   ### Test Results

   Scroll down to see the results of all of these specs.
   */
  var currentWindowOnload = window.onload;
  window.onload = function() {
    if (currentWindowOnload) {
      currentWindowOnload();
    }

    //document.querySelector('.version').innerHTML = jasmineEnv.versionString();
    execJasmine();
  };

  function execJasmine() {
    jasmineEnv.execute();
  }
})();
describe('Controller: weatherCtrl', function() {
  var $scope, ctrl, $httpBackend, weatherService;
  
  //This is not the complete data we get, it's just a fake object
  var weatherObject = {
    "query":{
      "results":{
        "channel":{
          "location":{
            "city":"Salt Lake City",
            "country":"US",
            "region":"UT"
          }
        }
      }
    }
  };
  
  var resolvedData = {
    "location":{
      "city":"Salt Lake City",
      "country":"US",
      "region":"UT"
    }
  };
  
  var zip = 84105;
  
  beforeEach(module('weatherApp'));

  beforeEach(inject(function($rootScope, $controller, $httpBackend, weatherService) {
    $scope = $rootScope.$new();
    $httpBackend = $httpBackend;
    weatherService = weatherService;
    
    $httpBackend.when("GET", 'https://query.yahooapis.com/v1/public/yql?q=SELECT%20*%20FROM%20weather.forecast%20WHERE%20location%3D%22' + zip + '%22&format=json&diagnostics=true&callback=').respond(weatherObject);
    $httpBackend.when("GET", 'https://query.yahooapis.com/v1/public/yql?q=SELECT%20*%20FROM%20weather.forecast%20WHERE%20location%3D%2284060%22&format=json&diagnostics=true&callback=').respond(weatherObject);
    
    ctrl = $controller('weatherCtrl', {
      $scope: $scope,
      weatherService: weatherService
    });
    $httpBackend.flush();
  }));
  
  afterEach(inject(function($httpBackend){
    $httpBackend = $httpBackend;
    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();
  }));
  
  describe('using', function(){
    it('should get some weather data for the default zip code 84106', function() {
      $scope.$digest();
      expect($scope.place).toEqual(resolvedData);
    });
  
    it('should get some weather data for any given valid zip code', function() {
      $scope.$digest();
      $scope.findWeather('84060');
      expect($scope.place).toEqual(resolvedData);
    });
  });
});