Faking Ajax calls: Reading Synchronously
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeThe categories
data is now available as a global variable: window.categories
.
In sidebar.vue
, we're calling fetchCategories()
, which lives in our fancy new categories-service
module. You can find this at assets/js/services/categories-service.js
.
To switch this from an Ajax call to the global variable, just return window.categories
. Celebrate by removing the axios
import on top.
/** | |
* @returns Array | |
*/ | |
export function fetchCategories() { | |
return window.categories; | |
} |
This is what I like about centralizing the fetchCategories()
method: we don't need to run around and change our code in a bunch of places: just here. Well... that's not quite true yet. One problem is that our function does not return a Promise
anymore! It now returns an array. That could affect code that uses this.
Whoops! We're Returning Different Data
But... let's ignore that for a moment! Move over and refresh. Bah! It's broken:
Cannot read property
hydra:member
of undefined
We did change the function from returning a Promise
to returning an array. But that's actually not what broke our code! The real problem is that, down in created()
, fetchCategories()
no longer gives us a response
object with a data
key!
Let's back up: it's actually ok to use await
on a non-async function: JavaScript just grabs the return value from the function and gives it to us: no error. The real problem is that the value that the previous code gave us was a response
object... but now we're returning an array of categories. This means that response.data
is undefined!
The simplest way to fix this is right here: comment out the old this.categories
line and directly say this.categories = fetchCategories()
. We don't need the await
anymore, but it doesn't hurt anything.
// ... lines 1 - 50 | |
<script> | |
// ... lines 52 - 54 | |
export default { | |
// ... lines 56 - 79 | |
async created() { | |
this.categories = await fetchCategories(); | |
//this.categories = response.data['hydra:member']; | |
}, | |
}; | |
</script> | |
// ... lines 87 - 105 |
Simple enough! Back on the browser, it's already showing the categories on the left. And if we reload... yes! The categories are instantly there! Woo! There is still a slight delay before the styles load, but that will only happen in dev mode: we did that to allow hot module replacement. So, mission accomplished!
Returning a Promise from the Sync Method
One of the cool things about isolating our Ajax calls into functions like fetchCategories()
is that, when we call that function, we don't need to know or care if it's talking to an API, or which API, or if we're just loading the data locally from local storage or a variable.
But... that's not really true right now. Because when we changed this from using the API to the global variable, we changed what this function returned! We changed it from returning a Promise
to an array and we also changed the actual data that's returned from a response
object with data
and hydra:member
properties to an array. This meant that, once this function was synchronous, we needed to update any code that called this.
And... that's fine. If you know that you're going to load categories synchronously via window.categories
, then you can just update your code to reflect that. It's not a huge problem.
But when we changed to the global variable, we could have also written our function in a way that did not break any code that used it: we could have returned a Promise
.
Let's try that: return new Promise()
. This needs one argument: a callback with resolve
and reject
. If you've never seen a Promise
like this, check out our ES6 tutorial all about them. They're fascinating.
// ... lines 1 - 3 | |
export function fetchCategories() { | |
return new Promise((resolve, reject) => { | |
// ... lines 6 - 10 | |
}); | |
} |
Anyways, once our work is done - which will be instantly since we don't need to make any Ajax calls, call resolve()
and pass it the data that we want the promise to return. Now, we're not really making an Ajax request... so we can't exactly return the same data as before because... we don't have a response. But we know that what we really care about is that this Promise returns a object with a data
key and a hydra:member
key below it. Let's at least fake that here: add data
set to an object and hydra:member
set to window.categories
. I'll remove the extra return at the bottom and, above the function, once again, advertise that we return a Promise
!
// ... lines 1 - 3 | |
export function fetchCategories() { | |
return new Promise((resolve, reject) => { | |
resolve({ | |
data: { | |
'hydra:member': window.categories, | |
}, | |
}); | |
}); | |
} |
Now, back in sidebar.vue
, we can revert all of our changes and use the exact code we had before: const response = await fetchCategories()
.
And... that's it! The Promise
is a little funny... because it will always resolve immediately. But that's fine! When it resolves, it will return data that's not exactly the same as an Axios response, but it's close.
Moment of truth! At our browser... it looks like it's working. Let's refresh. Yes! It definitely works. So this is a great way to get dynamic data from your server without needing an Ajax call when you really want something to be available almost instantly.
Next, let's use the categories data and currentCategoryId
to print the name of the category on each page. To do that, we'll need to make sure all of that data lives in the right component.
Hi there,
A good idea to get the best experience for our users is use this component:
https://vuetifyjs.com/en/co...
It shows us a previsualization of the design of our pages as we can see at FB or other social networks.
It's a good UX trick! :) Brs.