In my vue 2.6/cli 4/vuex 3.1 app I update some data in store vuex, like in src/store/index.js :
userPropStore(context, userProp ) {
bus.$emit( 'beforeUserPropStore', userProp );
let apiUrl = process.env.VUE_APP_API_URL
Vue.http.post(apiUrl + '/personal/user-props', userProp).then(({data}) => {
let userProps= this.getters.userProps
userProps.push({
"id": data.user_props.id,
"name": data.user_props.name,
"value": data.user_props.value,
"created_at": data.user_props.created_at,
})
this.commit('refreshUserProps', userProps);
bus.$emit( 'onUserPropStoreSuccess', data );
}, error => {
console.log('context::')
console.log(context)
console.error(error)
self.$refs.userObserverForm.setErrors(error.body.errors)
});
}, // userPropStore(context, userProp ) {
and using ValidationProvider of vee-validate 3.2 I want to catch server errors (like not unique item)
but I got error :
index.js?4360:847 Uncaught (in promise) TypeError: Cannot read property 'userObserverForm' of undefined
on line
self.$refs.userObserverForm.setErrors(error.body.errors)
If there is a way in store object to get access to parent page, maybe with context, which has : https://imgur.com/a/P4St8Ri
?
Thanks!
This is a very strange implementation.
Obviously self.$refs.userObserverForm.setErrors(error.body.errors) fails because you are NOT in a component, which is where $refs is available.
What you have to do in your catch block is setting the errors in Vuex and then make your component read from there.
Pseudocode follows:
I don't understand what your bus is doing... I guess you use it to send data to your component, but why use Vuex then?
userPropStore(context, userProp ) {
bus.$emit( 'beforeUserPropStore', userProp );
let apiUrl = process.env.VUE_APP_API_URL
Vue.http.post(apiUrl + '/personal/user-props', userProp).then(({data}) => {
let userProps= this.getters.userProps
userProps.push({
"id": data.user_props.id,
"name": data.user_props.name,
"value": data.user_props.value,
"created_at": data.user_props.created_at,
})
this.commit('refreshUserProps', userProps);
bus.$emit( 'onUserPropStoreSuccess', data );
commit('SET_USER_PROPS, data)
}, error => {
console.log('context::')
console.log(context)
console.error(error)
commit('SET_USER_PROPS_ERRORS', error.body.errors)
});
}
The way I've done this in the past is to return the promise that Vue.http.post produces and then do what you want in your component with the failure information:
userPropStore(context, userProp ) {
bus.$emit( 'beforeUserPropStore', userProp );
let apiUrl = process.env.VUE_APP_API_URL
//add return to the line below
return Vue.http.post(apiUrl + '/personal/user-props', userProp).then(({data}) => {
Then over in your component:
loadData() {
this.$store.dispatch('userPropStore').catch((error) => {
this.$refs.userObserverForm.setErrors(error.body.errors)
//any other things you want to do "in component" goes here
});
}
Related
I'm trying to set an array of objects in React Native AsyncStorage.
However, just the 1st item will store in it.
await AsyncStorage.setItem(
`${props.index}`,
JSON.stringify({
data: totalSet,
name: props.index,
date: today.toISOString().substring(0, 10),
})
the first item (data) is an array
Update
In my workout tracker app,
I try to create nested object. in the child component, I have following data:
weight: number
reps: number
result: also number (combination of weight and reps)
setIndex :number, which indicate the index of each sets
I have sent above data to parent component like this:
Child component
onPress={() =>
childToParent({
setDetails: [
{
setIndex: setIndex,
result: result,
weight: weight,
reps: reps,
},
],
}) + buttonStatus()
in the parent, I have given data, and trying to add into exsiting array and also adding 2 more item, date and index of each workout
parent component
const [totalSet, settotalSet] = useState([{ today }, { index }]);
useEffect(() => {
if (data != 0) {
settotalSet((current) => [...current, data]);
}
}, [data]);
then I store it into asyncstorage
const storeData = async () => {
try {
await AsyncStorage.setItem(
`${props.index}`,
JSON.stringify(totalSet)
).then((res) => console.log(res));
} catch (e) {
// saving error
}
};
and get it into another component like this
getMyObject = async () => {
try {
await AsyncStorage.getItem('1512').then((res) => {
setData(JSON.parse(res));
});
} catch (e) {
// read error
}
};
Finally as a result, I have below array:
Array [
Object {
"today": "2022-09-04",
},
Object {
"index": "1512",
},
Object {
"setDetails": Array [
Object {
"reps": "3",
"result": 13.200000000000001,
"setIndex": 0,
"weight": "12",
},
],
},
Object {
"setDetails": Array [
Object {
"reps": "3",
"result": 26.400000000000002,
"setIndex": 1,
"weight": "24",
},
],
},
]
everything is fine, except I need a nested object and this is an array.
How to create such an nested object at the first place?
Im trying to PUT some of atributes from array Zamestnanci to array archivovany, I tried almost everything and it seems to not work at all. I allways get HTTP error 415 or HTTP 400 because the atributes in archivovany are null.
<script>
import axios from 'axios';
import ZamestnanciService from "../ZamestnanciService";
export default {
name: 'Zamestnanci',
data() {
return {
zamestnanci: [{
id:"",
meno:"",
priezvisko:"",
pozicia:"",
}],
archivovany: [{
id: "",
meno: "",
priezvisko: "",
datumPrepustenia: new Date(),
poslednaPozicia: "",
}]
,
};
},
created(){
this.getZamestnanci();
},
methods: {
getZamestnanci(){
axios.get('https://localhost:49153/api/zamestnanci').then(response => {
this.zamestnanci = response.data;
console.log(response.data);})
}, //get
archivovat(id){
axios.post('https://localhost:49153/api/archivovany/',this.archivovany).then(res=>{
console.log(res);})
},
deleteZamestnanci(id){
axios.delete('https://localhost:49153/api/zamestnanci/'+id).then(response => {this.getZamestnanci();})
if(confirm("chcete archivovaƄ zamestnanca ?")){
this.archivovat();
}
},//delete
}
}
</script>
I need to pass id, meno, priezvisko, pozicia to array archivovany and then PUT the data to another table, but nothing seems to work can anyone please help me ?
The data is from asp.net core API
Okay so I solved it my way, I don't know if its the best way but here is my solution.
i created one more object zamestnanec.
export default {
name: 'Zamestnanci',
data() {
return {
zamestnanci:"",
zamestnanec:"",
archivovany: {
meno: "",
priezvisko: "",
adresa:"",
datumNarodenia:"",
datumPrepustenia: new Date(),
pozicia: "",
plat: ""
}
I created one more axios.get function to load data to the object inside the function Archivovat(id) and there i saved the data from get function to zamestnanec and after that I have put the data to object where i needed.
archivovat(id){
axios.get('https://localhost:49153/api/zamestnanci/'+id).then(response => {
this.zamestnanec = response.data;
this.archivovany.meno=this.zamestnanec.meno;
this.archivovany.priezvisko=this.zamestnanec.priezvisko;
this.archivovany.adresa=this.zamestnanec.adresa;
this.archivovany.datumNarodenia=this.zamestnanec.datumNarodenia;
this.archivovany.pozicia=this.zamestnanec.pozicia;
this.archivovany.plat=this.zamestnanec.plat;
console.log(response.data);
axios.post('https://localhost:49153/api/archivovany/',this.archivovany).then(res=>{
console.log(res);})})
},
I'ts really messy code but it solved my problem.
Context:
I have a reports application that contains a report editor. This Report Editor is used to edit the contents of the report, such as the title, the criteria for filtering the results, the time range of results, etc..
The Problem:
There is something wrong with the way I have used Vuex/Vuejs in my components I believe. My store contains getters for each aspect of this report editor. Like this:
const getters = {
activeReportTitle: state => {
return state.activeReport.title;
},
activeReportID: state => {
return state.activeReport.id;
},
timeframe: state => {
return state.activeReport.timeframe;
},
includePreviousData: state => {
return state.activeReport.includePreviousData;
},
reportCriteria: state => {
return state.activeReport.reportCriteria;
},
emailableList: state => {
return state.activeReport.emailableList;
},
dataPoints: state => {
return state.activeReport.configuration?.dataPoints;
},
...
Each getter is used in a separate component. This component uses the getter only to initialize the local data, and uses actions to modify the state. The way I have done this is by adding a local data property and a watcher on the getter that changes the local data property. The component is using the local data property and that data property is sent to the action and the getter is updated.
ReportSearchCriteria.vue
...
data() {
return {
localReportCriteria: [],
currentCriteria: "",
};
},
watch: {
reportCriteria: {
immediate: true,
handler(val) {
this.localReportCriteria = [...val];
}
}
},
computed:{
...reportStore.mapGetters(['reportCriteria'])
},
methods: {
...reportStore.mapActions(["updateReportCriteria"]),
addSearchCriteria() {
if (this.currentCriteria) {
this.localReportCriteria.push(this.currentCriteria);
this.updateReportCqriteria(this.localReportCriteria);
}
this.currentCriteria = "";
this.$refs['reportCriteriaField'].reset();
},
...
The hierarchy of the components is set up like this
Reports.Vue
GraphEditor.vue
ReportSearchCriteria.vue
Could you clarify what the problem is? Does the 'reportCriteria' not get updated when it's supposed to? How does the function 'updatedReportCriteria' look like? You use mutations to update a state in the store. Also, you have a typo when you're calling the action.
In a vue cli app, I can't figure out how to make an object in a component re-render when there is a change in the Vuex store made by another component. In this example, I change the curDocTypevariable, but the b-form-select object remains the same value (initially 0). Not sure if the problem is in the Bootsrap side or in Vue.
I have this in one component1.vue :
HTML
<b-form-select v-model="curDocType" :options="options" class="mb-3" v-bind:style="{'background-color': activeColor}">
SCRIPT
data() {
return {
options: [
{ value: 1, text: 'Sale' },
{ value: 5, text: 'CrMemo' },
{ value: 0, text: 'Quote' },
{ value: 4, text: 'CashIn' },
],
curDocType : this.$store.state.curDocType,
activeColor : '#9EDE7D' //Red
}
},
watch:{
curDocType(newval,oldval){
if (newval == 5) this.activeColor = '#D67373'
else this.activeColor = '#9EDE7D'
if (this.$store.state.curOrder == ""){
this.$store.commit('setcurDocType', newval)
}else{
this.$nextTick(() => {this.curDocType=this.$store.state.curDocType})
}
}
}
Now, I have another component2.vue, where I call a method that changes the curDocType in the Vuex Store:
convertOrder(){
if (this.$store.state.curOrder != ""){
axios.post(this.ApiBaseUrl + 'PosFunctions/QuoteToOrder',
JSON.stringify(this.$store.state.curOrder),
{headers: {"Content-Type": "application/json"}})
.then((response) => {
var res = response;
this.$store.commit('setcurDocType', 1) //!!IMPORTANT
this.RecoverSale(response.data.return_value)
})
}
}
Store.js:
setcurDocType (state, DocType) {
state.curDocType = DocType
},
Versions:
bootstrap-vue#2.16.0
bootstrap#4.5.2"
vue#2.6.12
The problem must come from data(), i don't think calling $store from it will works. (even calling "this" in it is an error but i'm not 100% sure)
Moreover, you shouldn't set a store state to a v-model, since a store state is a "getter" only and a v-model is a two-way binding (getter + setter)
You could do a computed :
curDocType : {
get(){
return this.$store.state.curDocType
}
set(value){
this.$store.commit('setcurDocType', 1);
}
}
With this, binding curDocType to the v-model is correct.
Hope this will fix your problem
While playing around with vue.js I noticed some strange behavior while trying to display on a page data from an API, but here's the strange thing :
using vue 2.0.0, i can see the "Title", but I have an error in dev console [see printscreen]
using the latest vue version, i can't see the "Title" [and I have the same error in the printscreen]
Is it normal, or?
Source code :
template:
'<div>'+
'Form with id = {{id}}'+
'<br/>'+
'has title = {{item.details.Title}}'+
'</div>',
data: function(){
return {
id: '',
item: {}
}
},
created: function() {
this.get()
},
methods: {
get: function() {
var self = this
id = window.location.hash
id = id.replace('#/whatever/','')
axiosInstance.get('/thebackendresource/'+id) // <--- make http calls etc
.then(function (response) {
self.id = id
self.item = response.data
console.log(self.item)
}).catch(function (error) {
console.log(error)
}
);
}
}
You are getting this error, because when you are fetching data from axiosinstance, that time item.details is null, and when it tries to render it throws this error.
Once the api call is completed, it updates the the DOM and in turn re-renders the DOM, so you can see item.details.Title rendered.
You need to add a null check to prevent this error, which can be easily done using v-if, like follwoing:
template:
'<div>'+
'Form with id = {{id}}'+
'<br/>'+
'<span v-if="item.details"> has title = {{item.details.Title}}'+
'</span>' +
'</div>',