I have a this App component
<template>
<div id="app">
<Component1 #addItem="addItem" />
<Component2 :items="items" />
</div>
</template>
<script>
import Component1 from './components/Component1'
import Component2 from './components/Component2'
export default {
name: 'app',
components: { Component1, Component2 },
data: function () {
return {
items: [],
}
},
methods: function () {
addItem(item) {
items.push(item)
},
},
}
</script>
This is my Component2 component:
<template>
<div>
{{ ajax_data }}
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'Component2',
props: ['items'],
data: function () {
return {
ajax_data: null
}
},
mounted () {
this.callAJAX()
},
methods: {
callAJAX() {
axios
.get('/api/get-some-data', {
params: {
items: items
}
})
.then((response) => {
this.ajax_data = response.data
})
},
},
}
</script>
I want to trigger the AJAX everytime I add an item. The problem with my code is since Component2 is already mounted and when an item is added the AJAX is not running. So then I added this hook:
updated () {
this.callAJAX()
},
The problem with this is its running an infinite loop.
Is there a proper way to do this?
You can simply detect if value change with a watcher
https://v2.vuejs.org/v2/guide/computed.html#Watchers
https://v2.vuejs.org/v2/api/#watch
in your case, you may set the deep property to true...
Related
I want to fetch data everytime when props changes in component and display it without reloading page.
pages/invoice/index.vue:
<template>
<div>
<b-table-column
field="InvoiceNo"
label="Invoice No"
sortable
v-slot="props"
>
<a #click="selectInvoice(props.row.id)">
{{ props.row.invoiceNumber }}
</a>
</b-table-column>
<Invoice :invoiceId="selectedInvoice" />
</div>
</template>
<script>
import axios from "axios";
import Invoice from "../../../components/Invoice.vue";
export default {
components: {
Invoice,
},
data() {
return {
selectedInvoice: "",
}
},
methods: {
selectInvoice(invoiceId) {
this.selectedInvoice = invoiceId;
},
}
}
</script>
components/Invoice.vue:
<script>
import axios from "axios";
export default {
props: ["invoiceId"],
data() {
return {
invoiceData: "",
};
},
watch: {
invoiceId: function (newVal, oldVal) {
this.fetchData(newVal)
},
deep: true,
immediate: true,
},
methods: {
async fetchData(invoiceId) {
let { data: invoiceDetails } = await axios.get(
`${process.env.backendapi}/invoice/byid?invoiceId=${invoiceId}`
);
return {
invoiceData: invoiceDetails,
};
},
},
};
</script>
When I select/change invoice, I can see the backend api getting called everytime with selected invoice, but invoiceData is always blank. The returned result is not getting updated in invoiceData.
I think you want the following in the fetchData method
this.invoiceData = invoiceDetails
Instead of
return {}
Only the already existing data and fetch vue/nuxt functions need to return an object
The problem I need to solve: I am writing a little vue-app based on VueJS3.
I got a lot of different sidebars and I need to prevent the case that more than one sidebar is open at the very same time.
To archive this I am following this article.
Now I got a problem:
Vue received a Component which was made a reactive object. This can lead to unnecessary performance overhead, and should be avoided by marking the component with markRaw or using shallowRef instead of ref. (6)
This is my code:
SlideOvers.vue
<template>
<component :is="component" :component="component" v-if="open"/>
</template>
<script>
export default {
name: 'SlideOvers',
computed: {
component() {
return this.$store.state.slideovers.sidebarComponent
},
open () {
return this.$store.state.slideovers.sidebarOpen
},
},
}
</script>
UserSlideOver.vue
<template>
<div>test</div>
</template>
<script>
export default {
name: 'UserSlideOver',
components: {},
computed: {
open () {
return this.$store.state.slideovers.sidebarOpen
},
component () {
return this.$store.state.slideovers.sidebarComponent
}
},
}
</script>
slideovers.js (vuex-store)
import * as types from '../mutation-types'
const state = {
sidebarOpen: false,
sidebarComponent: null
}
const getters = {
sidebarOpen: state => state.sidebarOpen,
sidebarComponent: state => state.sidebarComponent
}
const actions = {
toggleSidebar ({commit, state}, component) {
commit (types.TOGGLE_SIDEBAR)
commit (types.SET_SIDEBAR_COMPONENT, component)
},
closeSidebar ({commit, state}, component) {
commit (types.CLOSE_SIDEBAR)
commit (types.SET_SIDEBAR_COMPONENT, component)
}
}
const mutations = {
[types.TOGGLE_SIDEBAR] (state) {
state.sidebarOpen = !state.sidebarOpen
},
[types.CLOSE_SIDEBAR] (state) {
state.sidebarOpen = false
},
[types.SET_SIDEBAR_COMPONENT] (state, component) {
state.sidebarComponent = component
}
}
export default {
state,
getters,
actions,
mutations
}
App.vue
<template>
<SlideOvers/>
<router-view ref="routerView"/>
</template>
<script>
import SlideOvers from "./SlideOvers";
export default {
name: 'app',
components: {SlideOvers},
};
</script>
And this is how I try to toggle one slideover:
<template>
<router-link
v-slot="{ href, navigate }"
to="/">
<a :href="href"
#click="$store.dispatch ('toggleSidebar', userslideover)">
Test
</a>
</router-link>
</template>
<script>
import {defineAsyncComponent} from "vue";
export default {
components: {
},
data() {
return {
userslideover: defineAsyncComponent(() =>
import('../../UserSlideOver')
),
};
},
};
</script>
Following the recommendation of the warning, use markRaw on the value of usersslideover to resolve the warning:
export default {
data() {
return {
userslideover: markRaw(defineAsyncComponent(() => import('../../UserSlideOver.vue') )),
}
}
}
demo
You can use Object.freeze to get rid of the warning.
If you only use shallowRef f.e., the component will only be mounted once and is not usable in a dynamic component.
<script setup>
import InputField from "src/core/components/InputField.vue";
const inputField = Object.freeze(InputField);
const reactiveComponent = ref(undefined);
setTimeout(function() => {
reactiveComponent.value = inputField;
}, 5000);
setTimeout(function() => {
reactiveComponent.value = undefined;
}, 5000);
setTimeout(function() => {
reactiveComponent.value = inputField;
}, 5000);
</script>
<template>
<component :is="reactiveComponent" />
</template>
I have got a wrapper around a package called vue-awesome-swiper, as follows:
Slider.vue
<template>
<div class="media-slider">
<slot :sliderSetting="sliderSettings" :name="name">
<swiper :options="sliderSettings[name]"
class="swiper"
v-if="slides"
ref="default-slider">
<slot name="slides" :slides="slides" :code="code">
<swiper-slide v-for="image in slides" :key="image" v-if="endpoint"
:style="{'background-image': `url('${image}')`}">
</swiper-slide>
</slot>
<div class="swiper-button-next swiper-button-white" slot="button-next"></div>
<div class="swiper-button-prev swiper-button-white" slot="button-prev"></div>
<div class="swiper-pagination" slot="pagination"></div>
<div class="swiper-scrollbar" slot="scrollbar"></div>
</swiper>
</slot>
</div>
</template>
<script>
import { Swiper, SwiperSlide } from 'vue-awesome-swiper';
import 'swiper/css/swiper.css';
import Axios from '../../../../axiosConfig';
// https://github.surmon.me/vue-awesome-swiper/
export default {
components: { Swiper, SwiperSlide },
data: function() {
return {
code: null,
images: [],
defaults: {
'default-slider': {
loop: true,
loopedSlides: 5,
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev'
},
scrollbar: {
el: '.swiper-scrollbar',
hide: true
}
}
},
sliderSettings: {}
}
},
props: {
endpoint: {
type: String,
default: null
},
settings: {
type: Object,
default: {}
},
theme: {},
name: {},
hash: {},
numberOfImages: {},
imageFormat: {},
vehicleId: {}
},
computed: {
slides() {
if (this.images.length) {
return this.images;
}
return [...Array(parseInt(this.numberOfImages))].map(
(_, i) => {
i++;
return this.imageFormat.replace('#', i);
}
);
}
}
}
</script>
As you can see I have got a slot within this component, however it must use an instance of SwiperSlide for it to work. I need to register this as a component to use it.
However this isn't working as expected:
Vue.component('slider', () => import('./components/Media/Slider/Index'));
Vue.component('slide', () => import('vue-awesome-swiper'));
How can I do this?
Edit
<slider class="app">
<template v-slot:slides="props">
<slide :style="{'background-image': `url('img-src/${props.code}/theme/slide-1.jpg')`}"></slide>
</template>
</slider>
An import like this import() is gonna import the default export of the package, what you have done here is that you have destructured the import with import { .. } from ".." that means it has an named export.
However try it like this
Vue.component('slider', () => import('./components/Media/Slider/Index'));
Vue.component('slide', async () => (await import('vue-awesome-swiper')).SwiperSlide);
I'm using chartkick in my Vue project. Right now, the data is loading from Firebase after the chart has rendered, so the chart is blank. When I change the code in my editor, the chart renders as expected, since it's already been retrieved from Firebase. Is there a way to make chartkick wait for the data to load before trying to render the chart? Thanks!
Line-Chart Component:
<template>
<div v-if="loaded">
<line-chart :data="chartData"></line-chart>
</div>
</template>
<script>
export default {
name: 'VueChartKick',
props: ['avgStats'],
data () {
return {
loaded: false,
chartData: this.avgStats
}
},
mounted () {
this.loaded = true
}
}
</script>
Parent:
<template>
...
<stats-chart v-if="avgStatsLoaded" v-bind:avgStats="avgStats" class="stat-chart"></stats-chart>
<div v-if="!avgStatsLoaded">Loading...</div>
...
</template>
<script>
import StatsChart from './StatsChart'
export default {
name: 'BBall',
props: ['stats'],
components: {
statsChart: StatsChart
},
data () {
return {
avgStatsLoaded: false,
avgStats: []
}
},
computed: {
sortedStats: function () {
return this.stats.slice().sort((a, b) => new Date(b.date) - new Date(a.date))
}
},
methods: {
getAvgStats: function () {
this.avgStats = this.stats.map(stat => [stat.date, stat.of10])
this.avgStatsLoaded = true
}
},
mounted () {
this.getAvgStats()
}
}
modify your code of StatsChart component:
you may use props directly
<template>
<div v-if="loaded">
<line-chart :data="avgStats"></line-chart>
</div>
</template>
export default {
name: 'VueChartKick',
props: ['avgStats'],
data () {
return {
loaded: false,
}
},
mounted () {
this.loaded = true
}
}
I have a button in parent component template like below.
<template>
<div class="data_table">
<button class="mini ui button" #click="show">
</div>
</template>
This show() is kept in child component like below
<script>
export default {
data:
function () {
return {
value: this.active1
}
},
props: {
active1: true
},
methods: {
show () {
this.active1 = true
}
},
}
</script>
How can I call that show() function ?
I am using vue-cli.
Thanks
Child Component
<template>
<div class="data_table">
<button class="mini ui button" #click="show">
</div>
</template>
data: => ({
value: this.active1
}),
props: {
active1: {
type: Boolean
}
},
methods: {
show () {
this.$emit('someEventName')
}
}
Parent Component
<template>
<child-component
:active1="booleanValue"
#someEventName="show"
/>
</template>
data: => ({
booleanValue: false
}),
method: {
show () {
this.booleanValue = true
}
}