TCorner is a serialized blog post from our newest Labs member, Taylor Cornelius.  TCorn comes from a design background and these are his adventures on the development side of the fence.

A few months ago I was taking a Udemy course on Angular JS v.1. Near the end of the course came an assignment to create a single page weather forecast app. The assignment was to use many of the angular concepts demonstrated in the course as well as utilize an API to openweathermap.org to receive data based on a user’s input. The project result would be an input field for a user to enter a city and the API would return weather forecasts by number of days.

I first began by declaring my app with ng-app and gave it a name of weatherApp. I set the ng-app inside the html tag because I knew I would only have one module for my project and everything inside it would be relevant to weatherApp.

Part of the assignment was to use ngRoute as a directive so that the app could give the illusion it was multiple pages while not having to actually load new files only new views. For this I had to include a path ngRoute in a script tag within the head of my index.html file. The source path can be found on Angular’s website along with all of the other built in directives.

The weather app file setup structure was thus:

  1. A main index.html file to set up a top nav bar and an include for ng-view.
  2. A home.html file which would include an input field to search weather forecast by city.
  3. A forecast.html file which would show once a user searched by a city. In this file would include navigation back to home.html, filter options to show multiple days of weather forecast and set up an ng-repeat div block to repeat the forecasts returned from the API call.
  4. A weatherPanel.html file which included specific API information to include within each forecast.
  5. An app.js file to include all of my services, custom directives, routes, controllers and API call. A single file for all of these is not recommended but sufficed for a beginner project.

My first step was to establish my route destinations. I included “ngRoute” as a dependency in my weatherApp module, then added a config function which included $routeProvider as the only parameter. $routeProvider sets up route paths, which files or views they should point to and any controllers associated with those views.

You can see that $routeProvider works in that when a relative path ends in ‘/’, the templateUrl loads the home.html file and specifies which controller is tied to the view. However that is half of the battle because now I need to specify those route paths within my html file links.

So now each href, when clicked will load in the correct html view file and it’s associated controller.

Next I set up my two controllers. Each has a specific name to it’s function. Each loads in some of Angular’s built in services such as $scope, $http for API calls and my own custom service ‘forecastService’ which I will discuss later. I did not need to reference the controllers in my html views because ngRoute handled that when I specified controller in the .when statements. I did need to include the ng-view directive inside my index.html file. The ng-view empty div container will hold all of the routing information that is loaded into the page. I put the ng-view container just before my closing tag.

The ‘forecastController’ also loads in $routeParams which references the final .when statement in my $routeProvider block. :days is like a variable declaration in that last statement and by injecting $routeParams into the ‘forecastController’ I can set my scope equal to $routeParams.days. So now if I changed the url path to be /forecast/3, the forecast will return 3 days worth of weather. This is also dependent on the API call.

Inside of ‘forecastController’ I declare this line setting the scope equal to $routeParams.days but will default to two. Then if I select a different day, the $routeParams is updated as well as my relative path ‘/forecast/:days’.

In my forecast.html file I have this statement for filtering results by number of days.

Along with changing the route path when each link is clicked, I’ve added a bootstrap class whenever days === ‘#’. This will visually call out to the user which filter they have selected.

This next block of code will repeat for how ever many days are selected because of how the API call is constructed.

I set up the API call within the forecastController. It returns data from openweathermap.org and I access certain things from the data it returns.

You will notice that in $scope.url there is forecastService.city. This comes from a custom service I made. The service sets up a default city of Atlanta, which is where I live.

Inside the homeController I have a $scope.$watch function that looks for changes in the city input field. When the city changes forecastService.city updates to the new city.

The last thing I made was a custom directive so that the data I return from the API can be inserted into the weatherPanel view and become updated by that view.

I have the directive to restrict to Element name. I have it pointing to my weatherPanel view and have added an isolate scope.

Inside my forecast.html view I have added the custom directive tag which also includes custom attributes. Weather-object references the data object returned from the API. Convert-to-standard references a function that converts the Kelvin temperature returned from the API into fahrenheit. Convert-to-date references a function that returns a new date. Date-format references a format string.

Inside the weatherPanel.html view I have added the expressions inside {{ }} so that each weather forecast will display the correct date, the temperature and the weather description as returned by the API call.

As an added bonus for the project I found a library of weather icons. The library is in the form of an object with each key representing a unique id that matches an id returned from the openweather API. I added a link to the library inside my index.html file. I included the weather icons inside my custom service, as an object in forecastService.

Inside my API call I created a loop to loop through the data returned and push the icon ids to an empty array.

Next, I created a nested loop. The outer loop cycles through $scope.iconFromData. The inner loop cycles through the key value pairs in the weatherIcons object. I then have an if statement that checks whether the key in the weatherIcons object equals a value in the $scope.iconFromData array. If it does equal I set a new property on the data returned from the API and set it equal to the value of the key in weatherIcons.

Finally, I needed to update the attribute inside my custom directive html tag within the forecast.html view. Since the custom element is within an ng-repeat div block I set the expression inside the {{ }} to forecast.className.

Leave a Reply