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>
Related
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>
It's possible to does a pagination with asyncData in nuxt?
I have this code:
<template>
<v-container fluid>
<v-row>
<v-col
v-for="sessao in sessoes"
:key="sessao.id"
xs="12"
sm="12"
md="6"
lg="4"
>
<FotografoSessao :sessao="sessao" :is-mostrar-titulo="true" />
</v-col>
</v-row>
<v-row>
<v-container class="max-width">
<v-pagination
v-model="paginaAtual"
:length="totalPages"
:total-visible="10"
#input="proximo"
></v-pagination>
</v-container>
</v-row>
</v-container>
</template>
<script>
export default {
async asyncData({ $api, store, route }) {
let url = "/sessao/ultimas";
if (store.state.auth.isLogged) {
url = "/sessao/praias/usuario";
}
const page = parseInt(route.query.page);
const retorno = await $api.get(`${url}?page=${page - 1}`);
return {
sessoes: retorno.data.content,
totalPages: retorno.data.totalPages,
totalItems: retorno.data.content.totalItems,
paginaAtual: parseInt(page),
};
},
data() {
return {};
},
watchQuery: ["page"],
methods: {
proximo(val) {
const page = parseInt(val);
this.$router.push({ path: this.$route.path, query: { page: page } });
},
recuperarImagem(prop) {
return "data:image/png;base64," + prop;
},
},
};
</script>
So when I navigate to page the content show fine. but when I click to go to next page "proximo" Method, the asyncData are executed (because in my back I have the log) but the page are not updated
First, remove this part:
data() {
return {};
},
And the query is directly available as follows:
async asyncData({ $api, store, query }) {
const page = parseInt(query.page);
// ...
}
I am making a "create account" flow for user and I am not able to pass data from one component to another. The first component has radio buttons with options of "tenant", "landlord", "contractor". Once the user selects "tenant", then the data should pass to the next step where they fill out a form with name and all that good stuff.. once they submit, it should all go together to the back end.
acc-for.vue with radio buttons component below.
<template>
<div>
<v-app
style="background-image: url('https://blog.modsy.com/wp-content/uploads/2019/06/D2_Full.jpg')"
>
<v-container class="pa-12">
<v-row>
<v-card class="pa-16">
<v-card-title>
Are you a?
</v-card-title>
<v-radio-group v-model="selectedValue" #change="selectedAcc">
<v-radio
v-for="account in accountType"
:key="account.name"
:value="account.name"
:label="account.name"
></v-radio>
</v-radio-group>
<v-row>
<v-btn rounded color="black" class="white--text" href="/login"
>Back</v-btn
>
<v-btn
rounded
color="black"
class="white--text"
#click="selected(accountSelected)"
>Next</v-btn
>
<!-- href="/create-acc" -->
</v-row>
</v-card>
</v-row>
</v-container>
</v-app>
</div>
</template>
<script>
import { mapMutations } from "vuex";
export default {
data() {
return {
selectedValue: false,
};
},
computed: {
accountType() {
return this.$store.state.accountType;
},
selected() {
return this.$store.state.selectedAccType;
},
},
methods: {
...mapMutations(["SELECTED_ACCOUNT_TYPE"]),
selectedAcc(e) {
this.$emit("selected-accountType", e);
},
},
};
</script>
<style></style>
createAccount.vue this component has the form for the fName and lName and all that good stuff..
<template>
<div>
<v-app
style="background-image: url('https://blog.modsy.com/wp-content/uploads/2019/06/D2_Full.jpg')"
>
<v-container class="pa-12">
<v-row>
<v-card class="pa-16">
<v-card-title>
{{ selectedTypeUser }}
</v-card-title>
<v-form>
<v-text-field
class="pa-4"
type="text"
v-model="newUser_fName"
label="First Name"
/>
<v-text-field
class="pa-4"
type="text"
v-model="newUser_lName"
label="Last Name"
/>
<v-text-field
class="pa-4"
type="text"
v-model="newUser_email"
label="Email"
/>
<v-text-field
class="pa-4"
type="text"
v-model="newUser_password"
label="Password"
/>
<v-row>
<v-btn rounded color="black" class="white--text" href="/acc-for"
>Back</v-btn
>
<v-btn
#click="registerUser"
rounded
color="black"
class="white--text"
>Next</v-btn
>
</v-row>
</v-form>
</v-card>
</v-row>
</v-container>
</v-app>
</div>
</template>
<script>
import { mapMutations } from "vuex";
import axios from "axios";
export default {
data() {
return {
newUser_fName: "",
newUser_lName: "",
newUser_email: "",
newUser_password: "",
};
},
methods: {
...mapMutations(["ADD_USER"]),
registerUser() {
let config = {
headers: {
"Content-Type": "application/json",
},
};
axios
.post(
"http://localhost:7876/createUser",
{
fName: this.newUser_fName,
lName: this.newUser_lName,
email: this.newUser_email,
password: this.newUser_email,
},
config
)
.then((response) => {
console.log(response.statusText);
})
.catch((e) => {
console.log("Error: ", e.response.data);
});
},
},
};
</script>
store.js (state) is below
// import vue from "vue";
import vuex from "vuex";
import axios from "axios";
import Vue from "vue";
Vue.use(vuex, axios);
export default new vuex.Store({
state: {
users: [],
accountType: [
{ name: "Tenant" },
{ name: "Landlord" },
{ name: "Contractor" }
],
selectedAccType: [],
},
mutations: {
ADD_USER: (state, payload) => {
state.users.push(payload.user);
},
SELECTED_ACCOUNT_TYPE: (state, payload) => {
state.selectedAccType.push(payload)
}
},
actions: {
addUser: ({ commit }, payload) => {
commit("ADD_USER", payload);
},
selectAcc: ({ commit }, payload) => {
commit("SELECTED_ACCOUNT_TYPE", payload)
}
},
// getters: {
// addAccountType(state, e) {
// state.accountType.push(e)
// },
// },
});
I see this on the button:
<v-btn rounded
color="black"
class="white--text"
#click="selected(accountSelected)"
>Next</v-btn
>
But I'm not finding a method with that name in your attached code. Double check that your names are all matched up and that you are calling the correct function on the click event.
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>
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.