I need to send a form from a modal. Not using a full Vue app, but inserting Vue.js in my HTML page.
I tried a lot of unsuccesful things with my current modal, so I reduced it to the basic modal example I used for the first time https://v2.vuejs.org/v2/examples/modal.html
For the form, I used also the most basic form validation example at https://v2.vuejs.org/v2/cookbook/form-validation.html (I have it working in other places).
And I have created this unsuccessful fiddle:
https://jsfiddle.net/JIBRVI/03qnok9m/53/
Vue.component('modal', {
template: '#modal-template'
})
// start app
// eslint-disable-next-line no-new
new Vue({
el: '#app',
data: {
showModal: false,
errors: [],
name: ''
},
methods: {
checkForm: function (e) {
if (this.name) {
return true
}
this.errors = []
if (!this.name) {
this.errors.push('Name required.')
}
e.preventDefault()
}
}
})
In the basic modal example I added the form with a field, a submit button and a placeholder to show errors. Also the input field «name» and the array «errors» to the data section in the app. I also added the «checkForm» method.
The main error says:
Property or method "checkForm" is not defined on the
instance but referenced during render. Make sure that this property is
reactive, either in the data option, or for class-based components, by
initializing the property
Maybe the main page can communicate with the modal, so data and methods from the main page can’t be used.
I also tried to make a component with the form, but it didn’t work either. I can’t communicate with the modal.
Any help will be aprreciated.
You need to move the name and checkform methods to the modal component. You have currently defined those two in the app component and are trying to access it from the modal which is in the modal component.
Vue.component('modal', {
template: '#modal-template',
data(){
return {
name: '',
errors: [],
}
},
methods: {
checkForm: function (e) {
if (this.name) {
return true
}
this.errors = []
if (!this.name) {
this.errors.push('Name required.')
}
e.preventDefault()
}
}
})
Related
I have a crud page, it is only a one file that works for both editing existing content and creating a new one, I am using froala editor on product description. I did the config of the froala, and it works fine when i try to create a new product but it is not working on the editing side also not throwing any error. Here is what i did:
I am using Vue3 for the project,
Firstly i defined and imported froala,
data() {
return {
product: undefined as Product<Populated>,
froala: {
instance: null as FroalaTypes.FroalaEditor,
config: froala.baseConfig
}
}
},
Then i did the config on mounted hook
mounted() {
this.froala.instance = FroalaEditor(
'.froala-editor',
froala.extendBase({
events: {
contentChanged: () => {
this.product.description = this.froala.instance.html.get()
this.$forceUpdate()
}
}
})
)
},
unmounted() {
froala.destroyAllInstances()
},
When i print out this.froala.instance on console, it prints an empty array
But all works fine on create mode
What is the problem with this?
I have stored a userProfile in Vuex to be able to access it in my whole project. But if I want to use it in the created() hook, the profile is not loaded yet. The object exists, but has no data stored in it. At least at the initial load of the page. If I access it later (eg by clicking on a button) everything works perfectly.
Is there a way to wait for the data to be finished loading?
Here is how userProfile is set in Vuex:
mutations: {
setUserProfile(state, val){
state.userProfile = val
}
},
actions: {
async fetchUserProfile({ commit }, user) {
// fetch user profile
const userProfile = await fb.teachersCollection.doc(user.uid).get()
// set user profile in state
commit('setUserProfile', userProfile.data())
},
}
Here is the code where I want to acess it:
<template>
<div>
<h1>Test</h1>
{{userProfile.firstname}}
{{institute}}
</div>
</template>
<script>
import {mapState} from 'vuex';
export default {
data() {
return {
institute: "",
}
},
computed: {
...mapState(['userProfile']),
},
created(){
this.getInstitute();
},
methods: {
async getInstitute() {
console.log(this.userProfile); //is here still empty at initial page load
const institueDoc = await this.userProfile.institute.get();
if (institueDoc.exists) {
this.institute = institueDoc.name;
} else {
console.log('dosnt exists')
}
}
}
}
</script>
Through logging in the console, I found out that the problem is the order in which the code is run. First, the method getInstitute is run, then the action and then the mutation.
I have tried to add a loaded parameter and played arround with await to fix this issue, but nothing has worked.
Even if you make created or mounted async, they won't delay your component from rendering. They will only delay the execution of the code placed after await.
If you don't want to render a portion (or all) of your template until userProfile has an id (or any other property your users have), simply use v-if
<template v-if="userProfile.id">
<!-- your normal html here... -->
</template>
<template v-else>
loading user profile...
</template>
To execute code when userProfile changes, you could place a watcher on one of its inner properties. In your case, this should work:
export default {
data: () => ({
institute: ''
}),
computed: {
...mapState(['userProfile']),
},
watch: {
'userProfile.institute': {
async handler(institute) {
if (institute) {
const { name } = await institute.get();
if (name) {
this.institute = name;
}
}
},
immediate: true
}
}
}
Side note: Vue 3 comes with a built-in solution for this pattern, called Suspense. Unfortunately, it's only mentioned in a few places, it's not (yet) properly documented and there's a sign on it the API is likely to change.
But it's quite awesome, as the rendering condition can be completely decoupled from parent. It can be contained in the suspensible child. The only thing the child declares is: "I'm currently loading" or "I'm done loading". When all suspensibles are ready, the template default is rendered.
Also, if the children are dynamically generated and new ones are pushed, the parent suspense switches back to fallback (loading) template until the newly added children are loaded. This is done out of the box, all you need to do is declare mounted async in children.
In short, what you were expecting from Vue 2.
The reason why I am writing here because I just got a job as a front-end developer and on the first day they threw at me a big project and I lost, very lost, hopeless.
My job would be that I am having a home page where there is a table with some information for example date, hours, the daily wind speed, daily celsius, and under the table there would be information which can be generated from a config panel.
So basically with Vue-router am having two pages, one with the home and one with the config panel, now in the config panel I am having a form where you can write your text you want to display to the home page and my problem is that I have no clue how to display that text from one router to another I tried to make a method where on submitting the form it should somehow commit that message to my Vuex state but when I am about to write it out to the home page it is now showing,
This is what I have in my modules (vuex file) :
const state = {
message: '',
};
const getters = {
message: (state) => {
return state.message;
},
};
const actions = {
setMessage: ({
commit,
state
}, newValue) => {
commit('SET_MESSAGE', newValue);
return state.message;
},
};
const mutations = {
SET_MESSAGE: (state, newValue) => {
state.message = newValue;
console.log(state.message);
},
};
export default {
state,
getters,
actions,
mutations,
};
when I am console logging the state.message the text which got submitted is there now I need to put this text to my homepage, please help me with that I know that this should be an easy one but I cannot solve it.
On home page you should add
created() {
this.$store.dispatch('SET_MESSAGE');
}
This code will call SET_MESSAGE
computed: {
...mapGetters({
message: 'message',
}),
}
After adding this part you can take message value simple call "this.message" in methods or "message" in template
I have a Vue application in which i display list of events and every event individually, when i visit the page of the selected link i get an error in my console says GET http://localhost:1337/undefined 404 (Not Found) then the image loads
i used this method to set the id of the event to the component
export default {
data: function() {
return {
id: this.$route.params.id,
e: {},
users: []
}
},
methods: {
issueTicket: function(id, user) {
}
},
created(){
this.$http.get('http://localhost:1337/api/v1/event/find', { params : { id : this.id } }).then(result => {
this.e = result.body.result[0];
})
}
}
is there a way to get rid of this error ? i'm kind of new to Vue JS
You should add your frontend code, in order to make clear where the error occurs.
A first wild guess: You try to access an image like
<img :src="e.img">
However, your e has no .img property until it's loaded. So you might want to consider to set
e: null
Initially and add a v-if for your page
<div class="this is your page div" v-if="e">
<img :src="e.img">
...
This will ensure that you are not accessing undefined properties of e
In addition you should consider not mixing code styles
created() { .. }
vs
created: function() { ... }
I am trying to call a parent/root level method on a child component in Vue.js, but I keep getting a message saying TypeError: this.addStatusClass is not a function.
Vue.component('spmodal', {
props: ['addStatusClass'],
created: function() {
this.getEnvironments();
},
methods: {
getEnvironments: function() {
this.addStatusClass('test');
}
}
});
new Vue({
el: '#app',
methods: {
addStatusClass(data) {
console.log(data);
}
}
});
Here is a full JSBIN example: http://jsbin.com/tomorozonu/edit?js,console,output
If I call this.$parent.addStatusClass('test'); it works fine, but based on the Vue.js documentation, this is bad practice and I should be using props which is not working.
specifying the prop does nothing on its own, you have to actually pass something to it from the parent - in this case, the function.
<spmodal :add-status-class="addStatusClass"></spmodal>