⚠️ This lesson is retired and might contain outdated information.

AngularJS Architecture: Using $http to load JSON data

Lukas Ruebbelke
InstructorLukas Ruebbelke
Share this video with your friends

Social Share Links

Send Tweet
Published 10 years ago
Updated 2 years ago

Now let's learn how use the $http service to make requests to remote servers. In our case, we will load the data from JSON files and then make them available in our controllers. We will see a few techniques that I frequently use to make working with $http data a lot more convenient.

[00:01] In this lesson, we are going to learn how to use the http service to fetch remote data. The http service is a core AngularJS service that uses the browser's xml, http request object or JSONP to communicate with remote servers.

[00:20] In our case, we are going to use it to load a JSON file that has the categories collection that we've been working with, as well as load a separate JSON file for the bookmarks collection. We are also going to see a few tricks that I've picked up that makes working with the http service and a model a bit more convenient.

[00:45] If we hop into our categories model, the first thing that we need to do is inject the $http service. We can also get rid of the local categories collection. Now, one thing that I like to do when I am working with remote services is to create an endpoint map for the possible endpoints that I would need to call.

[01:12] In this case, it is just a single endpoint. I'm going to create a URLS object and create a property under called fetch that we're going to point towards data/categories.json. Then, we'll replace this return object with an actual call using the http service.

[01:40] The nice thing about the http service is that it has convenience methods baked into it that match restful verbs. In our case, we want to call get. This takes a single argument which is a configuration object that constructs the http call itself. We're just going to pass in the url like so.

[02:10] Let's hop into the controller. We are going to switch this up just a little bit. We're going to call getCategories immediately. Because this returns a promise, we are going to use then to handle that. After we've made the call and the result has come back, then we can do something. This would take one argument, a function that represents the success handler of this call and that takes one argument which is the result of that call.

[02:45] From here, we are going to say categoriesListCtrl.categories = result. There's going to be a problem with this. I will show you in just a moment. Let's go ahead and dump this result and see what it looks like in the browser.

[03:05] Let's refresh the page. You can see in the console that it's an object with data on that object that has the array that we actually want. From here, I can actually go back into my controller. I could say = result.data. This would work. Let's refresh the page.

[03:34] We have categories. The problem with this is that I prefer for my controllers not to know about the implementation details of how my data is being returned from the server. I like to use a trick to extract this data before I actually send it to the controller.

[03:59] What we will do here is create a method called extract that takes the result and it just returns result.data. I'm going to create another method here called cacheCategories, because as it stands now, we're not actually storing the result of categories. It's actually stateless, but I want to actually store a reference to the server result so I can use it a bit later.

[04:38] We will go categories = extract result, return categories. From here, instead of returning just the call itself, we can return a promise that has the result of cacheCategories. Let's refresh the page. You can see that it's still working, but we are now extracting out that data and then storing a reference to categories.

[05:19] Let's go ahead and do this real quick for the bookmarks. Let's inject $http. I'm going to delete the local collection here, create my endpoint map. We'll create the extract method, the cacheBookmarks method, $http.get and fetch, cacheBookmarks.

[05:53] We'll go into our bookmarksCtrl. We'll just shuffle this around a bit. There we go. Let's refresh the page. You can see now, we have categories and bookmarks coming in to our page as it was before but now, we're pulling it from the JSON files.

[07:08] In the next lesson, we will extend this idea by creating promises and manually resolving them, giving us even more control over how we handle the data when it comes back from the server. See you in the next lesson.

Rogier
Rogier
~ 10 years ago

What would the bookmarks-model look like if the bookmarks where a nested resource on the api server? Like when you'd get to a bookmark using a URL like: '/api/categories/design/bookmarks'

The URLS.FETCH property would then depend on the currently viewed category. Would it be something like this?:

model.getBookmarks = function(categoryName) {
    return $http.get('/api/categories/' + categoryName + '/bookmarks').then(cacheBookmarks);
};
Lukas Ruebbelke
Lukas Ruebbelkeinstructor
~ 10 years ago

Rogier, that is correct and why I love REST so much because you simply have to construct the proper endpoint. I would extract the logic behind generating the URL into a separate method but you are headed in the right direction.

Jonathan
Jonathan
~ 9 years ago

Out of curiosity, why did you capitalize the URLS object?

Lukas Ruebbelke
Lukas Ruebbelkeinstructor
~ 9 years ago

Good question. That is just a convention I use to imply it is a constant as endpoints generally do not change over the lifecycle of an application.

Jonathan
Jonathan
~ 9 years ago

I see. Many thanks. One more quick question. Why use $http.get(URLS.FETCH).then(...), instead of $http.get(URLS.FETCH).success(...)

Doesn't using .success save a few steps, as it returns the data directly and not the promise object? So no need for the extract and cache functions? Super confused here, ha.

Lukas Ruebbelke
Lukas Ruebbelkeinstructor
~ 9 years ago

Because we are dealing with an asynchronous operation, we definitely want to return a promise. This allows use to ensure uniformity in how we handle the response even though we are not sure when it will complete.

By returning a promise, we can also control what and how we respond to the controller that is requesting the operation i.e. caching, etc.

Jonathan
Jonathan
~ 9 years ago

Hey Lucas, thanks for entertaining my ignorance! Need to read up and get smarter on (i) how promises work and (ii) caching. Still quite confused.

Re caching, can you recommend any reading on how caching works / when to use it / how to use it in JS? I get the broad idea ('load something once instead of multiple times') but the implementation is a black box to me.

Re promises, strange that the angular documentation only covers using $http with .success and .error.

Matt
Matt
~ 9 years ago

So I'm trying to get my JSON data to load to the template and I did everything in this video. However, when I console.log(result) inside of the getCategories() function in categories.js, the result ends up being my entire index.html template??? Very bizarre and I'm not sure why it is reading the HTML rather than my json file. Help please!

Lukas Ruebbelke
Lukas Ruebbelkeinstructor
~ 9 years ago

Hi Matt -- are you using an HTTP server to serve up the web application? What endpoint are you hitting in your categories service? Can you trace it out in the network tab in the Chrome developer console?

Matt
Matt
~ 9 years ago

I'm tracing through my steps, console.logging everything...so this is what I've found.

On the extract(result) function, when I console.log(result), I can see that inside of the data property is my entire index.html for some reason, when it should be the array of objects from my JSON file. As excepted, logging result.data returns the index.html file.

I'm building my project out with the MEAN stack, so I am using an Express.js server. My endpoint is similar to what you have in the video:

URLS = {FETCH: '/data/categories.json'}

I added the '/' in the beginning to try and route it through the main directory. When I trace it through the network tab, I see that the Request URL is as follow:

Request URL:http://127.0.0.1:8080/data/categories.json

Lukas Ruebbelke
Lukas Ruebbelkeinstructor
~ 9 years ago

So just to clarify... you are hitting this URI http://127.0.0.1:8080/data/categories.json and getting the contents of index.html? If so, I am pretty certain that there is a problem with your Express middleware.

Matt
Matt
~ 9 years ago

Yea that's seems to be what is happening. Do you have any ideas as to what to look for?

Lukas Ruebbelke
Lukas Ruebbelkeinstructor
~ 9 years ago

You need to set up an Express route that is specific for http://127.0.0.1:8080/data/categories.json and return the categories.json file. You could even skip the JSON and just return the collection from within your Express app.

Nisarg
Nisarg
~ 8 years ago

why we are adding this extra method

        function cacheBookmarks(result) {
            bookmarks = extract(result);
            return bookmarks;
        }

isn't doing this is enough ?

        model.getBookmarks = function() {
            return $http.get(URLS.FETCH).then(extract);
        };

any reason to pipe that data to cacheBookmarks ?

Lukas Ruebbelke
Lukas Ruebbelkeinstructor
~ 8 years ago

Hi Jayendra -- I added that in to show how to implement caching as well as making your service stateful. There are cases where you may not want to store your results in the service and fetch a fresh copy every time but for performance reasons, it would make sense to not have to fetch a fresh copy every time. Especially if the data is fairly static.

Markdown supported.
Become a member to join the discussionEnroll Today