I am using steppers in vue. I am creating an agency in step 1 and on step 2 I am displaying the agency details. The issue is that the agency details don't appear on step 2 until I refresh page after going on step 2. Is there a way to pass agency as a prop from agency.vue to event.vue so that I dont need to refresh the page to make the agency details appear on step 2.
stepper.vue
<template>
<div >
<v-stepper v-model="e1">
<v-stepper-header>
<v-stepper-step :complete="e1 > 1" step="1">Agency</v-stepper-step>
<v-divider></v-divider>
<v-stepper-step :complete="e1 > 2" step="2">Event</v-stepper-step>
<v-divider></v-divider>
</v-stepper-header>
<v-stepper-items>
<v-stepper-content step="1">
<Agency #next="goTo(2, true)"></Agency>
</v-stepper-content>
<v-stepper-content step="2">
<Event/>
</v-stepper-content>
</v-stepper-items>
</v-stepper>
</div>
</template>
<script>
import Agency from 'parties/agency';
import Event from 'events/event';
export default {
components: {
Agency,
Event
},
data () {
return {
e1: 0,
agency: {
id: '',
name: '',
phone_number: ''
}
}
},
created() {
this.step = 1;
this.getAgency();
},
methods: {
getAgency() {
this.$axios.get('/agency.json')
.then(response => {
if (Object.keys(response.data).length > 0) {
this.agency = response.data;
}
})
},
goTo(step, can) {
if (can) {
this.e1 = step;
}
},
}
};
</script>
agency.vue
<template>
<v-card>
<v-form :model='agency'>
<v-layout row wrap>
<v-flex xs12 sm12 lg12 >
<v-layout row wrap>
<v-flex xs12 md6 class="add-col-padding-right">
<v-text-field
label='Agency Name'
v-model='agency.name'>
</v-text-field>
</v-flex>
</v-layout>
<v-layout row wrap>
<v-flex xs12 md6 class="add-col-padding-right">
<v-text-field
label='Agency Phone Number'
v-model='agency.phone_number'>
</v-text-field>
</v-flex>
</v-layout>
<v-layout row wrap>
<div>
<v-btn #click.prevent='saveAgency'>Save</v-btn>
</div>
</v-layout>
</v-flex>
</v-layout>
</v-form>
<v-btn #click.prevent='nextStep'>
Next
</v-btn>
</v-card>
</template>
<script>
export default {
data: function () {
return {
agency: {
id: '',
name: '',
phone_number: ''
}
};
},
created: function() {
this.getAgency();
},
methods: {
nextStep() {
this.$emit('next');
},
getAgency() {
this.$axios.get('/agency.json')
.then(response => {
if (Object.keys(response.data).length > 0) {
this.agency = response.data;
}
})
},
saveAgency() {
this.$axios.post('/agencies.json', { agency: this.agency })
.then(response => {
});
},
}
};
</script>
event.vue
<template>
<v-card class="mb-12">
<v-form :model='agency'>
{{ agency.name }}<br/>
{{ agency.phone_number }}<br/>
</v-form>
</v-card>
</template>
<script>
export default {
data: function () {
return {
agency: {
id: '',
name: '',
phone_number: ''
},
event_final: false
};
},
created: function() {
this.getAgency();
},
methods: {
getAgency() {
this.$axios.get('/agency.json')
.then(response => {
if (Object.keys(response.data).length > 0) {
this.agency = response.data;
if (this.agency.name === "XYZ") {
this.event_final = true;
}
}
}).
then(() => {
});
},
}
};
</script>
Have Agency emit the details in its next event, capture them at the parent and pass them as a prop to Event.
Given you load the initial data in stepper.vue, you can also pass that into Agency for editing
For example
// agency.vue
props: { editAgency: Object },
data () {
return { agency: this.editAgency } // initialise with prop data
},
methods: {
nextStep() {
this.$emit('next', { ...this.agency }) // using spread to break references
},
// etc, no need for getAgency() here though
}
<!-- stepper.vue -->
<Agency :edit-agency="agency" #next="nextAgency"></Agency>
<!-- snip -->
<Event :agency="agency" />
// stepper.vue
methods: {
nextAgency (agency) {
this.agency = agency
this.goTo(2, true)
},
// event.vue
export default {
props: { agency: Object } // no need for a local "data" copy of agency, just use the prop
}
Related
I have a ProjectPage.vue page that displays issues in a v-data-table. Projects are retrieved from a server api call in the sidebar and displayed there. After I choose a project, I would like to use that project's id to get its issues from the server. Is it possible to do so using Vuex.
Is it possible using Vuex, that each project can use the same .js file to retreive its issues, since there could be any number of projects.
What I am trying to do is from VerticalNavMenu.vue, pass an id and project as props to ProjectPage, so I can pass the id as a parameter to mapAction inside ProjectPage to retreive its issues.
The I'm way doing it now is not working. The table has no data available when I open a project's table
I hope Peoject_Pages.js helps understand what I'm asking about.
VerticalNavMenu.vue (related template lines are 38 -> 48)
<template>
<v-navigation-drawer
:value="isDrawerOpen"
app
expand-on-hover
mini-variant-width="60px"
floating
width="260"
class="app-navigation-menu"
:right="$vuetify.rtl"
#input="val => $emit('update:is-drawer-open', val)"
>
<!-- Navigation Header -->
<div class="vertical-nav-header d-flex items-center ps-6 pe-5 pt-5 pb-2">
<router-link to="/" class="d-flex align-center text-decoration-none">
<v-slide-x-transition>
<h2 class="app-title text--primary">ITrackerHub</h2>
</v-slide-x-transition>
</router-link>
</div>
<!-- Navigation Items -->
<v-list expand shaped class="vertical-nav-menu-items pr-5">
<nav-menu-link
title="Dashboard"
:to="{ name: 'dashboard' }"
:icon="icons.mdiHomeOutline"
></nav-menu-link>
<v-list>
<v-list-group :prepend-icon="icons.mdiTelevisionGuide">
<template v-slot:activator>
<v-list-item-content>
<v-list-item-title v-text="'My Projects'"></v-list-item-title>
</v-list-item-content>
</template>
<v-list-item v-for="(project, index) in ProjectList" :key="index">
<v-icon class="mx-2">{{ icons.mdiAccountGroup }}</v-icon>
<v-list-item-content>
<router-link
class="d-flex align-center text-decoration-none black--text"
:to="{ name: 'ProjectPage', params: { id: project.id, project} }"
>
{{ project.title }}
</router-link>
</v-list-item-content>
</v-list-item>
</v-list-group>
</v-list>
<nav-menu-link title="My Issues" :to="{ name: 'MyIssues' }" :icon="icons.mdiBookEditOutline"></nav-menu-link>
<nav-menu-link
style="position:relative; top:70px;"
title="Account Settings"
:to="{ name: 'pages-account-settings' }"
:icon="icons.mdiAccountCogOutline"
></nav-menu-link>
<nav-menu-link
style="position: relative; top: 200px"
title="Create Project"
:to="{ name: 'CreateProject' }"
:icon="icons.mdiPlusMinus"
></nav-menu-link>
</v-list>
</v-navigation-drawer>
</template>
<script>
// eslint-disable-next-line object-curly-newline
import {
mdiHomeOutline,
mdiAlphaTBoxOutline,
mdiEyeOutline,
mdiCreditCardOutline,
mdiTable,
mdiFileOutline,
mdiFormSelect,
mdiAccountCogOutline,
mdiAccountGroup,
mdiAccountMultiple,
mdiTelevisionGuide,
mdiBookEditOutline,
mdiPlusMinus,
} from '#mdi/js'
// import NavMenuSectionTitle from './components/NavMenuSectionTitle.vue'
import NavMenuGroup from './components/NavMenuGroup.vue'
import NavMenuLink from './components/NavMenuLink.vue'
import { mapGetters, mapActions } from 'vuex'
export default {
components: {
// NavMenuSectionTitle,
NavMenuGroup,
NavMenuLink,
},
computed: {
...mapGetters(['ProjectList'])
},
methods: {
...mapActions(['fetchProjects'])
},
created() {
// this.getProjectList()
this.fetchProjects()
},
props: {
isDrawerOpen: {
type: Boolean,
default: null,
},
},
setup() {
return {
icons: {
mdiHomeOutline,
mdiAlphaTBoxOutline,
mdiEyeOutline,
mdiCreditCardOutline,
mdiTable,
mdiFileOutline,
mdiFormSelect,
mdiAccountCogOutline,
mdiAccountGroup,
mdiAccountMultiple,
mdiTelevisionGuide,
mdiBookEditOutline,
mdiPlusMinus,
},
}
},
}
</script>
<style lang="scss" scoped>
.app-title {
font-size: 1.25rem;
font-weight: 700;
font-stretch: normal;
font-style: normal;
line-height: normal;
letter-spacing: 0.3px;
}
// ? Adjust this `translateX` value to keep logo in center when vertical nav menu is collapsed (Value depends on your logo)
.app-logo {
transition: all 0.18s ease-in-out;
.v-navigation-drawer--mini-variant & {
transform: translateX(-10px);
}
}
#include theme(app-navigation-menu) using ($material) {
background-color: map-deep-get($material, 'background');
}
.app-navigation-menu {
.v-list-item {
&.vertical-nav-menu-link {
::v-deep .v-list-item__icon {
.v-icon {
transition: none !important;
}
}
}
}
}
</style>
NavBar.js
import axios from 'axios'
const state = {
Projects: [],
}
const getters = {
ProjectList: (state) => state.Projects
}
const actions = {
async fetchProjects({ commit }) {
const response = await axios.get('https://fadiserver.herokuapp.com/api/v1/my-projects/')
commit('setProjects', response.data)
}
}
const mutations = {
setProjects: (state, Projects) => (state.Projects = Projects)
}
export default {
state,
getters,
actions,
mutations
}
ProjectPage.vue
<template>
<v-card>
<v-card-title class="text-center justify-center py-6">
<h1 class="font-weight-bold text-h2 basil--text">
{{ project.title }}
</h1>
</v-card-title>
<v-tabs v-model="tab" background-color="primary" dark centered>
<v-tab v-for="item in items" :key="item.tab">{{ item.tab }}</v-tab>
</v-tabs>
<v-tabs-items v-model="tab">
<v-tab-item v-for="item in items" :key="item.tab">
<v-card flat>
<v-card v-if="item.tab == 'Issues'">
<template>
<div class="text-center">
<v-dialog v-model="dialog" width="500">
<template v-slot:activator="{ on }">
<v-btn class="success" dark v-on="on">
<v-icon align-self: left>
mdi-plus-thick
</v-icon>
Add Issue
</v-btn>
</template>
<v-card>
<v-card-title>
<h2>Add Issue</h2>
</v-card-title>
<v-card-text>
<v-form class="px-3">
<v-text-field v-model="title" label="Title"></v-text-field>
<v-textarea v-model="description" label="Description"></v-textarea>
<v-select
item-text="text"
item-value="value"
:items="time_est"
v-model="time_estimate"
label="Time Estimate"
></v-select>
<v-select
item-text="title"
item-value="id"
:items="issueType"
v-model="issue_type"
label="Issue Type"
></v-select>
<v-select
item-text="title"
item-value="id"
v-model="issue_status"
label="Issue Status"
:items="issueStatus"
></v-select>
<v-select
item-text="title"
item-value="id"
:items="issueSeverity"
v-model="issue_severity"
label="Issue Severity"
></v-select>
<v-spacer></v-spacer>
<v-btn
flat
#click="
postIssue()
reloadPage()
"
class="success mx-0 mt-3"
>
<v-icon align-self:left>mdi-content-save-check-outline</v-icon> Save</v-btn
>
</v-form>
</v-card-text>
</v-card>
</v-dialog>
</div>
</template>
<v-card>
<v-data-table
:headers="headers"
:items="Project_Issues"
item-key="full_name"
class="table-rounded"
hide-default-footer
enable-sort
#click:row="handleClick"
>
</v-data-table>
</v-card>
</v-card>
</v-card>
</v-tab-item>
</v-tabs-items>
</v-card>
</template>
<script>
import axios from 'axios'
import { mapGetters, mapActions } from 'vuex'
export default {
props: ['id', 'project'],
computed: {
...mapGetters(['Project_Issues']),
},
data() {
return {
tab: null,
items: [{ tab: 'Issues' }, { tab: 'Calender' }, { tab: 'About' }],
title: '',
description: '',
time_estimate: '',
issue_type: '',
issue_status: '',
issue_severity: '',
time_est: [
{ value: '1', text: '1' },
{ value: '2', text: '2' },
{ value: '3', text: '3' },
{ value: '4', text: '4' },
{ value: '5', text: '5' },
{ value: '6', text: '6' },
{ value: '7', text: '7' },
{ value: '8', text: '8' },
],
}
},
setup() {
return {
headers: [
{ text: 'Title', value: 'title' },
{ text: 'Description', value: 'description' },
{ text: 'Estimate', value: 'time_estimate' },
{ text: 'Assignees', value: 'user' },
{ text: 'Type', value: 'issueType' },
{ text: 'Status', value: 'issueStatus' },
{ text: 'Severity', value: 'issueSeverity' },
],
}
},
methods: {
...mapActions(['fetchProjectIssueList']),
handleClick(issue) {
this.$router.push({
name: 'IssuePage',
params: { id: issue.id, issue },
})
},
postIssue() {
axios
.post('https://fadiserver.herokuapp.com/api/v1/my-issues/', {
title: this.title,
description: this.description,
time_estimate: this.time_estimate,
userid: 'f3260d22-8b5b-4c40-be1e-d93ba732c576',
projectid: this.id,
issueTypeId: this.issue_type,
issueStatusId: this.issue_status,
issueSeverityId: this.issue_severity,
})
.then(response => {
console.log(response)
})
.catch(error => {
console.log(error)
})
},
reloadPage() {
window.location.reload()
},
},
mounted() {
this.fetchProjectIssueList(this.id)
},
}
</script>
<style scoped>
.v-btn {
left: 43%;
}
</style>
Project_Page.js
import axios from 'axios'
const state = {
issuesList: [],
}
const getters = {
Project_Issues: (state) => state.issuesList
}
const actions = {
async fetchProjectIssueList({ commit }, {projectid}) {
const response = await axios.get('https://fadiserver.herokuapp.com/api/v1/my-issues-titles/?projectid=' + projectid)
commit('setProjectIssues', response.data)
},
}
const mutations = {
setProjectIssues: (state, issuesList) => (state.issuesList = issuesList)
}
export default {
state,
getters,
actions,
mutations
}
There are 2 ways of solving your problem.
Or you pass an object with the key projectid in the fetchProjectIssueList method
Or you do not need to destructure the object in the fetchProjectIssueList method
this.fetchProjectIssueList({ projectid: this.id })
...
async fetchProjectIssueList({ commit }, {projectid}) { ... }
or
this.fetchProjectIssueList(this.id)
...
async fetchProjectIssueList({ commit }, projectid) { ... }
I've got a problem with event orders, I have one method for getting data and another to open modal with data from previous method, and it works fine, but modal is rendered before getting data, so I see previous result for a sec. I do understand that I need my methods to be called in promise, but fail to realize how to do this.
App.vue
<v-app>
<v-main>
<h1 class="text-center text-uppercase">Gallery</h1>
<Cards
:images="images"
#addImage="updateImage($event)"
#showModal="showPopup($event)"
/>
<Card :image="image" v-if="modal" #closeImage="toggleImage($event)" />
</v-main>
</v-app>
</template>
<script>
import Cards from "./components/Cards.vue";
import Card from "./components/Card.vue";
export default {
name: "App",
components: { Cards, Card },
data: () => ({
images: {},
image: {},
modal: false,
}),
methods: {
updateImage: function (updatedImage) {
this.image = updatedImage;
},
showPopup: function (state) {
this.modal = state;
},
toggleImage: function (state) {
this.modal = state;
},
},
};
</script>
Cards.vue
<v-row>
<v-col
v-for="image in images"
:key="image.id"
class="d-flex"
cols="4"
#click="
getImage(image.id);
toggleWindow();
"
>
<v-img :src="image.url" :id="image.id">
<template v-slot:placeholder>
<v-row class="fill-height ma-0" align="center" justify="center">
<v-progress-circular
indeterminate
color="grey lighten-5"
></v-progress-circular>
</v-row>
</template>
</v-img>
</v-col>
</v-row>
</template>
<script>
export default {
name: "Cards",
props: ["images"],
methods: {
getImage(imageId) {
fetch(`https://boiling-refuge-66454.herokuapp.com/images/${imageId}`)
.then((res) => {
if (res.status == 200) {
return res.json();
} else {
throw new Error(res.status);
}
})
.then((data) => {
this.$emit("addImage", data);
});
},
toggleWindow() {
let toggle = true;
this.$emit("showModal", toggle);
},
},
};
</script>
<style></style>
I believe this is because getImage() is an async method. It should return an Promise that resolves itself after the last then(). The last then is the one containing this.$emit("addImage", data);.
In your #click you should then wait for getImage() to be resolved before calling toggleWindow().
So something like #click="async () => { await getImage(image.id); toggleWindow();}".
I am having one root component know as App.vue. and another component named as FileUploaderParent.vue. I am calling a dispatch promise to store the data in the store. I am calling dispatch under mounted lifecycle hook.
On the other side, I am trying to access stored user data in the mounted function of a different component. It shows the error of undefined
I know, a work around can be to call same dispatch promise on the mounted function. But, It feels like a hack and the dispatch call is getting redundant.
Here is the code for App.vue:
<template>
<v-app>
<v-navigation-drawer v-model="drawer" app temporary >
<v-img :aspect-ratio="16/9" src="https://image.freepik.com/free-vector/spot-light-background_1284-4685.jpg">
<v-layout pa-2 column fill-height class="lightbox gray--text">
<v-spacer></v-spacer>
<v-flex shrink>
<!-- <div class="subheading">{{this.$store.getters.userData.name}}</div> -->
<!-- <div class="body-1">{{this.$store.getters.userData.email}}</div> -->
</v-flex>
</v-layout>
</v-img>
<v-list>
<template v-for="(item, index) in items">
<v-list-tile :href="item.href" :to="{name: item.href}" :key="index">
<v-list-tile-action>
<v-icon light v-html="item.icon"></v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title v-html="item.title"></v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</template>
</v-list>
</v-navigation-drawer>
<v-toolbar color="white" light :fixed=true>
<v-toolbar-side-icon #click.stop="drawer = !drawer"></v-toolbar-side-icon>
<v-img :src="require('#/assets/mad_logo.png')" max-width="80px" max-height="41px" />
<v-toolbar-title class="black--text justify-center" > <h1>MeshApp</h1></v-toolbar-title>
<v-spacer></v-spacer>
<v-avatar color="primary">
<!-- <span class="white--text headline">{{this.avatar.slice(0,2)}}</span> -->
</v-avatar>
</v-toolbar>
<v-content style="margin-top: 60px;">
<v-fade-transition mode="out-in">
<router-view></router-view>
</v-fade-transition>
</v-content>
</v-app>
</template>
<script>
export default {
name: 'app',
components: {
},
data() {
return {
avatar: '',
drawer: false,
items: [
{
href: 'home',
router: true,
title: 'home',
icon: 'grid_on',
},
{
href: 'view_volunteers',
router: true,
title: 'View Volunteer',
icon: 'group'
},
{
href: 'profile',
router: true,
title: 'profile',
icon: 'account_circle',
},
{
href: 'logout',
router: true,
title: 'Logout',
icon: 'toggle_off',
}
]
}
},
props: [],
mounted() {
this.$store.dispatch('getUserData').
then(() => {
let findAvatar = this.$store.getters.userData.name.split(" ")
let createAvatar = ''
for(let i = 0; i < findAvatar.length; i++) {
createAvatar = createAvatar + findAvatar[i].slice(0,1)
}
this.avatar = createAvatar
console.log(this.avatar)
// this.$store.dispatch('getUserId', id)
})
}
}
</script>
<style scoped>
v-content {
margin-top: 60px !important;
}
</style>
Here is the code for FileUploaderParent.vue:
<template>
<v-layout class="text-xs-center ">
<v-flex>
<image-input v-model="avatar">
<div slot="activator">
<v-avatar color = "primary" size="150px" v-ripple v-if="!avatar" class=" mb-3">
<h1 class="white--text"><span>{{this.defaultAvatar}}</span></h1>
</v-avatar>
<v-avatar size="150px" v-ripple v-else class="mb-3">
<img :src="avatar.imageURL" alt="avatar">
</v-avatar>
</div>
</image-input>
<v-slide-x-transition>
<div v-if="avatar && saved == false">
<!-- Stores the Image and changes the loader -->
<v-btn class="primary" #click="uploadImage" :loading="saving">Save Avatar</v-btn>
</div>
</v-slide-x-transition>
</v-flex>
</v-layout>
</template>
<script>
import ImageInput from './FileUploaderChild.vue'
export default {
name: 'app',
data () {
return {
defaultAvatar: '',
avatar: null,
saving: false,
saved: false
}
},
mounted() {
this.$store.dispatch('getUserData').
then(() => {
let findAvatar = this.$store.getters.userData.name.split(" ")
let createAvatar = ''
for(let i = 0; i < findAvatar.length; i++) {
createAvatar = createAvatar + findAvatar[i].slice(0,1)
}
this.defaultAvatar = createAvatar
})
},
components: {
ImageInput: ImageInput
},
watch:{
avatar: {
handler: function() {
this.saved = false
},
deep: true
}
},
methods: {
uploadImage() {
this.saving = true
setTimeout(() => this.savedAvatar(), 1000)
},
savedAvatar() {
this.saving = false
this.saved = true
}
}
}
</script>
<style>
</style>
This is how the store looks like:
store.js
actions: {
getUserData(context) {
return new Promise((resolve, reject) => {
axios.get('http://someurl.in/api/v1/users/'+this.state.userId, {
headers: {
'Content-Type': 'application/json'
},
auth: {
username: 'someusername',
password: 'pass'
}
}).
then(response => {
context.commit('storeUserData', response.data.data.users)
resolve(response); // Let the calling function know that http is done. You may send some data back
}).catch(error => {
reject(error);
})
})
}
},
mutations: {
storeUserData(state, data) {
state.userData = data
}
}
This is how the error looks like:
How do i access store data in FileUploaderParent.vue under mounted function?
The code you have written seems right, but if you still need an answer you can use watch on store
this.$store.watch(() => this.$store.state.userData, async () => {
//do your code here
});
How about adding a check that determines if an API call is required:
actions: {
getUserData(context) {
return new Promise((resolve, reject) => {
// Be sure to set the default value to `undefined` under the `state` object.
if (typeof this.state.userData === 'undefined') {
axios
.get('http://someurl.in/api/v1/users/' + this.state.userId, {
headers: {
'Content-Type': 'application/json'
},
auth: {
username: 'someusername',
password: 'pass'
}
})
.then(response => {
context.commit('storeUserData', response.data.data.users);
resolve(response.data.data.users);
})
.catch(error => {
reject(error);
});
}
else {
resolve(this.state.userData);
}
})
}
}
The this.$store.getters refers to a getter in your Vuex store. You have no getters in your Vuex store - at least none can be seen in your sample. (https://vuex.vuejs.org/guide/getters.html)
I am getting this error when I edit one of the text fields (which updates the store):
I've already tried putting #change and v-model on the text fields and that is not proper. Need to find a proper way to mutate the state on an event triggered by the text field(s).
Example:
Profile.vue:
<v-text-field #change="setProfile(profileData)" v-model="profileData.groupName" label="Group Name"></v-text-field>
Here is my code:
Profile.vue:
<v-text-field #change="set" v-model="profileData.groupName" label="Group Name"></v-text-field>
Profile.vue Javascript:
import { mapGetters, mapMutations } from "vuex";
export default {
name: "Profile",
created() {
delete this.profileData;
this.profileData = JSON.parse(JSON.stringify(this.getProfile()));
console.log(this.profileData);
},
data() {
return {
profileData: {
groupName: null,
groupClid: null,
groupContact: null
}
};
},
methods: {
set() {
this.$store.commit("setProfile", this.profileData);
},
...mapGetters(["getProfile"]),
...mapMutations(["setProfile"])
}
}
build.js --> store.js:
const state = {
profile: {
"groupName": "Happy group",
"groupNumber": "9999999999",
"groupContact": "Bob Ross"
}
};
const getters = {
getProfile: (state) => state.profile,
};
const actions = { };
const mutations = {
setProfile: (state, profile) => (state.profile = profile)
};
export default {
state,
getters,
actions,
mutations,
}
Answer:
Remove delete this.profileData from created()
Change the set() to `setData'
Change to Object.assign (shouldn't matter if you use string->parse or Object.assign)
Put one change event on the card, above the text fields. This way, we don't have to duplicate the vue-style event listener.
<template >
<v-container fluid>
<v-layout row wrap fill-height>
<v-flex xs6>
<v-card elevation="10">
<v-card-title primary-title class="pb-0">
<div>
<h3 class="headline mb-0 pb-0">Group Information</h3>
</div>
</v-card-title>
<v-card-text #change="setData">
<v-container fluid>
<v-layout align-center row wrap>
<v-flex xs3>
<v-responsive>Group Name:</v-responsive>
</v-flex>
<v-flex xs9>
<v-text-field v-model="profileData.groupName" label="Group Name"></v-text-field>
</v-flex>
</v-layout>
</v-container>
</v-card-text>
</v-card>
</v-flex>
</v-layout>
<v-spacer></v-spacer>
</v-container>
</template>
<script>
import { mapGetters, mapMutations } from "vuex";
export default {
name: "Profile",
created() {
this.profileData = Object.assign({}, this.getProfile());
},
data() {
return {
profileData: {}
};
},
methods: {
setData() {
this.setProfile(this.getData());
},
getData() {
return Object.assign({}, this.profileData);
},
...mapGetters(["getProfile"]),
...mapMutations(["setProfile"])
}
};
</script>
i'm learning vuetify framework, i managed to use most of the components but i have a problem with autocomplete component.
Using it from scratch works fine, bug if i try to set value during creation it doesn't work at all.
I tried to extend one of the vuetify example but without success.
i would like to load first value from the API during creation but it stays empty.
Thanks for your help.
new Vue({
el: '#app',
data: () => ({
descriptionLimit: 60,
entries: [],
isLoading: false,
model: null,
search: "Cats"
}),
created :function() {
model={"API":"Cats","Description":"Pictures of cats from Tumblr","Auth":"","HTTPS":true,"Cors":"unknown","Link":"https://thecatapi.com/docs.html","Category":"Animals"},
search="Cats"
},
computed: {
fields () {
if (!this.model) return []
return Object.keys(this.model).map(key => {
return {
key: key,
value: this.model[key] || 'n/a'
}
})
},
items () {
return this.entries.map(entry => {
const Description = entry.Description.length > this.descriptionLimit
? entry.Description.slice(0, this.descriptionLimit) + '...'
: entry.Description
return Object.assign({}, entry, { Description })
})
}
},
watch: {
search (val) {
// Items have already been loaded
if (this.items.length > 0) return
this.isLoading = true
console.log("loadgin data")
// Lazily load input items
axios.get('https://api.publicapis.org/entries')
.then(res => {
const { count, entries } = res.data
this.count = count
this.entries = entries
})
.catch(err => {
console.log(err)
})
.finally(() => (this.isLoading = false))
}
}
})
<div id="app">
<v-app id="inspire">
<v-card
color="red lighten-2"
dark
>
<v-card-title class="headline red lighten-3">
Search for Public APIs
</v-card-title>
<v-card-text>
Explore hundreds of free API's ready for consumption! For more information visit
<a
class="grey--text text--lighten-3"
href="https://github.com/toddmotto/public-apis"
target="_blank"
>the Github repository</a>.
</v-card-text>
<v-card-text>
<v-autocomplete
v-model="model"
:items="items"
:loading="isLoading"
:search-input.sync="search"
color="white"
hide-no-data
hide-selected
item-text="Description"
item-value="API"
label="Public APIs"
placeholder="Start typing to Search"
prepend-icon="mdi-database-search"
return-object
></v-autocomplete>
</v-card-text>
<v-divider></v-divider>
<v-expand-transition>
<v-list v-if="model" class="red lighten-3">
<v-list-tile
v-for="(field, i) in fields"
:key="i"
>
<v-list-tile-content>
<v-list-tile-title v-text="field.value"></v-list-tile-title>
<v-list-tile-sub-title v-text="field.key"></v-list-tile-sub-title>
</v-list-tile-content>
</v-list-tile>
</v-list>
</v-expand-transition>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
:disabled="!model"
color="grey darken-3"
#click="model = null"
>
Clear
<v-icon right>mdi-close-circle</v-icon>
</v-btn>
</v-card-actions>
</v-card>
</v-app>
</div>
If this is the code you are trying to use then you are missing a ',' at the end of the "model".
created :function() {
model={...}, <----
search="Cats"
},
blalan05 on the discrod channel just give me the reply : my created function was garbled.
new Vue({
el: '#app',
data: () => ({
descriptionLimit: 60,
entries: [],
isLoading: false,
model: null,
search: "Cats"
}),
created () {
this.model = {"API":"Cats","Description":"Pictures of cats from Tumblr","Auth":"","HTTPS":true,"Cors":"unknown","Link":"https://thecatapi.com/docs.html","Category":"Animals"},
this.search = "Cats"
},
computed: {
fields () {
if (!this.model) return []
return Object.keys(this.model).map(key => {
return {
key: key,
value: this.model[key] || 'n/a'
}
})
},
items () {
return this.entries.map(entry => {
const Description = entry.Description.length > this.descriptionLimit
? entry.Description.slice(0, this.descriptionLimit) + '...'
: entry.Description
return Object.assign({}, entry, { Description })
})
}
},
watch: {
search (val) {
// Items have already been loaded
if (this.items.length > 0) return
this.isLoading = true
console.log("loadgin data")
// Lazily load input items
axios.get('https://api.publicapis.org/entries')
.then(res => {
const { count, entries } = res.data
this.count = count
this.entries = entries
})
.catch(err => {
console.log(err)
})
.finally(() => (this.isLoading = false))
}
}
})
<div id="app">
<v-app id="inspire">
<v-card
color="red lighten-2"
dark
>
<v-card-title class="headline red lighten-3">
Search for Public APIssss
</v-card-title>
<v-card-text>
Explore hundreds of free API's ready for consumption! For more information visit
<a
class="grey--text text--lighten-3"
href="https://github.com/toddmotto/public-apis"
target="_blank"
>the Github repositoryyy</a>.
</v-card-text>
<v-card-text>
<v-autocomplete
v-model="model"
:items="items"
:loading="isLoading"
:search-input.sync="search"
color="white"
hide-no-data
hide-selected
item-text="Description"
item-value="API"
label="Public APIs"
placeholder="Start typing to Search"
prepend-icon="mdi-database-search"
return-object
></v-autocomplete>
</v-card-text>
<v-divider></v-divider>
<v-expand-transition>
<v-list v-if="model" class="red lighten-3">
<v-list-tile
v-for="(field, i) in fields"
:key="i"
>
<v-list-tile-content>
<v-list-tile-title v-text="field.value"></v-list-tile-title>
<v-list-tile-sub-title v-text="field.key"></v-list-tile-sub-title>
</v-list-tile-content>
</v-list-tile>
</v-list>
</v-expand-transition>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
:disabled="!model"
color="grey darken-3"
#click="model = null"
>
Clear
<v-icon right>mdi-close-circle</v-icon>
</v-btn>
</v-card-actions>
</v-card>
</v-app>
</div>