Dynamically updating GraphQL Apollo variable causes page refresh - vue.js

I am trying to dynamically fetch & filter data from API to a component in Vue using Apollo and GraplhQL. However, when the category value (this.category) is updated via user action (#click event), it causes the entire page to refresh.
Component code:
apollo: {
cards: {
prefetch: true,
query: cardsQuery,
variables() {
return {
category: this.category,
}
}
}
},
methods: {
categorySelector(category) {
this.category = category;
},
},
gql query:
query cards ($section: String){
cards (
where: { category: {section: $section} }
) {
name
category {
section
}
}
}
Am I doing something wrong with my graphql / apollo query or is the issue somewhere else?

Related

NuxtJS Apollo response is null and Missing field warnings

I'm trying to make graphql query calls using apollo on NuxtJS and I'm getting the following error.
WARN Missing field description in { 11:29:49
"__typename": "EduExp"
}
WARN Missing field componentName in { 11:29:49
"__typename": "EduExp"
}
{ 11:29:49
data: null,
loading: false,
networkStatus: 7,
stale: true
}
Here is my query
fragment IntroCardFields on IntroCard {
legend
profile {
title
url
}
introList
description {
json
}
componentName
}
query getPage($pageId: String!) {
page(id: $pageId) {
slug
name
componentsCollection {
items {
...IntroCardFields
}
}
}
}
I'm using it like this in vuex
async fetchPageData({ commit, state }) {
const apollo = this.app.apolloProvider.defaultClient;
const pageData = [];
const res = await apollo.query({
query: getPage,
variables: {
pageId: '2S3x7vBmaB2FhTUbNXWvwY',
},
});
console.log(res);
},
When I try this query without parameters on a api tool like postman or insomnia works well.
I don't get it why not working on Nuxt

Apollo smart query data not updating when variable is changed (Shopify Storefront API + Nuxt + Vuex + Apollo + GraphQL)

After days crawling through documentation I am unable to get past this issue.
I am building a currency toggle which will allow customers to switch between $AUD and $USD currencies in the UI. I am attempting to implement this via Shopify's Storefront API International Pricing GraphQL queries, specifically the #inContext directive.
I'm storing a countryCode variable in the Vuex store (which is updated via a toggle in the UI) and passing it into an Apollo Smart Query as a reactive variable in the page component.
I am able to successfully retrieve product data/prices for a certain country on first load but my issue is when updating the countryCode Smart Query variable via a Vuex action it has no effect on the Apollo data even though the Vuex data updates as desired.
I'm not sure if this issue is directly related to the Shopify Storefront API or a mistake with my Apollo query?
FYI – when updating the reactive variable productHandle, the data automatically updates as expected.
Page template
export default {
data: () => ({
productHandle: "product-name",
}),
// Get selected country code from Vuex store module
computed: {
currentCountryCode() {
return this.$store.getters["currency/countryCode"];
},
},
// Pass country code to Smart query variable
apollo: {
product: {
client: "shopify",
query: ProductByHandle,
variables: function () {
return {
handle: this.productHandle,
countryCode: this.currentCountryCode, // this should be reactive but doesn't effect query when variable is updated/changes
};
},
update(data) {
return _get(data, "productByHandle", {});
},
deep: true, // has no noticeable effect
},
},
}
GraphQL query (for context)
query ProductByHandle($handle: String!, $countryCode: CountryCode!) #inContext(country: $countryCode) {
productByHandle(handle: $handle) {
id
title
handle
productType
tags
description
descriptionHtml
availableForSale
vendor
images(first: 10) {
edges {
node {
transformedSrc
}
}
}
priceRange {
minVariantPrice{
amount
currencyCode
}
}
}
}
Any guidance or help would be greatly appreciated!
I've been finding that I have to set fetchPolicy: 'no-cache' on the Apollo query if I'm passing the product data to a component. If you're using the product data where the Apollo Query happens (i.e. same component / page ), you can skip the fetchPolicy and just add the watcher.
apollo: {
product: {
client: "shopify",
query: ProductByHandle,
fetchPolicy: 'no-cache',
variables: function () {
return {
handle: this.productHandle,
countryCode: this.currentCountryCode
}
}
}
}
Next, I've been using a watcher and call a method to update the pricing. For example:
methods: {
updatePrice(product) {
this.minPrice = Number(product.node.priceRange.minVariantPrice.amount).toFixed(2),
this.maxPrice = Number(product.node.priceRange.maxVariantPrice.amount).toFixed(2),
this.compareAtMinPrice = Number(product.node.compareAtPriceRange.minVariantPrice.amount).toFixed(2),
this.compareAtMaxPrice = Number(product.node.compareAtPriceRange.maxVariantPrice.amount).toFixed(2)
}
},
watch: {
product: function(newval, oldval) {
this.updatePrice(newval)
}
}
This works, but I'd love to figure out a solution that includes having caching. I suspect using a mutation when the currency changes might do it, but haven't dug into it.

Can't assign correct data to model through event emit

everyone. I'm working on a project and I'm stuck on a particular point. On the backend side, I'm using Laravel 5.6 and MySQL. I make a request that returns a simple JSON like this:
{
id: 1,
name: "someone",
salary_min: 2600.5,
salary_max: 3512.35
}
And I fecth this result in the frontend using Vue + axios like any other GET request and assign to a list of employees.
this.axios.get(process.env.ROOT_API + 'employee/${id}', auth)
.then(response => {
if (response.data) {
this.employee = response.data;
}
}, (error) => {
console.log(error.response.data);
});
I'm passing this data to another child component througn a method defined like so:
onEdit (id) {
// Send data received from axios and stored in 'emmployee'
bus.$emit('editEmployee', this.employee);
}
Inside the child component, I'm listening to the event like this:
mounted () {
bus.$on('editEmployee', (data) => {
console.log(data);
this.newEmployee = data;
console.log(this.newEmployee);
}
}
The result of log is as following:
// data from parent component
{ id: 1, name: "someone", salary_min: 2600.5, salary_max: 3512.35 }
// newEmployee model
{ id: 1, name: "someone", salary_min: "0.00", salary_max: "0.00" }
Somehow, during assignment, the decimal values are being zeroed and converted to string. I can't understand what's happening. Any clue?

Onsen + VueJS: Call back from child component (using onsNavigatorProps)

Per documentation here
If page A pushes page B, it can send a function as a prop or data that modifies page A’s context. This way, whenever we want to send anything to page A from page B, the latter just needs to call the function and pass some arguments:
// Page A
this.$emit('push-page', {
extends: pageB,
onsNavigatorProps: {
passDataBack(data) {
this.dataFromPageB = data;
}
}
});
I am following this idea. Doing something similar with this.$store.commit
I want to push AddItemPage and get the returned value copied to this.items
//Parent.vue
pushAddItemPage() {
this.$store.commit('navigator/push', {
extends: AddItemPage,
data() {
return {
toolbarInfo: {
backLabel: this.$t('Page'),
title: this.$t('Add Item')
}
}
},
onsNavigatorProps: {
passDataBack(data) {
this.items = data.splice() //***this*** is undefined here
}
}
})
},
//AddItemPage.vue
...
submitChanges()
{
this.$attrs.passDataBack(this, ['abc', 'xyz']) // passDataBack() is called, no issues.
},
...
Only problem is this is not available inside callback function.
So i can't do this.items = data.splice()
current context is available with arrow operator.
Correct version:
onsNavigatorProps: {
passDataBack: (data) => {
this.items = data.splice()
}
}

How do I handle deletes in Vue Apollo with deeply nested queries?

I have a query that returns multiple nested objects to render a screen full of information. I want to delete one of the deeply-nested objects and update the screen optimistically (i.e. without running the complete query).
To explain the query and UI, I'll use a Trello board -like query as an example:
query everything {
getBoard(id: "foo") {
name
cardLists {
edges {
node {
id
name
cards {
edges {
node {
id
name
}
}
}
}
}
}
}
}
The result of this query is used to build a UI like this: https://d3uepj124s5rcx.cloudfront.net/items/170a0V1j0u0S2p1l290I/Board.png
I'm building the app using:
VueJS
Vue Apollo
Scaphold.io as my GraphQL store
When I want to delete one of the cards, I call:
deleteCard: function () {
this.$apollo.mutate({
mutation: gql`
mutation deleteCard($card: DeleteCardInput!) {
deleteCard(input: $card) {
changedCard {
id
}
}
}
`,
variables: {
'card': {
id: this.id
}
},
})
.then(data => {
// Success
})
}
The mutation is successfully deleting the card, but I want to update the UI immediately based on the mutation. The simple option for doing this is to call refetchQueries: ['everything'] — but this is an expensive query and too slow for quick UI updates.
What I want to do is update the UI optimistically, but the example mutations for Vue Apollo don't address either deletes or the deeply-nested scenario.
What is the right solution / best-practices for deleting an item from a deeply-nested query, and optimistically updating the UI?
If you look at the documentation for the optimistic Response of apollo you see that the optimistic response "fakes" the mutation result.
So it will handle the updateQueries function with the optimistic values. In your case this means that if you add the optimisticResponse property it should alter the query inside the apollo store with the optimistic values:
Could look like this:
this.$apollo.mutate({
mutation: gql `
mutation deleteCard($card: DeleteCardInput!) {
deleteCard(input: $card) {
changedCard {
id
}
}
}
`,
variables: {
'card': {
id: this.id
}
},
updateQueries: {
// .... update Board
},
optimisticResponse: {
__typename: 'Mutation',
deleteCard: {
__typename: 'Card', // graphQL type of the card
id: this.id,
},
},
})