i have tried to using $on method and this.$root.$refs.compname_component = this; but got some errors,Please refer below my codes
formComponent.vue
<template>
<div v-if="showForm">
create Form
</div>
</template>
<script>
export default {
props:[],
setup(props) {
return props;
},
data() {
return {
formData:{},
showForm:false
}
},
created() {
// this.$root.$refs.tableCommon = this;
// this.$root.$refs.compname_component = this;
},
mounted() {
console.log('form mounted');
// this.$root.$on("displayForm", () => {
// this.displayForm();
// });
},
methods: {
displayForm:function(){
this.showForm = true;
}
},
}
</script>
commonComponent.vue
<template>
<div class="col-10 text-end custom-inline-spacing mb-3">
<button type="button" class="btn btn-outline-secondary" #click="showCreateForm">Create</button>
</div>
</template>
<script>
export default {
props: [],
setup() {
return {}
},
data() {
return {
}
},
mounted() {
console.log('mounted common')
},
methods: {
showCreateForm : function(){
// this.$refs.form.displayForm();
// this.$root.$refs.compname_component.displayForm();
// this.$root.$emit("displayForm");
this.createForm.displayForm();
}
}
}
</script>
app.js
require('./bootstrap')
import { createApp } from 'vue'
import tableCommon from './components/CommonComponent'
import createForm from './components/formComponent';
const app = createApp({})
app.component('vue-common', tableCommon);
app.component('create-form', createForm);
app.mount('#app')
actualy what i want means call formComponent.displayForm() from CommonComponent.
If you want to conditionally display child component, you can move logic out of that component into the parent component.
Parent.vue
<template>
<FormComponent v-if="showComponent" />
</template>
Alternatively, you can pass a prop into FormComponent if you need to conditionally display only a part of that component.
Parent.vue
<template>
<FormComponent v-bind:show-component="showComponent" />
</template>
FormComponent.vue
<template>
<div v-if="showComponent">
...
</div>
<div>
...
</div>
</template>
Related
I have created a Vue3 to-do list project with VueCLI(VueX) for practice. I can add items to the array of objects and display them from objects.
Now, I want to implement a delete function that when I click the delete button beside the item, it deletes the element and also removes the object from array.
Here is my code:
NoteInput.vue
<template>
<div>
<input
type="text"
v-model="inputValue"
#keyup.enter="addItem"
/>
</div>
</template>
<script>
import { ref } from 'vue'
import { useStore } from 'vuex'
export default {
setup() {
const inputValue = ref()
const store = useStore()
const addItem = () => {
if (inputValue.value !== '') {
store.commit('addItem', inputValue.value)
}
inputValue.value = ''
}
return {
inputValue,
addItem
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
</style>
NoteItem.vue
<template>
<div>
<div
v-for="(item, index) in list"
:key="index"
>
<span>{{item.title}}</span>
<span>
<button #click="deleteItem">Delete</button>
</span>
</div>
</div>
</template>
<script>
import { useStore } from 'vuex'
export default {
setup() {
const store = useStore()
const list = store.state.list
const deleteItem = () => {
// store.commit('deleteItem', this.item.title)
console.log()
}
return {
list,
deleteItem
}
}
}
</script>
store/index.js
import { createStore } from 'vuex'
export default createStore({
state: {
list: []
},
getters: {
},
mutations: {
addItem(state, item) {
state.list.push({
title: item,
status: 'normal'
})
},
deleteItem(state, item) {
}
},
actions: {
},
modules: {
}
})
Please modify your NoteItem.vue and store/index.js files as below.
Working codesandbox link https://codesandbox.io/s/vue-3-vuex-4-vue-router-forked-ei4x1r
NoteItem.vue
<template>
<div>
<div
v-for="(item, index) in list"
:key="index"
>
<span>{{item.title}}</span>
<span>
<button #click="deleteItem(index)">Delete</button>
</span>
</div>
</div>
</template>
<script>
import { useStore } from 'vuex'
export default {
setup() {
const store = useStore()
const list = store.state.list
const deleteItem = () => {
store.commit('deleteItem', index)
}
return {
list,
deleteItem
}
}
}
</script>
store/index.js
import { createStore } from 'vuex'
export default createStore({
state: {
list: []
},
getters: {
},
mutations: {
addItem(state, item) {
state.list.push({
title: item,
status: 'normal'
})
},
deleteItem(state, index) {
state = state.list.splice(index, 1);
}
},
actions: {
},
modules: {
}
})
I have a parent component containing three child components. The first child component is a form. On a submit event it passes data to both the second and third child components via the parent component using props. However in one of the child components, the prop is always undefined. I think it's a timing issue, but using v-if does not seem to solve the issue.
The Parent Component:
<template>
<div>
<patents-searchform v-on:form-submit="processForm"></patents-searchform>
<patents-word-cloud
v-if="searched"
v-show="searched"
:patentsQuery="patentsQuery"
:livePage="livePage"
v-on:pageChange="handlePageChange"
/>
<patents-search-results
v-if="searched"
v-show="searched"
ref="resultsRef"
:livePage="livePage"
:results="patentsQueryResult"
v-on:pageChange="handlePageChange"
</div>
</template>
export default {
data() {
return {
livePage: 1,
searched: false,
queryform: 'initVal',
patentsQueryResult: {},
searching: false,
patentsQuery: {}
};
},
components: {
'patents-searchform': PatentsSearchForm,
'patents-searchresults': PatentsSearchResults,
'patents-word-cloud': PatentsWordCloud,
},
methods: {
handlePageChange(value) {
console.log('Homepage::handlePageChange', value)
this.queryform.page = value;
this.livePage = value;
this.fetchData();
},
processForm(formData) {
this.queryform = formData;
this.fetchData();
this.patentsQuery['query'] = this.queryform['query']
this.patentsQuery['searchMode'] = this.queryform['searchMode']
this.searched = true;
},
fetchData() {
const path = '/flask/searchPatentsNEW';
this.searching = true;
if (this.queryform !== 'initVal') {
axios.post(path, this.queryform)
.then((res) => {
this.patentsQueryResult = res.data;
this.searching = false;
})
.catch((error) => {
console.log(error);
});
}
}
}
};
The child component (PatentSearchResults) in which the props work correctly:
<template>
<b-container>
<b-card>
<a id="sTitleCard">Search Results</a>
<div id="quickStats" style="margin-left: 5%" v-if="this.results.stats">
{{results.stats.totalAuthors}} inventors across {{results.stats.docCount}} patents
({{results.stats.totalQueryTime}} seconds)
</div>
</b-card>
</b-container>
</template>
<script>
export default {
name: 'Results',
props: ['results', 'livePage'],
computed: {
thisAuthorPage() {
if (this.results.authors !== null) {
return this.results.authors; //this.results works fine
}
console.log('no authors')
return [];
},
},
methods: {
},
};
</script>
And the child component where the props are undefined:
<template>
<div>
<b-card id="patentWordCloudCard" bg-variant="light">
<b-container>
<b-form id="queryForm" #submit="onSubmit" #reset="onReset" novalidate>
<b-row class="d-flex flex-row-reverse">
<b-button id="btnSubmit" type="submit" variant="primary">Generate query word cloud</b-button>
</b-row>
</b-form>
</b-container>
</b-card>
</div>
</template>
<script>
export default {
name: 'Patents Word Cloud',
props: ['patentsQuery'],
data() {
return{
form: {
query: this.patentsQuery.query,
searchMode: this.patentsQuery.searchMode
},
show: true,
}
},
mounted() {
console.log(this.patentsQuery) //undefined
},
computed() {
console.log(this.patentsQuery) //undefined
},
methods: {
onSubmit(evt) {
evt.preventDefault();
console.log(this.patentsQuery) //undefined
}
}
}
</script>
Is it a timing issue where the word cloud component is mounted before patentsQuery is defined? If so, why did v-if not delay the component, as searched is false until after patentsQuery is defined.
It was a timing issue, I was able to access patentsQuery with the following code:
<template>
<div>
<b-card id="patentWordCloudCard" bg-variant="light">
<b-container>
<b-form id="queryForm" align-h="center" #submit="onSubmit" #reset="onReset" novalidate>
<b-row align-h="center">
<b-button align-h="center" id="btnSubmit" type="submit" variant="primary">Generate query word cloud</b-button>
</b-row>
</b-form>
</b-container>
</b-card>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'Patents Word Cloud',
props: ['patentsQuery'],
methods: {
onSubmit(evt) {
evt.preventDefault();
const path = 'flask/patentWordCloud';
this.searching = true
axios.post(path, this.patentsQuery).then((res) => {
console.log('Patent Word Cloud Data')
console.log(res.data)
this.patentResults = res.data;
})
.catch((error) => {
console.log(error)
})
}
}
}
</script>
I need to bind the return from my method to my child template.
methods object
methods: {
filterOptions(checkedValues: any) {
let filtered = this.cards.filter(card => {
return card.profile
.map(profile => profile.salary)
.find(profileSalary => {
return checkedValues.find((salaryOption: number) => {
return profileSalary >= salaryOption;
});
});
});
}
}
template
<template>
<section id="app">
<Gallery v-bind:filtered="filtered"/>
</section>
</template>
You can pass an array of objects as a parameter to the child component.
See the docs.
Child
<template>
<div>
<span v-for="item in arr"
:key="item.id">{{ item.name }}</span>
</div>
</template>
<script>
export default {
name: 'Child',
params: {
arr: {
type: Array,
default: () => []
}
}
}
</script>
Parent
<template>
<div>
<child :arr="parentArray"/>
</div>
</template>
<script>
import Child from './Child.vue'
export default {
name: 'Parent',
components: {
Child
},
computed: {
parentArray () {
return [...whatever]
}
}
}
</script>
Am working on an SPA using Vuejs and Vuex. I'm setting some data in the store and showing it in a child component. In the child component, there are radio buttons, which when clicked, I call a function called getCalculations where I log the vehicle object but I keep getting undefined error. The child component is further embedded in parent component.
Vuex Store
const getDefaultState = () => {
return {
//Vehicle Data
vehicleData: {
reg_no: "KAS 234R",
chasis_number: "BGSHS-IUISUS",
engine_number: "MNVSS-8787SNS"
}
}
}
const state = getDefaultState()
//getters
const getters = {
vehicle: (state) => state.vehicleData
}
//actions
const actions = {
//......
}
//mutations
const mutations = {
// .....
}
export default {
state,
getters,
actions,
mutations
}
Parent Component
<template>
<div>
<vehicleFeature/>
</div>
</template>
<script>
import { mapGetters } from "vuex";
import vehicleFeature from "./partials/vehicleFeature";
export default {
name: "StepFour",
data() {
return {
//.....
};
},
computed: mapGetters(["vehicle"]),
components:{
vehicleFeature
}
</script>
Child Component
<template>
<div>
<form class="ipf_form">
<div class="inputGroup">
<input id="radio4" name="radio" #change="getcalculations" type="radio" value="4">
<label for="radio4">1 INSTALMENTS</label>
</div>
<div class="inputGroup">
<input id="radio5" name="radio" #change="getcalculations" type="radio" value="5" >
<label for="radio5">2 INSTALMENTS</label>
</div>
</form>
</div>
</template>
<script>
import { mapGetters } from "vuex";
export default {
name: "vehicleFeature",
data() {
return {
//.....
};
},
computed: {
...mapGetters(["vehicle"]),
principalamount(){
//.....
}
},
methods: {
getcalculations() {
console.log(this.vehicle.reg_no);
}
}
</script>
<style scoped>
</style>
simply change your code as:
const state = {
//Vehicle Data
vehicleData: {
reg_no: "KAS 234R",
chasis_number: "BGSHS-IUISUS",
engine_number: "MNVSS-8787SNS"
}
}
const getters = {
vehicle: (state) => state.vehicleData
}
and get vehicle state as:
...mapGetters(['vehicle'])
this.vehicle.reg_no
For some reason my $emit doesn't seem to be firing inside the parent. I am basically trying to create a modal popup for a html form. Inside my header component I have a button that fires $emit I then try to listen to this event inside my app.js on the form component. But the form component is doing nothing when the emit is fired.
Here's my code
client/src/app.js
<template>
<div id="app">
<MainHeader :modalVisability="modal" />
<OppForm :modalVisability="modal" v-on:showModal="modal = $event"/>
<div>{{ modal }}</div>
</div>
</template>
<script>
import MainHeader from './components/MainHeader.vue';
import OppForm from './components/oppForm.vue';
export default {
name: 'App',
components: {
MainHeader,
OppForm
},
data() {
return {
modal: false
}
}
}
</script>
client/components/MainHeader.vue
<template>
<div id="main_header_wrap">
<header>
<button v-on:click="showOppForm">Add Post</button>
</header>
<div>{{ modalVisability }}</div>
</div>
</template>
<script>
export default {
props: {
modalVisability: Boolean
},
methods: {
showOppForm() {
this.modalVisability = true;
this.$emit('showModal', this.modalVisability);
}
},
}
</script>
client/src/components/oppForm.vue
<template>
<div id="opp_form" >
<form #submit.prevent="SubmitOpp" v-if="modalVisability">
<input type="text" name="company_name" v-model="company_name">
<button type="submit">Submit</button>
</form>
<div>{{ modalVisability }}</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'oppForm',
props: {
modalVisability: Boolean,
},
data() {
return {
company_name: ''
}
},
methods: {
SubmitOpp() {
axios.post('http://localhost:5000/', {
company_name: this.company_name,
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
}
}
</script>
I fixed somethings in your code. See the example below:
client/src/app.js
<template>
<div id="app">
<MainHeader :modalVisability="modal" #showModal="changeModal" />
<OppForm :modalVisability="modal" />
<div>App = {{ modal }}</div>
</div>
</template>
<script>
import MainHeader from './components/MainHeader.vue';
import OppForm from './components/oppForm.vue';
export default {
name: 'App',
components: { MainHeader, OppForm },
data() {
return {
modal: false,
};
},
methods: {
changeModal(newValueModal) {
this.modal = newValueModal;
},
},
};
</script>
client/components/MainHeader.vue
<template>
<div id="main_header_wrap">
<header>
<button v-on:click="showOppForm">Add Post</button>
</header>
<div>MainHeader = {{ modalVisability }}</div>
</div>
</template>
<script>
export default {
props: {
modalVisability: Boolean,
},
methods: {
showOppForm() {
this.$emit('showModal', !this.modalVisability);
},
},
};
</script>
client/src/components/oppForm.vue
<template>
<div id="opp_form">
<form #submit.prevent="SubmitOpp" v-if="modalVisability">
<input type="text" name="company_name" v-model="company_name" />
<button type="submit">Submit</button>
</form>
<div>oppForm = {{ modalVisability }}</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'oppForm',
props: {
modalVisability: Boolean,
},
data() {
return {
company_name: '',
};
},
methods: {
SubmitOpp() {
axios
.post('http://localhost:5000/', {
company_name: this.company_name,
})
.then(function(response) {
console.log(response);
})
.catch(function(error) {
console.log(error);
});
},
},
};
</script>
1 - App.js: Listen the event in MainHeader component.
2 - App.js: OppForm don't need to listen the event, because this component don't change the modal value.
3 - MainHeader.vue: Avoid to change the props value.