How do I render my results using graphql in Vuejs - graphql

I am learning graphql and using strapi as a backend nuxt as a front end
I have set up the backend and am now trying to display the results
I have the following code, it is returning the results but I cannot for the life of me figure out how to display just the name field, can you assist
<template>
<div>
<!-- Events are displayed here -->
<div
v-for='organisation in organisations'
:key='organisation.id'
>
test {{ organisation }}
</div>
</div>
</template>
<script>
import gql from "graphql-tag";
export default {
data() {
return {
};
},
apollo: {
organisations: gql`
query organisations {
organisations {
data {
attributes {
name
}
id
}
}
}`
}
};
</script>
returns
test [ { "attributes": { "name": "Organisation 1", "__typename": "Organisation" }, "id": "1", "__typename": "OrganisationEntity" }, { "attributes": { "name": "test2", "__typename": "Organisation" }, "id": "2", "__typename": "OrganisationEntity" } ]
test OrganisationEntityResponseCollection
if i try {{ organisation.name }} it returns no error but nothing displayed, if I try {{ organisation.attributes.name }} i get an error
Thanks

Ah, I should have had
v-for='organisation in organisations.data'
in my v-for, now working

Related

Apollo is not letting me edit an object field because it is readonly, but I cannot just make a copy of it

I am not sure how I should set cart.items to a new array, I have already made a copy of the original cache because I learned Apollo does not let you directly edit the cache, but I am still getting the following error
Error: Cannot assign to read only property 'items' of object '#'
Do I need to make a copy of the items array? And if so how do I go about changing the array on the current objects item field?
Here are my console.logs
You can ignore the typename fields as they are irrelevant to the problem
addItem
{
"__typename": "Cart",
"items": [
{
"__typename": "CartItem",
"name": "Item 3"
},
{
"__typename": "CartItem",
"name": "Item 4"
},
{
"__typename": "CartItem",
"name": "New Item!"
}
]
}
carts
{
"carts": [
{
"__typename": "Cart",
"id": "1",
"items": [
{
"__typename": "CartItem",
"id": "1",
"name": "Item 1"
},
{
"__typename": "CartItem",
"id": "2",
"name": "Item 2"
}
]
},
{
"__typename": "Cart",
"id": "2",
"items": [
{
"__typename": "CartItem",
"id": "3",
"name": "Item 3"
},
{
"__typename": "CartItem",
"id": "4",
"name": "Item 4"
}
]
}
]
}
So it seems you need to remake the items array as well since items is its own gql object type the easiest way to do this was to do it all at once with a map.
Please note the comment as that was an important detail I learned
// IMPORTANT NOTE when updating the cache of a query you must return the
// same fields as the original query even if you aren't using them in the code
const GET_CARTS = gql`
query {
carts{
id
items{
id
name
}}} `;
const MUTATION = gql`
mutation AddItem($input:MutationAddItemInput!) {
addItem(input: $input){
items{
id
name
}
}
}
`;
const { loading, error, data } = useQuery(GET_CARTS)
const [addItem] = useMutation(MUTATION, {
// refetchQueries: [{ query: GET_CARTS }]
update(cache, { data: { addItem } }) {
// addItem is the response of the query of add item function
console.log({ addItem });
// #ts-ignore
let { carts } = cache.readQuery({ query: GET_CARTS });
console.log({ carts })
// make a new array out of the carts array and add the new item to the array if the id of the cart is 2
let newCarts = carts.map((cart: Cart) => {
if (cart.id === "2") {
return { ...cart, items: [...addItem.items] }
} else {
return cart
}
})
console.log({ newCarts });
cache.writeQuery({
query: GET_CARTS,
data: { carts: newCarts }
// data: { carts: [{ id: "1", items: [{ id: "2", name: "an item" }] }] }
})
}
})
And lastly you will call the addItem function from the use mutation hook

Shentao/VueMultiselect is not accepting api json response in :option="" vue3 composition api

Template
the category is API JSON Response asenter image description here
[{ "id": 1, "name": "sadi" }, { "id": 2, "name":"kurtha" }, { "id": 3, "name": "shirt" }]
it throw error by Uncaught (in promise) TypeError: this.options.concat is not a function
Error Image
<div v-if="category">
{{ category }}
<VueMultiselect
class="text-dark"
track-by="name" label="name"
v-model="form.category"
:options="category"
:loading="true">
</VueMultiselect>
</div>
But if I store the same response in the array manually it works,
Template
<div v-if="category">
{{ category }}
<VueMultiselect
class="text-dark"
track-by="name" label="name"
v-model="form.category"
:options="api"
:loading="true">
</VueMultiselect>
</div>
Script
const api = [
{ "id": "1", "name": "sadi" },
{ "id": "2", "name": "kurtha" },
{ "id": "3", "name": "shirt" }
];
Error when I put category API response
Working Image but manuall

Vue3 apollo displaying query results using composition API

So I am using vue router and trying to display the graphql results on my page.
Here is the router link on index.js
{
path: '/clients/:id',
name: 'client_profile',
component: () => import('../views/client_profile.vue')
},
The link to the page is from a table with this code using the router-link, where an id is passed as a param:
<router-link :to="{ name:'client_profile', params: { id: data.id }}"> {{data.name}}
</router-link>
The dynamic link looks like this on the setup(), where the useQuery loads my query clientEntity:
setup(){
const route = useRoute(),
id = computed(() => route.params.id)
const { result } = useQuery(clientEntity,{
id: id.value,
})
const client = computed(() => result.value?.entities[0])
return{
client,
result
}
}
On the HTML if I put in {{client}} or {{result}} I get the following:
//results
{ "entities": [ { "address": "555 Fake Street", "name": "Test1", "notes": "", "phone": null } ] }
//client
{ "address": "555 Fake Street", "name": "Test1", "notes": "", "phone": null }
But if I try accessing some of the data like {{client.address}} or {{client.name}} the page turns blank and I get the following error:
[Vue warn]: Unhandled error during execution of render function
at <BaseTransition appear=false persisted=false mode=undefined ... >
at <Transition name="p-toggleable-content" >
at <Panel header="Description" toggleable=true style=
Object { "text-align": "left" }
>
at <ClientProfile onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > >
at <RouterView>
at <App>
at <App>

Can't display images sourced from GraphQL, error [gatsby-plugin-image] missing image prop

I'm trying to source content with images from Contentful into Gatsby but I failed to get images displayed.
I installed gatsby-transformer-sharp, gatsby-plugin-image, gatsby-plugin-sharp, gatsby-remark-images and gatsby-remark-images-contentful.
down below is a simple of my code
import { GatsbyImage, getImage } from "gatsby-plugin-image"
const Projects = ({ data }) => {
const projects = data.projects.nodes
return (
<Layout>
<Seo
title={"Projects"}
description={"Projects & Websites I've Developed"}
/>
<div className={styles.portfolio}>
<h1>My Portfolio</h1>
<h2>Projects & Websites I've Developed</h2>
<div className={styles.projects}>
{projects.map(project => (
<Link
to={"/projects/" + project.slug}
key={project.id}
className={styles.project}
>
<GatsbyImage
image={getImage(project.thumb)}
alt={project.title}
/>
<div className={styles.cardText}>
<h3>{project.title}</h3>
<p>{project.stack}</p>
</div>
</Link>
))}
</div>
</div>
</Layout>
)
}
export default Projects
export const query = graphql`
query ProjectsPage {
projects: allContentfulProjects(sort: { fields: date, order: DESC }) {
nodes {
key
slug
stack
title
thumb {
gatsbyImageData(placeholder: BLURRED, layout: FULL_WIDTH)
}
id
}
}
}
`
here what i got from GraphQL
{
"data": {
"projects": {
"nodes": [
{
"key": "project",
"slug": "portfolio-website",
"stack": "html - css - javascript",
"title": "Portfolio Website",
"thumb": [
{
"gatsbyImageData": {
"images": {
"sources": [
{
"srcSet": "https://images.ctfassets.net/kj59ethbquzj/1qDaw8RjPxxhzjOehxHz1g/152307656408e0efcf7c907a59cd91a7/personal-portfolio-website.png?w=750&h=361&q=50&fm=webp 750w,\nhttps://images.ctfassets.net/kj59ethbquzj/1qDaw8RjPxxhzjOehxHz1g/152307656408e0efcf7c907a59cd91a7/personal-portfolio-website.png?w=1080&h=520&q=50&fm=webp 1080w,\nhttps://images.ctfassets.net/kj59ethbquzj/1qDaw8RjPxxhzjOehxHz1g/152307656408e0efcf7c907a59cd91a7/personal-portfolio-website.png?w=1366&h=658&q=50&fm=webp 1366w,\nhttps://images.ctfassets.net/kj59ethbquzj/1qDaw8RjPxxhzjOehxHz1g/152307656408e0efcf7c907a59cd91a7/personal-portfolio-website.png?w=1920&h=925&q=50&fm=webp 1920w",
"sizes": "100vw",
"type": "image/webp"
}
],
"fallback": {
"src": "https://images.ctfassets.net/kj59ethbquzj/1qDaw8RjPxxhzjOehxHz1g/152307656408e0efcf7c907a59cd91a7/personal-portfolio-website.png?w=1920&h=925&q=50&fm=png",
"srcSet": "https://images.ctfassets.net/kj59ethbquzj/1qDaw8RjPxxhzjOehxHz1g/152307656408e0efcf7c907a59cd91a7/personal-portfolio-website.png?w=750&h=361&q=50&fm=png 750w,\nhttps://images.ctfassets.net/kj59ethbquzj/1qDaw8RjPxxhzjOehxHz1g/152307656408e0efcf7c907a59cd91a7/personal-portfolio-website.png?w=1080&h=520&q=50&fm=png 1080w,\nhttps://images.ctfassets.net/kj59ethbquzj/1qDaw8RjPxxhzjOehxHz1g/152307656408e0efcf7c907a59cd91a7/personal-portfolio-website.png?w=1366&h=658&q=50&fm=png 1366w,\nhttps://images.ctfassets.net/kj59ethbquzj/1qDaw8RjPxxhzjOehxHz1g/152307656408e0efcf7c907a59cd91a7/personal-portfolio-website.png?w=1920&h=925&q=50&fm=png 1920w",
"sizes": "100vw"
}
},
"layout": "fullWidth",
"width": 1,
"height": 0.4817708333333333,
"placeholder": {
"fallback": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAMAAACDi47UAAABv1BMVEUaGhosLSN+gm9ORjIcHBwlJB8kJBgkJBclJBgeHRREORVFWEeEj5SNingqNys+x8tWzNFk1Nhq1dl42Nx51dp219xw19twxMhjyMxKys89x8wnZlw7MhUiIRtrKiRCLCBHys5bztJu1tuD2t501tp62N1519yokpF3b25My9A/yc4oZ10VFRUkJCQoKChHR0c1NTUqKSotOCxEw8dbxcllys1owcR30dR2z9Nyz9NkyM2+n52cjo0/wsc5vsMrXVNdTx2niSCnjCqniiOfgyAtOC1HsbVRq69errJcpah1y8982N1u1dpto7F7RlG7lpeLWXVFr7koYFYtKiJJQyxTTDZMRS9DPSssNytNk5VWf3VbfWVWdVlnsKxryc1ays+xJ06sCy2sCS2wCi2bJkYrXlUjIyMuLi48PDw0NDQsLCwrNyw6n6I/j5BJlZBJlJFavL5Xxco4v8XDEz+QCiSqCSuHCiCJDidhKS07OzszMzMeHRk4NSg7OCs5NSk5NSg6Nio5Nik7Nys6NyocGhI6OjkxMTEYGBgmJiUmJiYjJCQlJSUXFxcWFhYRERE0Lhw7NBxBORwpJRswMDA0NTUvbwraAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAB3RJTUUH5gUJBR4Qdhx/lQAAAGRJREFUCNeNzUEKglAAANEZ/5cgRLTO0ZWCTtS6jdfxEJ5BUNyF+FuIiNSit5zNiKuUAbBAMHLWqfQgctGJWsdqrze/9PH6Z+R3hNphe8z5HFIgQuFQqHbtHSVlyFN9n3w92DQfWKcTSK8wndgAAAAASUVORK5CYII="
what it might be wrong with My code? need some help :)
According to what you said in the comment section, I'd say that there's a position in projects that has no thumbnail defined (or not properly queried).
Try adding a condition wrapping the GatsbyImage display:
{project.thumb && <GatsbyImage
image={getImage(project.thumb)}
alt={project.title}
/>}
That said, check in which project you have no thumbnail.
Finally I have figured it out by
1- I removed all My content and images in Contentful CMS and create a fresh ones, It seemed there was a bug with sourcing Images into GraphQL where the Image src was always giving an empty array!!
2- Taking out getImage function and replace it with <GatsbyImage image={project.thumb.gatsbyImageData} alt={project.title}/>
,then gatsby clean to clear the .cashe and also triggered clean cashe and rebuild.
Now everything is works well.

Output values from nested Api/Laravel Collection response in vuejs

I'm trying to output values from an axios promise to my vue component. So far I'm still getting an error [Vue warn]: Error in render: "TypeError: Cannot read property 'surname' of null". Below is what my code looks like
<template>
<div>
{{user.surname}}
</div>
</template>
<!-- ----------------------------------------------------------------------------------- -->
<script>
export default {
name: 'EmployeeCard',
data(){
return{
user: null
}
},
methods:{
getUser(){
axios.get('/api/users/'+ this.$route.params.id)
.then ( response => {
this.user = response.data.data;
})
}
},
mounted(){
this.getUser();
}
}
</script>
This is the actual data returned from the api
{
"data": [
{
"data": {
"id": 11,
"surname": "Hand",
"first_name": "Westley",
"other_name": "Collier",
"email": "ole48#example.com",
"phone_number": "306-755-6192 x493",
"birthday": "06/21/1991",
"company_id": 3,
"department_id": 6,
"job_id": 1,
"state_id": 11,
"marital_status": "married",
"gender_id": 2,
"photo": null,
"is_admin": 0,
"date_of_employment": null,
"job": {
"id": 1,
"title": "HR Manager",
"comment": null,
"created_at": "2019-10-30 17:38:42",
"updated_at": "2019-10-30 17:38:42"
},
"department": {
"id": 6,
"name": "Technical",
"created_at": "2019-10-30 17:38:43",
"updated_at": "2019-10-30 17:38:43"
},
"gender": {
"id": 2,
"name": "Female",
"created_at": "2019-10-30 17:38:42",
"updated_at": "2019-10-30 17:38:42"
},
"company": {
"id": 3,
"name": "Cometshipping",
"created_at": "2019-10-30 17:38:42",
"updated_at": "2019-10-30 17:38:42"
},
"employmentstatus": {
"id": 1,
"name": "Full Time Permanent",
"comment": null,
"created_at": "2019-10-30 17:38:42",
"updated_at": "2019-10-30 17:38:42"
}
}
}
]
}
<template>
<div>
{{surname}}
</div>
</template>
<!-- ----------------------------------------------------------------------------------- -->
<script>
export default {
name: 'EmployeeCard',
data(){
return{
user: null
}
},
computed: {
surname () {
if (this.user) {
return this.user.surname
}
}
}
methods:{
getUser(){
axios.get('/api/users/'+ this.$route.params.id)
.then ( response => {
this.user = response.data[0].data;
})
}
},
mounted(){
this.getUser();
}
}
</script>
Your user variable will initially be null, and you can't get properties from a null value. Therefore, you should replace {{ user.surname }} With {{ user ? user.surname : '' }}.
Another issue is that the data property from your response is an array, not an object, so in your mounted hook you can't do this.user = response.data.data. Instead, you should do this.user = response.data[0].data.
That way, while your user isn't fetched you'll display an empty text instead of getting an error.
Also, I suggest you add a catch hook to your promise to tend to any possible errors.
<template>
<div>
{{ user.surname }}
</div>
</template>
<script>
export default {
name: 'EmployeeCard',
data(){
return{
user: {}
}
},
methods:{
getUser(){
axios.get('/api/users/'+ this.$route.params.id)
.then ( {data} => {
this.user = data[0].data;
})
}
},
mounted(){
this.getUser();
}
}
</script>

Resources