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 SubscribeOk team! We have the currentCategoryId
and we're using it on the sidebar to highlight which page we're on. That is awesome! But our products on the right aren't being filtered at all yet! Yikes!
Go to /api
to check out our API docs and scroll down to the GET /api/products
endpoint. I've already done a bit of work behind the scenes in API platform to allow us to fetch all the products for a specific category.
Here's how it works: we can enter a category's IRI into this box: so, /api/categories/
- and then 24 to get the Furniture category. When we hit Execute... yes! It only returned 5 items! And if I scroll up, you can see the URL that gave us this result: if you ignore the url-encoded parts, this is /api/products?category=/api/categories/24
.
All we need to do is make that same request from inside of Vue!
Head back to our app. From the top level products.vue
, hold Command or Ctrl and click <catalog />
to jump into that component. Catalog is responsible for loading our products on created
by making a request to /api/products
. Hmm... I wish we had access to the currentCategoryId
here... because we could use that to change the URL in the Ajax call! Well then... let's go get it!
Back in products.vue
, add :current-category-id="currentCategoryId"
to pass it as a prop... just like we did with the sidebar.
<template> | |
... lines 2 - 11 | |
<div :class="contentClass"> | |
<catalog :current-category-id="currentCategoryId" /> | |
</div> | |
... lines 15 - 16 | |
</template> | |
... lines 18 - 53 |
Now, in catalog.vue
, add that as a prop. Actually, let's go steal the prop definition from sidebar - it's perfect there - and paste it here.
... lines 1 - 18 | |
<script> | |
... lines 20 - 23 | |
export default { | |
... lines 25 - 29 | |
props: { | |
currentCategoryId: { | |
type: String, | |
default: null, | |
}, | |
}, | |
... lines 36 - 53 | |
}; | |
</script> |
Wonderful! We are now receiving currentCategoryId
. To use this, down in created
we could add ?category=
and then the currentCategoryId
. But with Axios, there's a better way. Create a new params
variable set to an object: this will hold all the query parameters that we want to send. Now, if (this.currentCategoryId) {
, then params.category = this.currentCategoryId
.
... lines 1 - 23 | |
export default { | |
... lines 25 - 41 | |
async created() { | |
const params = {}; | |
if (this.currentCategoryId) { | |
params.category = this.currentCategoryId; | |
} | |
... lines 47 - 52 | |
}, | |
}; | |
... lines 55 - 56 |
To pass that to axios, add a second parameter, which is an options object. One of the options you can pass is called params
. So: params: params,
.
... lines 1 - 41 | |
async created() { | |
... lines 43 - 47 | |
const response = await axios.get('/api/products', { | |
params: params, | |
}); | |
... lines 51 - 52 | |
}, | |
... lines 54 - 56 |
That should work... but yikes! ESLint is mad! It says:
expected property shorthand.
This is referring to something that we've actually already done many times, but I want to highlight it in case you haven't noticed. In JavaScript, if you are trying to add a property to an object... and that property's name is the same as the variable being used for its value, you can use a shorthand syntax: just params
. This sets a property named params
to the params
variable.
If we go over now, you can already see it! It reloaded! Yes! Furniture shows furniture! Breakroom shows breakroom products! Office supplies shows office supplies! And Snacks shows... uh... did this just break? Where are my snacks?
It turns out that our snacks category is currently empty! Gasp! If that's not bad enough, instead of saying - "No snacks! You're on your own!" - we see the loading screen forever.
That's... my fault. When catalog
renders product-list
- hold Command or Ctrl and click to jump to that - the loading is showing based on whether the products
length is zero or not. An empty category looks like it's still loading!
We need to improve this: we need to truly know whether or not the Ajax call has finished! Let's make a smarter loading mechanism next!
Hey David!
A mystery! Ok, so we know that going to https://127.0.0.1:8000/api/products?currentCategoryId=/api/categories/2 via the (1) API Platform interface works correctly but (2) going to this URL via axios is NOT working correctly. That IS, indeed, super strange. What could be different?
The only thing that immediately came to mind is that the API Platform interface is setting an Accept
header on the request - iirc it's application/ld+json
. However, I don't think that would make a difference in how the items are filtered... and I think API Platform (via axios) IS returning json ld anyways. So, I don't think this is it.
But something must be different. So here's what I would do:
A) You are already able to get a "curl" command version that DOES do the filtering correctly. Awesome!
B) After making the Ajax request via Axios (where the filtering is incorrect), in your network tools, you should be able to right click on that request and select "copy as curl".
Cool! So now you have 2 similar (but not identical) curl commands: one that works correctly and one that doesn't. Try tweaking each of these until you find what subtle difference is causing the bad behavior. I'd love to know what you find out.
Cheers!
OMFG. You won't -- no I think maybe you will! -- believe this. I was saying
params.currentCategoryId = this.currentCategoryId
and the attentive reader will see there's a wee little mistake there. The name of the parameter should be category. This is what I get for typing like a good person rather than copy-pasting (-: D'oh. So embarrassing, maybe we should delete this little thread.
Thanks for putting me on track to figuring it out!
Hello!
I love this course, great job as always.
I was just wondering if it was considered "best practice" to keep using props to pass an information we're collecting with a service.
The reason why I'm asking is because I was doing this part of the course on my own (for the challenge - and being really psyched about Vue! :p) and I stumbled upon that reflection: should I keep passing this piece of basic information (routing) through props from component to component or should I just call the service directly from the component I'm currently using that information?
My answer was to import the getCurrentCategoryId() method from the page-context service but I'm very interested in knowing your take on this.
Hey Thibaut,
That's a good question, and the answer is (as always) that it depends on your app. If the service method you need to call tends to change or has arguments that are not too easy to get, then it's better just to inject the value as a prop in your component. So, you need to evaluate what option will make your code more resilient to change
Cheers!
Hi!!
I am interested how should look axios get (what is sintax) if we use
https://api-platform.com/do...
How I can get all objects from db on curent date, or how I can get objects beetwen two dates
In my api platform everything is work, but I dont know how to send date (dates) via axios so I can filter result by date or range date.
Hey sasa1007
Have you tried sending your dates as a string? Then in your backend you can read the string and transform it back into a DateTime object
Cheers!
Thank you for your answer.
Uh, I'll try to explain.
I can get string from date object in my vue component and I can try to use it in axios, but I need to send somehow date (string) as parameter so I can get collections of object.
In my api documatacion when I put in entity this line of code
@ApiFilter(DateFilter::class, properties={"created"})
I get this
When i put 02-09-2020 in field created[strictly_after]
my curl is look like this
curl -X GET "http://localhost:8000/api/presences?created%5Bstrictly_after%5D=02-09-2020&page=1"
so my axios call will bi something like this
axios.get('http://localhost:8000/api/presences'.+'?created[strictly_after]'=02-09-2020' ) which I dont like it and I thing that this sintax 'created[strictly_after]' is not going to work, and I hope so that there is a better way to assign a value to the parameters from screenshot via axios.
Best regards
Hi Sasa, I think you are on the right path. Though I'm not an expert on axios, it seems you have to send that URL in order to get that filter!
// package.json
{
"devDependencies": {
"@symfony/webpack-encore": "^0.30.0", // 0.30.2
"axios": "^0.19.2", // 0.19.2
"bootstrap": "^4.4.1", // 4.5.0
"core-js": "^3.0.0", // 3.6.5
"eslint": "^6.7.2", // 6.8.0
"eslint-config-airbnb-base": "^14.0.0", // 14.1.0
"eslint-plugin-import": "^2.19.1", // 2.20.2
"eslint-plugin-vue": "^6.0.1", // 6.2.2
"regenerator-runtime": "^0.13.2", // 0.13.5
"sass": "^1.29.0", // 1.29.0
"sass-loader": "^8.0.0", // 8.0.2
"vue": "^2.6.11", // 2.6.11
"vue-loader": "^15.9.1", // 15.9.2
"vue-template-compiler": "^2.6.11", // 2.6.11
"webpack-notifier": "^1.6.0" // 1.8.0
}
}
I hate to be a whiner, but I am stuck with a weird problem I can't figure out. My products are not being filtered. I keep getting 12 items of different categories.
For example: When I hit the url https://127.0.0.1:8000/api/products?currentCategoryId=/api/categories/2 using the Platform API interface or curl, the data comes back as it should: five items of office furniture (the id of the Office Furniture category in my world being 2 rather than 24). When I click Furniture in the sidebar category, however, I get the 12 unfiltered items.
Doing my Troubleshooting 101, I ask, OK, is currentCategoryId set correctly by Javascript when the page is rendered, or is it null? It is correct. Are the right params being passed in the axios call? Yes. What is the URL we are hitting with this axios call? It is indeed https://127.0.0.1:8000/api/products?currentCategoryId=/api/categories/2 according to the Firefox console. And what data is in the response? The 12 unfiltered items. And that is what is being assigned to this.products in my created() method.
Any ideas?