I am having problems in an html tag that uses an object from my object in store.
When i refresh my page, the array from my sotre is empty, so i when i refresh in the index page, it will first load the html, then the mounted method, and its where i fill my store. its says that Cannot read property 'substring' of undefined
index.vue that i use this object:
<p v-html="pegaPrimeiroPost.conteudo.substring(0,500)"></p>
export default of index.vue:
computed: {
...mapGetters({
postsDB: "postagensDB/pegaPosts",
pegaPrimeiroPost: "postagensDB/pegaPrimeiroPost",
}),
},
methods: {
...mapActions({
buscaPostDB: "postagensDB/pegaPostsDB",
}),
},
async mounted() {
**await this.buscaPostDB();**
});
},
this object pegaPrimeiroPost is an objetct from my array that i fill from my database.
store/postagensDB:
import axios from 'axios'
export const state = () => ({
posts: [],
primeiroPost: {},
})
export const getters = {
pegaPosts(state) {
return state.posts;
},
pegaPrimeiroPost(state) {
return state.primeiroPost;
},
}
export const actions = {
async pegaPostsDB(state) {
await axios
.get("http:/MY_API_ADRESS")
.then((response) => {
state.commit('carregaStatePosts', response.data)
})
.catch((response) => {
console.log(response)
});
},
}
export const mutations = {
async carregaStatePosts(state, postsDB) {
state.posts = postsDB.posts;
state.primeiroPost = state.posts[0];
},
}
If i erase the substring() method, reload the page, then it will fill my store; and then re-add the substring(), it works, but wont solve my prob. Can anyone help me?
I've never used Vue, but this sounds like you have some sort of async action that populates the object, but your default value (used before the async call has completed) doesn't have that property. The quickest solution is probably just give it a value if it doesn't exist:
(pegaPrimeiroPost.conteudo || '').substring(0,500)
or set a "default" object with that property:
export const state = () => ({
posts: [],
primeiroPost: { conteudo: '' },
})
Related
I'm using vue 3 and composable files for sharing some functions through my whole app.
My usePluck.js composable file looks like
import { api } from 'boot/axios'
export default function usePlucks() {
const pluckUsers = ({val = null, excludeIds = null}) => api.get('/users/pluck', { params: { search: val, exclude_ids: excludeIds }})
return {
pluckUsers
}
}
In order to make use of this function in my component I do
<script>
import usePlucks from 'composables/usePlucks.js'
export default {
name: 'Test',
setup() {
const { pluckUsers } = usePlucks()
onBeforeMount(() => {
pluckUsers({excludeIds: [props.id]})
})
return {
}
}
}
</script>
So far so good, but now I'd like to even be able to not send any args to the function
onBeforeMount(() => {
pluckUsers()
})
But when I do that, I get
Uncaught TypeError: Cannot read properties of undefined (reading 'val')
I assume it's because I'm not sending an object as argument to the function, therefore I'm trying to read val from a null value: null.val
What I'm looking for is a way to send, none, only one, or all arguments to the function with no need to set null values:
// I don't want this
pluckUsers({})
// Nor this
pluckUsers({val: null, excludeIds: [props.id]})
I just want to send only needed args.
Any advice about any other approach will be appreciated.
import { api } from 'boot/axios'
export default function usePlucks() {
const pluckUsers = ({val = null, excludeIds = null} = {}) => api.get('/users/pluck', { params: { search: val, exclude_ids: excludeIds }})
return {
pluckUsers
}
}
I believe this is what you're looking for. The { ... } = {}
EDIT: It didn't work without this because with no argument the destructuring failed because it can't match an object. That's why you also need a default value on the parameter object, also called simulated named parameter.
I would like to put my calls to my API in a separate page and not in the template page of my app. So, I create a file "customersAPI.js" and I put this code :
export function findAllCustomers () {
axios.get('http://127.0.0.1:8000/api/customers')
.then((reponse)=>{
console.log(reponse.data['hydra:member'])
return reponse.data['hydra:member']
}).catch(err=>console.log(err))
}
So I try to retrieve my data in my template page and put these data in data but It does not work because of the asynchronous thing of api call and because I don't know how to pass the data...
I do this in my template page :
data() {
return {
customer: [],
}
},
mounted() {
this.getAllCustomers();
},
getAllCustomers() {
this.customer = findAllCustomers();
}
I know it is not the good way to do this but I don't know how to do... So I need clarification about that. And, every time I go into the documentation, there are no examples with an API call outside of the part where there is the page template. Is it a good practice to want to put the api call apart? And in general calls to functions so that the code is not too long?
Thanks for help
In your case I advise you to try add async in mounted or in func.
async mounted() {
this.customers = await this.findAllCustomers();
},
------
methods: {
async getAllCustomers(){
this.customer = await findAllCustomers();
}
}
But better practice to fetch information from store:
COMPONENT
<script>
import {mapActions} from 'vuex'
export default {
data() {
return {
customer: [],
}
},
mounted() {
this.customer = this.fetchAll();//better to get via getters
},
methods() {
...mapActions('customers', ['fetchAll']),
//OR
// fetchAllCustomers(){
// this.$store.dispath('customers/fetchAll')
// }
}
}
</script>
STORE
// async action that put all customers in store
const fetchAll = async ({ commit }) => {
commit(types.SET_ERROR, '')
commit(types.TOGGLE_LOADING, true)
try {
const { data} = await customerAPI.findAll(namespace)
commit(types.SET_ALLIDS, data['hydra:member'])
commit(types.TOGGLE_LOADING, false)
return data['hydra:member']
} catch (error) {
commit(types.TOGGLE_LOADING, false)
commit(types.SET_ERROR, error)
}
},
API
// func that receive promise
export function findAll () {
return axios.get('http://127.0.0.1:8000/api/customers')
}
Please read about vuex
https://vuex.vuejs.org/guide/actions.html
I have a function which takes an ID as an argument and finds the object to which this ID belongs from a JSON that is stored in the Vuex store. So far I have used the function in 1 component only, however, I recently created a second component which also requires that function. Currently I have just copied and pasted the function, however, this seems to be less than optimal. This is why I wonder where should this function be placed so that it's accessible from all components that need it.
I've been wondering if the Vuex store is a viable place to store the function but I'm not too sure so I decided to ask for your advice. Thanks
findChampionName(id){
let championId = id.toString();
let champion = Object.entries(this.$store.state.champions).find(([key,value]) => value.key === championId);
return champion[1]
}
Vuex store:
export default new Vuex.Store({
state: {
champions: null
},
mutations: {
champions(state, data){
state.champions = data.champions
}
},
actions: {
getChampions({commit, state}){
axios.get("https://ddragon.leagueoflegends.com/cdn/9.14.1/data/en_US/champion.json")
.then((response) => {
commit('champions', {
champions: response.data.data
})
})
.catch(function (error) {
console.log(error);
})
}
}
})
As far as I can see, you should use a vuex getter for your case:
getters: {
getChampionName => state => id => {
let championId = id.toString();
let champion = Object.entries(state.champions).find(([key,value]) => value.key === championId);
return champion[1]
}
}
And you can access that getter by passing the id: this.$store.getters['findChampionName'](id)
I have searched around for an answer to this and also followed the example on the vue router documentation but am still having issues. I am trying to do an http call on initial load of a component and then also watch the router params and update the 'get' call from vue-resource.
My vue component js looks like this...
export default {
name: 'city',
components: {
Entry
},
data () {
return {
city: null
}
},
mounted() {
this.fetchData();
},
watch: {
'$route': 'fetchData'
},
methods: {
fetchData() {
const cityName = this.$route.params.name;
this.$http.get('http://localhost:3000/cities?short=' + cityName).then(function(response){
this.city = response.data;
}, function(error){
alert(error.statusText);
});
console.log(cityName)
}
}
}
I have logged out the 'cityName' in my fetchData method and it always returns the right name, but when I append that 'cityName' to the http get call it is not returning the proper data. On initial load, this.city remains null and then each time I update the route, the data returns with the previous city selected instead of the new updated city in the route. I have tried Vue's created property in place of mounted and the same thing happens. Any ideas?
Try changing your fetchData method to the following:
fetchData() {
const cityName = this.$route.params.name;
this.$http.get('http://localhost:3000/cities?short=' + cityName).then((response) => {
this.city = response.data;
}, (error) => {
alert(error.statusText);
});
console.log(cityName)
}
The => function notation keeps this in context of the component.
I am trying to separate my axios calls from my main vue instance by importing them instead of calling them directly in the created hook.
I have this in a separate file called data.js
import axios from 'axios'
export default{
myData() {
return axios.get(`http://localhost:8080/data.json`)
.then(response => {
// JSON responses are automatically parsed.
return response.data;
})
.catch(e => {
return this.myErrors.push(e)
});
},
And in my vue instance I have the following:
import myDataApi from '#/api/data.js'
export default {
name: 'app',
components: {
myDataApi, // not sure if this is correct
},
data: function () {
return {
myInfo: '',
}
},
created() {
this.myInfo = myDataApi.myData();
console.log('this.myInfo= ', this.myInfo)
},
I am trying to populate myInfo with the json called by myData. This returns [object Promise] in Vue devtools and the as PromiseĀ {<pending>} in the console.
All the data I need is inside that PromiseĀ {<pending>} in an array called [[PromiseValue]]:Object so I know it is working, I just need to know the correct way implementing this.
I don't have a development environment enabled to test this at the moment, but I do notice that you are trying to assign a variable the moment that the component is initialized. This object is a promise, but you're not handling the promise after it is resolved inside the component where you have imported it.
I would recommend trying to handle the promise inside of the actual component, something like:
import myDataApi from '#/api/data.js'
export default {
name: 'app',
components: {
myDataApi, // not sure if this is correct
},
data: function () {
return {
myInfo: '',
}
},
created() {
myDataApi.myData()
.then((data) => {
this.myInfo = data
console.log('this.myInfo= ', this.myInfo);
});
.catch((e) => handleError) // however you want to handle it
},
Just to add to #LexJacobs answer. I omitted the parenthesis around data in .then() as seen below. Vue was squawking about data not being available even though it was. This solved that problem, although to be honest I don't know why.
myDataApi.myData()
.then(data => {
this.dataHasLoaded = true;
this.myInfo = data;
})
.catch(e => {
this.myErrors.push(e)
});