Axios and Vuejs
I am receiving data from the api,
but some items are null,
and I get a message on the console,
how can I deal with these errors
I tried to make a filter but it didn't work.
link: App
It would help if you could post some of your code from your Vue component, but there are many ways to deal with this. In general, you need to check for the value before displaying. Below are a couple of ways you could do this with Vue.
One way is using v-if. If the network is not null, show the network
<div v-if="show.network">{{ show.network }}</div>
You could also use a v-else directive to display something else
<div v-if="show.network">{{ show.network }}</div>
<div v-else>network unavailable</div>
Another way is to use a computed property.
<template>
<div>
<div>{{ network }}</div>
</div>
</template>
<script>
export default {
data: function() {
return {
show: {
network: null
}
}
},
computed: {
network() {
return ( this.show.network ) ? this.show.network : "not available";
}
}
};
</script>
The list goes on... As the developer, you will need to check the value to determine if it can be shown before displaying it.
From your template, you can use this code:
<p><span>Network: </span>{{ result.show?.network?.name || '' }}</p>
All browsers dont support ? so below will always works:
<p><span>Network: </span>{{ result.show && result.show.network && result.show.network.name }}</p>
Related
I have a page where I want to display a message if a user comes from a certain URL:
If arriving from this URL:
http://www.testapp.com?_a=lookingforthis&token=5b6b7f/account/about
<template>Show this message</template>
If from here:
http://www.testapp.com/account/about
<template>Dont show this message</template>
Would I need to do this in mounted() or method()?
Id this the correct way to trigger this?
this.$route.query?.lookingforthis
Something like this should work well
<template>
<div>
{{ showOrNotTheMessage }}
</div>
</template>
<script>
export default {
computed: {
showOrNotTheMessage() {
return this.$route.query?.lookingforthis
? 'Show this message'
: 'Dont show this message'
},
},
}
</script>
Being triggered on an URL like http://localhost:3000/about?lookingforthis=TEST.
As shown if using the Vue devtools
PS: if TEST is missing, it's falsy as expected.
I have a Nuxt project with Buefy components. There is a form with some field component which should react on error according the message parameter for this component. But does not. I can see the correct value in debuger but component does not show the message. :message property should work like the in first email example from documentation
The code looks like:
<template #company>
<h2 class="title">{{ $t('general.login.create_company') }}</h2>
<b-field
:type="loginErrors.company_name ? 'is-danger' : ''"
:message="loginErrors.company_name ? loginErrors.company_name : ''"
>
<b-input
v-model="companyName"
name="company_name"
type="text"
autocomplete="off"
:placeholder="$t('general.login.create_company')"
></b-input>
</b-field>
<div class="buttons is-centered">
<b-button type="is-primary is-light" #click="createCompany">Save</b-button>
</div>
</template>
...
data() {
return {
...
loginErrors: {},
error: 'aaaaaa',
};
},
...
async createCompany() {
const result = await this.$api.users.createCompany({company_name: this.companyName});
if( result.error ) {
this.loginErrors.company_name = result.error; // This does not work although the variable has correct value set
this.error = result.error; // This works fine
return false;
}
},
I use this pattern in other components and it works. I dont understand it. thaks for any help.
change detection of data objects in Vue is shallow (top level only)
In vue.js, Dynamically added property to an object is not reactive. Instead we can assign a whole object so that change detection happen.
For a better understanding please go through this official documentation of Vue.
Demo :
new Vue({
el: '#app',
data() {
return {
loginErrors: {}
}
},
mounted() {
this.loginErrors = {
company_name: 'some value'
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<p>{{ loginErrors.company_name ? 'is-danger' : 'no-danger' }}</p>
</div>
I don't think Vue components react to object property changed in a direct way, you could try this.$set(this.loginErrors, 'company_name', result.error); instead of this.loginErrors.company_name = result.error;
FYI: https://v2.vuejs.org/v2/guide/reactivity.html?redirect=true#Change-Detection-Caveats
The solution in this case was to update Buefy version from 0.4.11 to 0.4.21. This fix the issue. Another thing is that is causes new issue with :type in combination with grouped param.
in my project i'm suffering from delay in API requests and that's because i have huge amount of data in API, so i added a cache but it still appears white page when page creates, so i was thinking of adding API call on app.vue so request will be faster... is there a way to do it?
now i'm making API request on each page in my project
code below:
//building.vue where buildings api used
<template>
<b-row class="icon-examples">
<b-col lg="3" md="6" v-for="(building, index) in buildings"
:key="index" >
<button type="button" class="btn-icon-clipboard" #click="GoToBuilding(building._id)"
>
<div>
<i class="ni ni-building"></i>
<router-link
class="question-routerToDetail"
:to="`/tables/${building._id}`"
> <span > B info - </span>
<span>{{building.building_number}}</span></router-link>
</div>
</button>
</b-col>
</b-row>
</template>
<script>
import BuildingsService from "../../../services/ApiService"
export default {
data() {
return {
};
},
components: {
props:
['buildings'],
BaseHeader,
// buildings:[]
},
}
}
</script>
app.vue:
<template>
<router-view :number="count" #send="getNewCount" #reset="onReset" :buildings="buildings">
<sidebar :number="count" #reset="onReset"/>
</router-view>
</template>
<script>
export default {
components: {
sidebar,
},
data() {
return {
buildings: []
};
},
created(){
BuildingsService.getBuildings().then((response) => {
this.buildings = response.data.response;
console.log(this.buildings , "skk")
});
}
}
</script>
can i add saved API request array in app.vue and use it on other pages? and is it gonna improve my API call?
thanks in advance
Edit: updated question depending on answer below.. but getting empty data with no console errors
Yes, you can call the API a single time in the component that contains router-view and pass down the results to rendered components through props. The rendered components must declare the props that will be passed down to them, but only if they will be using it.
<template>
<router-view :number="count"
#send="getNewCount" #reset="onReset"
:buildings="buildings">
<sidebar :number="count" #reset="onReset"/>
</router-view>
</template>
<script>
import BuildingsService from "../../../services/ApiService"
export default {
components: {
sidebar,
},
data() {
return {
buildings: []
};
},
created(){
BuildingsService.getBuildings().then((response) => {
this.buildings = response.data.response;
});
}
}
</script>
But if the API call returns a huge amount of data or is really slow, then I really suggest that you check into optimizing the backend queries of your API, paginating results, and loading them progressively with lazy load on scroll or something.
Also it would be good if you can keep something in your state to check if the data is being loaded or not, so that you can show a loader or something rather than a white page until you get the results.
One possible solution is to adapt getBuildings(), such that it will call the backend only once and store the result in a property of BuildingsService, e.g. cachedBuildings.
If cachedBuildings is empty, getBuildings() calls the backend and stores the result in cachedBuildings.
If cachedBuildings is not empty, getBuildings() returns cachedBuildings.
The advantage of this solution is, that you only adapt your code in one place and the caching is transparent for every component.
Why would something like this happen?
I have a vue app that is pointing to a strapi CMS instance and is consuming the API to render on the page.
I changed my backend query slightly and the response is a little different so I have to go array index 0 to it ({{ webinar[0].webinar_title }} ) but for some reason it says it's undefined, even though it still renders on the page:
<template>
<section class="webinar-information">
<div>
<h1>{{ webinar[0].webinar_title }}</h1>
<p>{{ webinar[0].webinar_description }}</p>
</div>
</section>
</template>
<script>
import axios from 'axios';
export default {
name: 'WebinarSingle',
data () {
return {
webinar: [],
error: null
}
},
async mounted () {
try {
const response = await axios.get('http://localhost:1337/webinars?webinar_slug=' + `${this.$route.params.id}`)
this.webinar = response.data
console.log(this.webinar)
// this is returning the title why is it "undefined" in the console?
console.log('the title is: ' + this.webinar[0].webinar_title)
} catch (error) {
this.error = error;
}
},
props: {
header: String
}
}
</script>
<style scoped>
</style>
The output is correct and looks like this:
But my console is this:
The output of
http://localhost:1337/webinars?webinar_slug=' + ${this.$route.params.id}``
is:
http://localhost:1337/webinars?webinar_slug=accelerating-the-close-with-technology-and-automation
When you console log the response it looks like this:
so I have to access everything by doing [0] with it "working" but the console says it's undefined. why?
When the page loads, Vue tries to render your template:
<template>
<section class="webinar-information">
<div>
<h1>{{ webinar[0].webinar_title }}</h1>
<p>{{ webinar[0].webinar_description }}</p>
</div>
</section>
</template>
At this point in time, webinar is what you initialised it with, i.e. []. When you try to access the first element, this causes your error.
Then X milliseconds later, localhost:1337 returns the response that displays.
To fix your problem, you can add a v-if="webinar && webinar.length" to the root element in your template (not the template element), then it will only try access webinar[0] when there is an element.
I am working on my own projects I made a query and it gets the total users and store it in the p tag.
<v-card class="mt-10 mb-5 users" max-width="344">
<v-card-text>
<p class="display-1 text--primary text-center">Users</p>
<div class="display-1 text--primary text-center">
<p id="users"></p>
</div>
</v-card-text>
</v-card>
created() {
// Get all user profile
db.collection("Profile").get().then((res) => {
document.getElementById('users').innerHTML = res.size
})
}
But now I get the error I didn't change anything.
The error
Uncaught (in promise) TypeError: Cannot set property 'innerHTML' of null
As others have mentioned, Vue works best when you use data to drive your templates. Directly manipulating the DOM is an anti-pattern.
For example, use a data property for the information you want to display and assign it a value when your query completes
<p>{{ profileCount }}</p>
export default {
data: () => ({ profileCount: null }),
async created () {
const { size } = await db.collection("Profile").get()
this.profileCount = size
}
}
Do not manipulate DOM directly as it's normally done while using vanilla JS (plain javascript) or jQuery because when you are using vue.js it'snice to follow reactive pattern.
<template>
<p> {{ users }} </p>
</template>
<script>
export default {
data() {
return {
users: 0
};
},
// you can use created or mounted, see which works
created() {
db.collection("Profile").get().then((res) => {
this.users = res.size
})
}
};
</script>