VueJS/Vuetify: Change colwidth with animation/transition - vue.js

this is my app component:
<template>
<v-app id="inspire">
<v-main>
<v-container fluid>
<v-row>
<v-col :cols="dynamicCol">
<worldmap></worldmap>
</v-col>
</v-row>
</v-container>
</v-main>
</v-app>
</template>
<script>
import WorldMap from "./components/WorldMap";
export default {
props: {
source: String
},
components: {
worldmap: WorldMap
},
computed: {
changeDynamicCol() {
return this.$store.state.lineData.data.length;
}
},
watch: {
changeDynamicCol(value) {
if (value > 0) {
this.dynamicCol = 9;
}
}
},
data: () => ({
dynamicCol: 12,
drawer: null
}),
created() {
this.$vuetify.theme.dark = true;
}
};
</script>
<style scoped></style>
My App starts with an empty array and when I receive data, the first container small shrink from a width of 12 to 9. The code itself works fine, however the chart inside reacts to changes in the viewport, so get´s currently just cut off. In general it looks much better when this is animated.
Does anyone know if and how I can change the width of v-col with a transition or other animation?

I think you use watchers in wrong way.
Here I show how I see your case, but I don't sure if it works fine.
If you have more question, I can answer in comments
<template>
<v-app id="inspire">
<v-main>
<v-container fluid>
<v-row>
<v-col :cols="columnCount">
<worldmap></worldmap>
</v-col>
</v-row>
</v-container>
</v-main>
</v-app>
</template>
<script>
import WorldMap from "./components/WorldMap";
import { mapState } from 'vuex'
export default {
props: {
source: String
},
components: {
worldmap: WorldMap
},
computed: {
...mapState({
lineData: state => state.lineData.data.length
}),
columnCount() {
if (this.lineData > 0) {
return 9
}
return 12
}
},
data: () => ({
drawer: null
}),
};
</script>

Related

Opening a modal component with a button in another ccomponent using Vuetify

I have 2 components. Modal and Navbar. I'm trying to open Modal using a button in Navbar using vuex. I have a state called modalIsOpen. This states value changes from false to true when clicked on the button in Navbar but only a blank row is rendered as a modal and modal content is not shown. I could not figure out what is wrong.
At the beginning i thought it was a vuetify v-dialog problem. But ive tried other libraries too. And as i said nothing worked yet.
Here is the components ,app.vue and store.js.
AddUpdateModal.vue:
<template>
<v-dialog>
<v-card width="50%" height="50%">
<v-card-title class="text-h5 grey lighten-2">
Privacy Policy
</v-card-title>
<v-card-text>
Lorem
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="primary" text #click="dialog = false">
I accept
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
export default {
name: "AddUpdateModal",
components: {},
data: () => ({}),
}
</script>
<style>
.v-card {
display: block !important;
}
.v-easy-dialog {
height: 500px !important;
}
</style>
NavBar.vue:
<template>
<div id="Navbar">
<v-row>
<v-btn color="primary" #click.stop="openModal" rounded>
Add / Update
</v-btn>
<v-btn color="primary" #click="closeModal" rounded>
Refresh
</v-btn>
</v-row>
<v-row>
<v-divider class="grey darken-4"></v-divider>
</v-row>
</div>
</template>
<script>
export default {
name: 'NavBar',
components: {},
data: () => ({}),
methods: {
openModal() {
this.$store.commit('openModal');
},
closeModal() {
this.$store.commit('closeModal')
}
},
}
</script>
App.vue:
<template>
<v-app>
<v-container>
<NavBar />
<br>
<div class="parent">
<!-- <AddButton></AddButton> -->
<v-btn #click="konsol">Konsol</v-btn>
<div id="modal" v-if="$store.state.modalIsOpen">
<template>
<AddUpdateModal></AddUpdateModal>
</template>
</div>
<v-row>
<v-col>
<DataTable />
</v-col>
<v-divider class="grey darken-4" vertical inset></v-divider>
<v-col>
<PieChart />
</v-col>
</v-row>
</div>
</v-container>
</v-app>
</template>
<script>
import NavBar from './components/NavBar.vue';
import PieChart from './components/PieChart.vue';
import DataTable from './components/DataTable.vue';
// import AddButton from './components/AddButton';
import AddUpdateModal from './components/AddUpdateModal';
// eslint-disable-next-line no-unused-vars
import store from './store/store'
// import axios from 'axios';
export default {
name: 'App',
components: {
NavBar,
AddUpdateModal,
PieChart,
DataTable,
// AddButton,
},
created() {
this.$store.dispatch("initApp")
},
data: () => ({
}),
methods: {
konsol() {
console.log("modalIsOpen", this.$store.state.modalIsOpen)
}
},
};
</script>
<style>
* {
margin: 5px;
}
.v-dialog__container {
display: unset !important;
position: relative !important;
}
</style>
store.js:
import Vue from "vue";
import Vuex from "vuex";
import axios from "axios";
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
binance24HrData: [],
modalIsOpen: false,
},
mutations: {
initPortfolioDetails(state, newCoin) {
state.binance24HrData = newCoin;
},
openModal(state) {
state.modalIsOpen = true;
},
closeModal(state) {
state.modalIsOpen = false;
},
},
actions: {
initApp(context) {
axios
.get("https://api2.binance.com/api/v3/ticker/24hr")
.then((response) => {
context.commit("initPortfolioDetails", response.data);
console.log("Binance", response.data);
});
},
openModal({ commit }) {
commit("openModal");
},
closeModal({ commit }) {
commit("closeModal");
},
},
getters: {
getCoinsDetails(state) {
return state.binance24HrData;
},
},
});
export default store;
main.js:
import Vue from "vue";
import App from "./App.vue";
import vuetify from "./plugins/vuetify";
import store from "./store/store.js";
Vue.config.productionTip = false;
new Vue({
vuetify,
store,
render: (h) => h(App),
}).$mount("#app");
I figured it out: all I had to do was add v-model to v-dialog. I thought it was unnecessary because I already had a v-if that wrapped the component containing the v-dialog. I assumed that with this requirement fulfilled, it should render the child component, but it didn't because I didn't have v-model in v-dialog.

lag Nuxt dynamic import component

How to dynamically load components?
When opening page, they are drawn gradually/slowly
I want to draw components before rendering the page
My code:
<template>
<v-row>
<v-col
cols="12"
md="4"
v-for="element in elements" v-bind:key="element.id"
>
<component :is="element.elementName"></component>
</v-col>
</v-row>
</template>
<script>
export default {
data() {
return {
elements: null,
}
},
methods: {
getElements() {
this.$axios.post('/api/elements').then(response => {
this.elements = response.data
})
}
},
created() {
this.getElements()
},
}
</script>

props date is null on submit with v-date-picker and Vue 2.6

Hello i'm trying to get the props date from children component Datepicker to the parent component Form but everytime when i submit i have date:null in console log.
I don't understand how to fecth it please ?
i'm using Vue 2.6 to use Vuetify with this datepicker
https://vuetifyjs.com/en/components/date-pickers/#formatting
here is the code :
<template>
<v-container>
<v-row>
<v-col cols="12" lg="6">
<v-menu v-model="menu" :close-on-content-click="false" transition="scale-transition" offset-y max-width="290px" min-width="auto">
<template v-slot:activator="{ on, attrs }">
<v-text-field v-model="computedDateFormatted" persistent-hint prepend-icon="mdi-calendar" readonly v-bind="attrs" v-on="on"></v-text-field>
</template>
<v-date-picker v-model="date" no-title #input="menu = false"></v-date-picker>
</v-menu>
</v-col>
</v-row>
</v-container>
</template>
<script>
export default {
name: "DatePicker",
// props: { date: { type: String } },
data: (vm) => ({
date: new Date(Date.now() - new Date().getTimezoneOffset() * 60000).toISOString().substr(0, 10),
dateFormatted: vm.formatDate(new Date(Date.now() - new Date().getTimezoneOffset() * 60000).toISOString().substr(0, 10)),
menu: false,
}),
computed: {
computedDateFormatted() {
return this.formatDate(this.date)
},
},
watch: {
date() {
this.dateFormatted = this.formatDate(this.date)
},
},
methods: {
formatDate(date) {
if (!date) return null
const [year, month, day] = date.split("-")
return `${month}/${day}/${year}`
},
parseDate(date) {
if (!date) return null
const [month, day, year] = date.split("/")
return `${year}-${month.padStart(2, "0")}-${day.padStart(2, "0")}`
},
},
}
</script>
<style lang="scss" scoped></style>
and the form component
<template>
<div>
<v-main>
<v-container class="white form-container">
<v-form
method="POST"
ref="form"
lazy-validation
#submit.prevent="postForm">
<!-- Datepicker -->
<v-row no-gutters>
<v-col sm="6" md="5" lg="5" class="bottom-row">
<v-label>Add a date</v-label>
<DatePicker :date="date" />
</v-col>
</v-row>
</v-form>
</v-container>
</v-main>
</div>
</template>
<script>
import axios from "axios"
import DatePicker from "./DatePicker.vue"
export default {
name: "Form",
components: {
DatePicker,
},
data() {
return {
date: null,
}
},
methods: {
async postForm(event) {
/**
* #param json
*/
const data = {
date: this.date,
}
const result = await axios.post("url", data)
console.log("Post date", data)
event.preventDefault()
},
},
}
</script>
<style lang="scss" scoped></style>

Vuejs - Same component with different data

I am trying to re-use the same component, but load the components with different data. I thought simply providing unique id's would do the trick, but no luck. I switched from a Vuex store for this data, to using a dataShare This is what I'm doing:
The components:
<logoHeader :panel=0 title="Add your logo / header" id="top" topPadding="pt-10" />
<logoHeader :panel=1 title="Add your main image" id="main" topPadding="pt-0"/>
So its the exact same component, with some different props and different ids
This is the logoHeader component:
<template>
<v-row
:class="topPadding"
align="center"
justify="center"
>
<v-col
align="center"
justify="center"
cols="12"
>
<v-hover v-slot:default="{ hover }">
<v-card
:elevation="hover ? 12 : 0"
class="mx-auto"
max-width="600"
>
<v-img
v-if="showImage"
:src="imageUrl"
max-width="600px"
class="pointer"
#click="panel = 0"
>
</v-img>
<v-icon
v-if="!showImage"
class="my_dark_purple_text"
size="100"
#click="sendToPanel"
>add_box</v-icon>
<p class="my_dark_purple_text">{{ title }}</p>
<p>URL {{ imageUrl }}</p>
<p>Show image? {{ showImage }}</p>
</v-card>
</v-hover>
</v-col>
</v-row>
</template>
<script>
import {mapGetters} from 'vuex';
import {mapActions} from 'vuex';
import {dataShare} from '../../../packs/fresh-credit.js';
export default {
props: ['panel', 'title', 'topPadding'],
data() {
return {
imageUrl: "",
showImage: false,
}
},
created() {
dataShare.$on('imageUrl', (data) => {
this.imageUrl = data;
});
dataShare.$on('showImage', (data) => {
this.showImage = data;
});
},
computed: {
...mapGetters('emailPanel', [
'returnPanel'
]),
},
methods: {
...mapActions('emailPanel', [
'updatePanel'
]),
sendToPanel() {
this.updatePanel(this.panel);
},
},
}
</script>
And then finally this is where the data enters the system:
<template>
<v-expansion-panel-content>
<h1 class="subtitle-1 font-weight-bold">Only images files accepted</h1>
<v-file-input
v-model="image"
accept="image/*"
label="Image Upload"
prepend-icon="add_a_photo"
color='#68007d'
></v-file-input>
<v-btn
:disabled="disableUpload"
color="#68007d"
class="white--text"
#click="sendImage"
>Submit</v-btn>
</v-expansion-panel-content>
</template>
<script>
import axios from 'axios';
import {dataShare} from '../../../../packs/fresh-credit.js';
export default {
data() {
return {
image: null,
disableUpload: true,
}
},
watch: {
image: function() {
if(this.image.size > 0){
this.disableUpload = false;
}
else{
this.disableUpload = true;
}
}
},
computed: {
},
methods: {
sendImage() {
let formData = new FormData();
formData.append('file', this.image);
axios.post('/admin/features/images', formData,
{
headers: {
'Content-Type': 'multipart/form-data'
}
}
).then(response => {
dataShare.$emit('imageUrl', response.data);
dataShare.$emit('showImage', true);
});
}
},
}
</script>
Where did I go astray?
Add the key property to the components and set it to different values (for example 1 and 2). If the key has different values Vue will differentiate them when rendering. Here is a basic explanation.

Vue Random Router Component

{
path: '/link_1',
name: 'link_1',
component: () => import('./views/Link1.vue')
},
It is possible to have it one path like /link_1 but every time when go to this route load different component.
Like: First time when go to /link_1 load Link1.vue and second time when user go to /link_1 load and display Link2.vue.
You can use a combination of watch and <component> to render a dynamic component each time the link is clicked.
For example, this generates 100 components named component1 through component100, rendering one at random each time the <router-link></router-link> is clicked:
Vue.use(VueRouter)
const router = new VueRouter({
routes: [{
path: '/random/:id'
}]
})
const components = Array.from(Array(100), (x, i) => {
return {
name: `component${ i+ 1 }`,
props: ['lorem'],
template: `
<v-card>
<v-card-title>
<v-avatar>
<span class="blue-grey--text headline">${i + 1}</span>
</v-avatar>
</v-card-title>
<v-divider></v-divider>
<v-card-text>
<v-container fluid>
<v-layout justify-center>
<v-flex>
<span class="subheader" v-html="lorem"></span>
</v-flex>
</v-layout>
</v-container>
</v-card-text>
</v-card>
`
}
}).reduce((carry, c) => {
carry[c.name] = c
return carry
}, {})
new Vue({
el: '#app',
components,
router,
computed: {
current() {
return `component${this.cid}`
}
},
data() {
return {
cid: 1,
lorem: 'What mystery does the next page hold?'
}
},
watch: {
'$route': {
handler: function() {
let id = this.cid
while (this.cid === id) {
id = Math.floor(Math.random() * 100) + 1
}
this.cid = id
fetch('https://baconipsum.com/api/?type=all-meat&paras=3&format=html').then(res => res.text()).then(data => {
this.lorem = data
})
}
}
}
})
<link href='https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons' rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.21/vue.js"></script>
<script src="https://unpkg.com/vue-router#3.0.2/dist/vue-router.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.js"></script>
<div id="app">
<v-app>
<v-container>
<v-toolbar app>
<v-toolbar-items>
<v-btn :to="`/random/${cid}`" color="deep-orange darken-4" dark>Click Me</v-btn>
</v-toolbar-items>
</v-toolbar>
<v-content>
<v-slide-x-transition leave-absolute mode="out-in">
<component :is="current" :lorem="lorem"></component>
</v-slide-x-transition>
</v-content>
</v-container>
</v-app>
</div>