How to create a dynamic form vuejs vuetify? - javascript

i'm trying to make a dynamic form to work.
I have an array of competences, and inside, i have a skills array. Each skill of the entire competence is going to be evaluated, so it need to have an answer.
Everything is organized in a v-stepper with dynamic steps, and my form fields are being generated by a v-for. For each skill the answer need to have, maybe an array like
answers: [
skillId:
skillLevel:
feedback:
feedforward:
...
]
My question is, being the form dynamically generated, how can i set the v-models for each field? Because a competence can have many skills, so the models need to be different to bind.
Here's my code
<template>
<v-stepper v-model="e1" :appraisal="appraisal">
<v-stepper-header>
<template v-for="n in steps">
<v-stepper-step :key="`${n}-step`" :step="n" :complete="e1 > n" editable></v-stepper-step>
<v-divider v-if="n !== steps" :key="n"></v-divider>
</template>
</v-stepper-header>
<v-stepper-items>
<v-stepper-content v-for="n in steps" :key="`${n}-content`" :step="n">
<v-row align="center" justify="center">
<v-col cols="4">
<v-subheader class="headline">{{appraisal.appraisalCompetences[n-1].competence.name}}</v-subheader>
</v-col>
</v-row>
<v-row>
<v-col cols="12">
<v-row justify="center">
<v-col cols="3">
<v-subheader class="title">Fatores</v-subheader>
</v-col>
<v-col cols="2">
<v-subheader class="title">Presença da competência</v-subheader>
</v-col>
<v-col cols="2">
<v-subheader class="title">Feedback do Gestor</v-subheader>
</v-col>
<v-col cols="2">
<v-subheader class="title">Auto Avaliação</v-subheader>
</v-col>
<v-col cols="3">
<v-subheader class="title">Feedforward</v-subheader>
</v-col>
</v-row>
</v-col>
</v-row>
<v-divider></v-divider>
<template v-for="competence in appraisal.appraisalCompetences[n-1]">
<v-form :key="`${competence.competenceId}-form`">
<v-row v-for="(item, index) in competence.competenceSkills" :key="index">
<v-col cols="12">
<v-row class="mb-n10" justify="center">
<v-col cols="3" class="mt-4">
<span>{{item.skill.name}}</span>
</v-col>
<v-col cols="2">
<v-select
v-model="answers.skillLevel"
outlined
:items="selectLevels"
:name="`skill-level-${item.skill.skillId}`"
label="Selecione"
item-text="level"
item-value="value"
></v-select>
</v-col>
<v-col cols="2">
<v-textarea outlined rows="3" :name="`skill-feedback-${item.skill.skillId}`"></v-textarea>
</v-col>
<v-col cols="2">
<v-textarea
outlined
rows="3"
:name="`skill-selfappraisal-${item.skill.skillId}`"
></v-textarea>
</v-col>
<v-col cols="3">
<v-textarea outlined rows="3" :name="`skill-feedforward-${item.skill.skillId}`"></v-textarea>
</v-col>
</v-row>
</v-col>
</v-row>
</v-form>
</template>
<v-row>
<v-col cols="12">
<v-row align="center" justify="space-between">
<v-btn tile large color="error" #click="previous(n)">
<v-icon dark left>mdi-arrow-left</v-icon>Voltar
</v-btn>
<v-btn tile large color="success" #click="next(n)">
Continuar
<v-icon dark right>mdi-arrow-right</v-icon>
</v-btn>
</v-row>
</v-col>
</v-row>
</v-stepper-content>
</v-stepper-items>
</v-stepper>
</template>
<script>
export default {
data: () => ({
e1: 1,
steps: 1,
appraisal: [],
selectLevels: [
{ value: 0, level: "Ausente" },
{ value: 1, level: "A Desenvolver" },
{ value: 2, level: "Satifatória" },
{ value: 3, level: "Excelencia" },
{ value: 4, level: "Não se aplica" }
],
answers: [
{
competenceId: "",
appraisalId: "",
skillId: "",
skillLevel: "",
feedback: "",
selfAppraisal: "",
feedforward: ""
}
]
}),
created() {
this.initialize();
},
methods: {
initialize() {
axios
.get(`/questionnaire/appraisals/${this.$route.params.appraisalId}`)
.then(response => {
this.appraisal = response.data;
this.steps = this.appraisal.appraisalCompetences.length;
});
},
previous(n) {
if (this.e1 == 1) {
this.$router.push("/app/pdc");
} else {
this.e1 = n - 1;
}
},
next(n) {
if (n === this.steps) {
this.e1 = 1;
} else {
this.e1 = n + 1;
}
}
}
};
</script>
EDITED
Let me try to improve the question
In my form, for each competence, i have a set of skills that will be evaluated. So for each of these skills, i need to have a separate answer, like
for skill 1
skillId:
skillLevel:
feedback:
feedforward:
...
And so on for all other skills. after the user types the answers for every skill in the competence, i need to do the same for competence 2 an so on.
The problema is in the answers part of the form, I don't know how to make every single line count as one answer and after add them to an array of answers
This is what i came up so far
<template v-for="competence in appraisal.appraisalCompetences[n-1]">
<v-row v-for="(item, index) in competence.competenceSkills" :key="index">
<v-col cols="12">
<v-form :key="`${item.skillId}-form`">
<v-row class="mb-n10" justify="center">
<v-col cols="3" class="mt-4">
<span>{{item.skill.name}}</span>
</v-col>
<v-col cols="2">
<v-select
v-model="`${item.skillId}-form`.skillLevel"
outlined
:items="selectLevels"
label="Selecione"
item-text="level"
item-value="value"
></v-select>
</v-col>
<v-col cols="2">
<v-textarea v-model="answer.feedback" outlined rows="3"></v-textarea>
</v-col>
<v-col cols="2">
<v-textarea v-model="answer.selfAppraisal" outlined rows="3"></v-textarea>
</v-col>
<v-col cols="3">
<v-textarea v-model="answer.feedForward" outlined rows="3"></v-textarea>
</v-col>
</v-row>
</v-form>
</v-col>
</v-row>
</template>
export default {
data: () => ({
e1: 1,
steps: 1,
appraisal: [],
selectLevels: [
{ value: 0, level: "Ausente" },
{ value: 1, level: "A Desenvolver" },
{ value: 2, level: "Satifatória" },
{ value: 3, level: "Excelencia" },
{ value: 4, level: "Não se aplica" }
],
answer: {
competenceId: "",
skillId: "",
skillLevel: "",
feedback: "",
selfAppraisal: "",
feedForward: ""
},
anwers: []
}),

first of all there are some good vuejs-vuetify ready form generator, which isbased on standard json-schema.
see below examples and projects, specially the github code for more detail and idea about how to create a good form generator,so you can use them.
https://github.com/koumoul-dev/vuetify-jsonschema-form
https://koumoul-dev.github.io/vuetify-jsonschema-form/latest/?example=basic
if you want to write some project from scrach, you shoud consider that the idea is simple like rendering a inline edit in a table (by using refrence by means of object passing):
see below example:
watch the logic, you should index properly, when i debugged your code, the code always refrences to answer 0 to 5 at least. so you couldnt make it work.
read below with care to fix you problem:
<v-col cols="2">
<v-select
v-model="answers[index + (competence.competenceId-1)*competence.competenceSkills.length ].skillLevel"
outlined
:items="selectLevels"
label="Selecione"
item-text="level"
item-value="value"
></v-select>
</v-col>
<v-col cols="2">
<v-textarea v-model="answers[index + (competence.competenceId-1)*competence.competenceSkills.length].feedBack" outlined rows="3"></v-textarea>
</v-col>
<v-col cols="2">
<v-textarea v-model="answers[index + (competence.competenceId-1)*competence.competenceSkills.length].selfAppraisal" outlined rows="3"></v-textarea>
</v-col>
<v-col cols="3">
<v-textarea v-model="answers[index + (competence.competenceId-1)*competence.competenceSkills.length].feedForward" outlined rows="3"></v-textarea>
</v-col>
or you can use a better idea, seperation of answers like below:
see below for how i fixed the problem to get the idea:

Related

localstorage doesn't save item without page reload first

I'm using vue.js with vuetify and saving some data in localstorage but whenever I save once and try to save a new data it calls the save function until the end but it doesn't save in localstorage being necessary to reload the page to be able to save a new data.
<v-card>
<v-card-title>
<span class="text-h5">{{ formTitle }}</span>
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col cols="12" sm="12" md="12">
<v-text-field
v-model="contact.name"
label="Name"
:error-messages="nameErrors"
required
#input="$v.contact.name.$touch()"
#blur="$v.contact.name.$touch()"
>
</v-text-field>
</v-col>
<v-col cols="12" sm="12" md="12">
<v-text-field
v-model="contact.cellPhone"
label="Phone"
v-mask="'(##) #####-####'"
:error-messages="cellPhoneErrors"
required
#input="$v.contact.cellPhone.$touch()"
#blur="$v.contact.cellPhone.$touch()"
>
</v-text-field>
</v-col>
</v-row>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="blue darken-1" text #click="close"> Cancel</v-btn>
<v-btn color="blue darken-1" text #click="save"> Save </v-btn>
</v-card-actions>
</v-card>
save() {
this.submitted = true;
this.$v.$touch();
if (this.$v.$error) {
return;
}
this.editing = false;
if (this.contact.id === 0) {
this.contact.id = this.contacts.length + 1;
this.contact.ddd = this.contact.cellPhone.substr(
1,
2
);
this.contacts.push(this.contact);
} else {
this.contacts[this.index] = this.contact;
}
localStorage.setItem(
'contacts',
JSON.stringify(this.contacts)
);
this.close();
this.contact = {
id: 0,
name: null,
cellPhone: null,
ddd: null,
};
},
I've already tried using async await but the problem remains, the only solution so far was using a normal html form instead of the vuetify form.

Vue prop is sent from a component is undefined

I have a Kanban board inside my dashboard which displays issues of a project. I added a menu to allow the user to filter the kanban board by project such that only one project's issue are visible at once. The default view is the issues of all the projects.
In my Dashboard component, I get the list of all projects from a server using axios (which works correctly).
When a user chooses a project, I send to the Kanban board component a prop which is the project id so that I can fetch that project's issues from the server.
However, the prop I'm sending from Dashboard is undefined somehow, and I cannot figure out why
Dashboard.vue
<template>
<v-container>
<v-row class="my-1">
<v-col cols="3">
<h2 style="font-size:40px;color:rgb(92, 92, 92)">Kanban Board</h2>
</v-col>
<v-col cols="7"></v-col>
<v-col cols="2">
<v-menu offset-y>
<template v-slot:activator="{ on, attrs }">
<v-btn color="primary" dark v-bind="attrs" v-on="on">
View
</v-btn>
</template>
<v-list>
<v-list-item v-for="(project, index) in ProjectList" :key="index">
<v-list-item-title #click="changeView(project.id)">{{ project.title }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</v-col>
</v-row>
<v-row>
<KanBanBoard :projectid="project_id"></KanBanBoard>
</v-row>
</v-container>
</template>
<script>
import KanBanBoard from './KanBanBoard.vue'
import { mapGetters, mapActions } from 'vuex'
export default {
components: {
KanBanBoard,
},
data() {
return {
project_id: '',
}
},
computed: {
...mapGetters(['ProjectList']),
},
methods: {
...mapActions(['getProjectList']),
changeView(project_id) {
this.project_id = project_id
},
},
created() {
this.getProjectList()
},
}
</script>
<style scoped>
.view {
font-size: 20px;
}
</style>
NavBar.js (Vuex file Dashboard uses to get the list of projects)
import axios from 'axios'
const state = {
Projects: [],
ProjectsIssuesList: []
}
const getters = {
ProjectList: (state) => state.Projects,
ProjectIssuesList: (state) => state.ProjectsIssuesList
}
const actions = {
async getProjectList({ commit }) {
var projectList = []
var issuesList = []
await axios
.get('https://fadiserver.herokuapp.com/api/v1/my-projects/')
.then(response => {
projectList = response.data
for (let i = 0; i < projectList.length; i++) {
let projectid = projectList[i].id
axios
.get('https://fadiserver.herokuapp.com/api/v1/my-issues-titles/?projectid=' + projectid)
.then(response => {
issuesList.push(response.data)
})
.catch(error => {
console.log(error)
})
}
})
.catch(error => {
console.log(error)
})
commit('setProjects', projectList),
commit('setProjectsIssues', issuesList)
},
}
const mutations = {
setProjects: (state, Projects) => (state.Projects = Projects),
setProjectsIssues: (state, ProjectsIssuesList) => (state.ProjectsIssuesList = ProjectsIssuesList)
}
export default {
state,
getters,
actions,
mutations
}
KanBanBoard.vue
<template>
<v-container>
<v-row wrap>
<v-col xl="4" lg="4" md="4" sm="4" xs="12">
<v-card>
<v-card-title class="blue lighten-3">
<span class="white--text">Open</span>
</v-card-title>
<v-divider horizontal></v-divider>
<v-card-text class="blue lighten-3">
<draggable class="list-group kanban-column" :list="Open" group="tasks">
<v-card
class="#f4f5fa"
style="height:auto; margin-top:10px"
v-for="issue in Open"
:key="issue"
align-center
elevation="3"
>
<v-card-text>
<v-row dense style="width:auto">
<router-link
class="d-flex align-center text-decoration-none grey--text"
style="font-size:18px;"
:to="{ name: 'IssuePage', params: { id: issue.id, issue } }"
>
{{ issue.title }}
</router-link>
</v-row>
<v-row dense>
<v-col>
<v-chip
class="ma-2"
color="red"
outlined
style="position:relative; right:10px;top:10px; height:min-content"
>
{{ issue.issueSeverity }}
</v-chip>
</v-col>
<v-col>
<v-chip
class="ma-2"
color="green"
outlined
style="position:relative; right:83px; top:10px;height:min-content"
>
{{ issue.issueType }}
</v-chip>
</v-col>
</v-row>
</v-card-text>
</v-card>
</draggable>
</v-card-text>
</v-card>
</v-col>
<v-col xl="4" lg="4" md="4" sm="4" xs="12">
<v-card>
<v-card-title class="light-green lighten-3">
<span class="white--text">In Progress</span>
</v-card-title>
<v-divider horizontal></v-divider>
<v-card-text class="light-green lighten-3">
<draggable class="list-group kanban-column" :list="InProgress" group="tasks">
<v-card
class="#f4f5fa"
style="height:auto; margin-top:10px"
v-for="issue in InProgress"
:key="issue"
align-center
elevation="3"
>
<v-card-text>
<v-row dense style="width:auto">
<router-link
class="d-flex align-center text-decoration-none grey--text"
style="font-size:18px;"
:to="{ name: 'IssuePage', params: { id: issue.id, issue } }"
>
{{ issue.title }}
</router-link>
</v-row>
<v-row>
<v-col>
<v-chip
class="ma-2"
color="red"
outlined
style="position:relative; right:10px;top:10px; height:min-content"
>
{{ issue.issueSeverity }}
</v-chip>
</v-col>
<v-col>
<v-chip
class="ma-2"
color="green"
outlined
style="position:relative; right:83px; top:10px;height:min-content"
>
{{ issue.issueType }}
</v-chip>
</v-col>
</v-row>
</v-card-text>
</v-card>
</draggable>
</v-card-text>
</v-card>
</v-col>
<v-col xl="4" lg="4" md="4" sm="4" xs="12">
<v-card>
<v-card-title class="orange lighten-3">
<span class="white--text">Completed</span>
</v-card-title>
<v-divider horizontal></v-divider>
<v-card-text class="orange lighten-3">
<draggable class="list-group kanban-column" :list="Completed" group="tasks">
<v-card
class="#f4f5fa"
style="height:auto; margin-top:10px"
v-for="issue in Completed"
:key="issue"
align-center
elevation="3"
>
<v-card-text>
<v-row dense style="width:auto">
<router-link
class="d-flex align-center text-decoration-none grey--text"
style="font-size:18px;"
:to="{ name: 'IssuePage', params: { id: issue.id, issue } }"
>
{{ issue.title }}
</router-link>
</v-row>
<v-row dense>
<v-col>
<v-chip
class="ma-2"
color="red"
outlined
style="position:relative; right:10px;top:10px; height:min-content"
>
{{ issue.issueSeverity }}
</v-chip>
</v-col>
<v-col>
<v-chip
class="ma-2"
color="green"
outlined
style="position:relative; right:83px; top:10px;height:min-content"
>
{{ issue.issueType }}
</v-chip>
</v-col>
</v-row>
</v-card-text>
</v-card>
</draggable>
</v-card-text>
</v-card>
</v-col>
</v-row>
</v-container>
</template>
<script>
import draggable from 'vuedraggable'
import { mapGetters, mapActions } from 'vuex'
export default {
props: ['project_id'],
components: {
draggable,
},
computed: {
...mapGetters(['Open']),
...mapGetters(['InProgress']),
...mapGetters(['Completed']),
},
watch: {
projectid() {
this.fetchIssuesofProject(this.project_id)
this.test()
},
},
methods: {
...mapActions(['fetchIssuesofProject']),
test() {
console.log(this.projectid)
},
},
created() {
this.test(), this.fetchIssuesofProject(this.project_id)
},
}
</script>
<style scoped>
hr {
margin-top: 0.1px;
margin-bottom: 0.1px;
border: 1;
border-top: 1px solid rgba(0, 0, 0, 0.1);
}
</style>
Kanban.js
import axios from 'axios'
const state = {
Issues: [],
}
const getters = {
Open: (state) => state.Issues.filter(x => x.issueStatus == 'Open'),
InProgress: (state) => state.Issues.filter(x => x.issueStatus == 'In Progress'),
Completed: (state) => state.Issues.filter(x => x.issueStatus == 'Closed'),
}
const actions = {
async fetchIssuesofProject({ commit }, projectid) {
const response = await axios.get('https://fadiserver.herokuapp.com/api/v1/my-issues-titles/?projectid=' + projectid).catch(error => {
console.log("The error is here")
})
commit('setIssues', response.data)
}
}
const mutations = {
setIssues: (state, Issues) => (state.Issues = Issues)
}
export default {
state,
getters,
actions,
mutations
}```
Probably it's because in KanBanBoard.vue you defined your prop as project_id and in Dashboard.vue you're passing it like this:
<KanBanBoard :projectid="project_id"></KanBanBoard>
instead do:
<KanBanBoard :project_id="project_id"></KanBanBoard>

How can I pre-populate my input with data from API?

I have an edit form, and I'm trying to populate my input base on the response from API. My campaign data look like this.
{
"id": 219,
"name": "finishedddd-1642606412049"
}
Testing
You see that I can access campaign.name like this
<p>Campaign Name : {{ campaign.name }}</p>
Trying
I want to pre-populated my name input, so I did this
data() {
return {
campaign: {},
form: {
errors: {},
values: {
name: this.campaign.name,
...
Result
Somehow that kept getting me :
"TypeError: Cannot read properties of undefined (reading 'name')"
Code
<template>
<v-container fluid class="my-1">
<Navbar />
<Breadcrumbs />
<v-row>
<v-col cols="12">
<v-card elevation="2">
<PanelHeader type="create" icon="campaign" title="Campaigns" />
<v-stepper v-model="e1" justify="center" elevation="0">
<v-stepper-header>
<v-stepper-step :complete="e1 > 1" step="1"> Campaign </v-stepper-step>
<v-divider></v-divider>
<v-stepper-step :complete="e1 > 2" step="2"> Setup </v-stepper-step>
<v-divider></v-divider>
<v-stepper-step step="3"> Finish </v-stepper-step>
</v-stepper-header>
<v-stepper-items>
<v-stepper-content step="1">
<v-card class="mb-12" elevation="0">
<v-form ref="form" lazy-validation v-model="valid" id="form">
<v-row>
<v-card-text class="font-weight-bold">
Campaigns
<p>Campaign Name : {{ campaign.name }}</p>
<v-tooltip right>
<template v-slot:activator="{ on, attrs }">
<v-btn icon v-bind="attrs" v-on="on">
<v-icon color="grey lighten-1">info</v-icon>
</v-btn>
</template>
<span>Select marketing campaign type for Print Materials or Product Tags. Provide a name to identify the marketing campaign.</span>
</v-tooltip>
</v-card-text>
</v-row>
<v-row>
<v-col class="col-sm-2 col-lg-2 col-12">
<v-select disabled dense outlined :items="types" label="Type" v-model="form.values.type" :rules="form.rules.type"></v-select>
</v-col>
<v-col cols="12" sm="6" md="2">
<v-text-field dense outlined v-model="form.values.name" :rules="form.rules.name" label="Name" required></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6" md="4">
<v-textarea dense rows="1" outlined v-model="form.values.description" label="Description" required></v-textarea>
</v-col>
</v-row>
<v-row>
<v-card-text class="font-weight-bold"
>Schedule :
<v-tooltip right>
<template v-slot:activator="{ on, attrs }">
<v-btn icon v-bind="attrs" v-on="on">
<v-icon color="grey lighten-1">info</v-icon>
</v-btn>
</template>
<span>Set the time zone, start and end date for this campaign to be active.</span>
</v-tooltip>
</v-card-text>
<v-col cols="12" sm="6" md="4">
<v-select dense outlined :items="timezones" v-model="form.values.timezone" :rules="form.rules.timezone" label="Timezone" append-icon="lock_clock"></v-select>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6" md="2">
<v-menu v-model="form.values.startDateMenu" :close-on-content-click="false" :nudge-right="40" transition="scale-transition" offset-y min-width="auto">
<template v-slot:activator="{ on, attrs }">
<v-text-field dense outlined v-model="form.values.startDate" :rules="form.rules.startDate" label="Start Date" append-icon="mdi-calendar" readonly v-bind="attrs" v-on="on"></v-text-field>
</template>
<v-date-picker v-model="form.values.startDate"></v-date-picker>
</v-menu>
</v-col>
<v-col cols="12" sm="6" md="2">
<v-menu ref="menu" v-model="startTimeMenu" :close-on-content-click="false" :nudge-right="40" :return-value.sync="form.values.startTime" transition="scale-transition" offset-y max-width="290px" min-width="290px">
<template v-slot:activator="{ on, attrs }">
<v-text-field dense v-model="form.values.startTime" label="Start Time" append-icon="mdi-clock-time-four-outline" readonly v-bind="attrs" v-on="on" outlined></v-text-field>
</template>
<v-time-picker v-if="startTimeMenu" v-model="form.values.startTime" full-width #click:minute="$refs.menu.save(form.values.startTime)"></v-time-picker>
</v-menu>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6" md="2">
<v-menu v-model="endDateMenu" :close-on-content-click="false" :nudge-right="40" transition="scale-transition" offset-y min-width="auto">
<template v-slot:activator="{ on, attrs }">
<v-text-field dense outlined v-model="form.values.endDate" :rules="form.rules.endDate" :min="form.values.startDate" label="End Date" append-icon="mdi-calendar" readonly v-bind="attrs" v-on="on"></v-text-field>
</template>
<v-date-picker v-model="form.values.endDate"></v-date-picker>
</v-menu>
</v-col>
<v-col cols="12" sm="6" md="2">
<v-menu ref="menu" v-model="endTimeMenu" :close-on-content-click="false" :nudge-right="40" :return-value.sync="form.values.endTime" transition="scale-transition" offset-y max-width="290px" min-width="290px">
<template v-slot:activator="{ on, attrs }">
<v-text-field dense v-model="form.values.endTime" label="End Time" append-icon="mdi-clock-time-four-outline" readonly v-bind="attrs" v-on="on" outlined></v-text-field>
</template>
<v-time-picker v-if="endTimeMenu" v-model="form.values.endTime" :min="form.values.startTime" full-width #click:minute="$refs.menu.save(form.values.endTime)"></v-time-picker>
</v-menu>
</v-col>
</v-row>
</v-form>
</v-card>
<v-btn color="primary" #click="validate()" :disabled="!valid"> Continue </v-btn>
<router-link :to="`/${segment1}`">
<v-btn text> Cancel </v-btn>
</router-link>
</v-stepper-content>
<v-stepper-content step="2">
<v-card class="mb-12" elevation="0">
<v-form ref="form2" lazy-validation v-model="valid2" id="form2">
<v-row>
<v-card-text class="font-weight-bold">
Destination
<v-tooltip right>
<template v-slot:activator="{ on, attrs }">
<v-btn icon v-bind="attrs" v-on="on">
<v-icon color="grey lighten-1">info</v-icon>
</v-btn>
</template>
<span>The scan destination is the end point for a consumer experience. Can be single URL or use URL Groups. </span>
</v-tooltip>
</v-card-text>
</v-row>
<v-row>
<v-col class="col-sm-2 col-lg-2 col-12">
<v-select dense outlined :items="urlTypes" label="Single or Multi URL" v-model="form.values.urlType" :rules="form.rules.urlType"></v-select>
</v-col>
<v-col cols="12" sm="6" md="2">
<v-text-field dense outlined v-model="form.values.url" :rules="form.rules.url" label="URL" required></v-text-field>
</v-col>
</v-row>
<v-row>
<v-card-text class="font-weight-bold"
>Conditions :
<v-tooltip right>
<template v-slot:activator="{ on, attrs }">
<v-btn icon v-bind="attrs" v-on="on">
<v-icon color="grey lighten-1">info</v-icon>
</v-btn>
</template>
<span>Set the conditions for a campaign. If all conditions are true, this campaign will trigger for consumer experience.</span>
</v-tooltip>
</v-card-text>
<v-col cols="12" sm="6" md="4">
<v-select dense outlined :items="attributes" item-text="name" item-value="id" v-model="form.values.attribute" :rules="form.rules.attribute" label="Attribute"></v-select>
</v-col>
<v-col cols="12" sm="6" md="1">
<v-combobox v-model="operator" :items="operators" item-text="operator" item-value="id" label="Operator" outlined dense></v-combobox>
</v-col>
<v-col cols="12" sm="6" md="4">
<!-- <v-text-field dense outlined v-model="form.values.value" :rules="form.rules.value" label="Values" required></v-text-field> -->
<v-text-field v-model="value" :items="values" label="Value" multiple outlined dense></v-text-field>
</v-col>
</v-row>
</v-form>
</v-card>
<v-btn color="primary" #click="validate2()" :disabled="!valid2"> Update </v-btn>
<v-btn text #click="e1 = 1"> Back </v-btn>
</v-stepper-content>
<v-stepper-content step="3"> </v-stepper-content>
</v-stepper-items>
</v-stepper>
</v-card>
</v-col>
</v-row>
</v-container>
</template>
<script>
import Navbar from '../../../components/Navbar'
import Breadcrumbs from '../../../components/Breadcrumbs'
import PanelHeader from '../../../components/PanelHeader'
import axios from 'axios'
import moment from 'moment-timezone'
export default {
components: {
Navbar,
Breadcrumbs,
PanelHeader
},
beforeMount() {},
computed: {
segment1: function () {
const firstSegment = new URL(window.location.href).pathname.split('/')[1]
return `${firstSegment}`
},
timeZone: function () {
console.log('timeZone')
}
},
beforeMount() {},
mounted() {
this.getCampaign()
},
data() {
return {
campaign: {},
form: {
errors: {},
values: {
name: this.campaign.name,
type: 'Marketing',
description: null,
timezone: 'America/New_York',
startDate: new Date(Date.now() - new Date().getTimezoneOffset() * 60000).toISOString().substr(0, 10),
endDate: new Date(Date.now() - new Date().getTimezoneOffset() * 60000).toISOString().substr(0, 10),
startTime: moment().format('HH:mm'),
endTime: '24:00',
urlType: 'Single',
url: 'https://',
attribute: '',
operator: '',
value: ''
},
rules: {
type: [(v) => !!v || 'Type is required'],
name: [(v) => !!v || 'Name is required'],
startDate: [(v) => !!v || 'Start Date is required'],
endDate: [(v) => !!v || 'End Date is required'],
timezone: [(v) => !!v || 'Timezone is required'],
startTime: [(v) => !!v || 'Start Time is required'],
endTime: [(v) => !!v || 'End Time is required'],
urlType: [(v) => !!v || 'URL Type is required'],
url: [(v) => !!v || 'URL is required'],
attribute: [(v) => !!v || 'Attribute is required'],
operator: [(v) => !!v || 'Operator is required'],
value: [(v) => !!v || 'Value is required']
}
},
e1: 1,
valid: false,
valid2: false,
types: ['Product', 'Marketing'],
operator: [],
operators: ['=', '!=', 'in', 'not in'],
value: [],
values: ['Italy', 'Finland', 'Norway'],
timezones: moment.tz.names(),
startDateMenu: false,
endDateMenu: false,
startTimeMenu: false,
endTimeMenu: false,
urlTypes: ['Single', 'Multiple'],
attributes: []
}
},
watch: {
'form.values.attribute'() {
this.operator = null
axios.defaults.headers['Content-Type'] = 'application/json'
let data = {
$root: 'vc_operator',
op: 'read',
brand: 'COLM',
selection: {
filters: [`id:${this.form.values.attribute}`]
},
_SESSION: localStorage.getItem('session')
}
axios.post(`${process.env.VUE_APP_API_ENDPOINT_URL}`, data).then((response) => {
this.operators = response.data.operators
})
}
},
methods: {
getAllData(id) {
let myForm = document.getElementById(id)
console.log(
Array.from(myForm.elements).map((e) => {
return e.value
})
)
},
validate() {
this.$refs.form.validate()
if (this.$refs.form.validate()) {
let data = {
$root: 'vc_rule_attribute',
op: 'read',
brand: 'COLM',
_SESSION: localStorage.getItem('session')
}
axios.defaults.headers['Content-Type'] = 'applcation/json'
axios.post(`${process.env.VUE_APP_API_ENDPOINT_URL}`, data).then((response) => {
this.attributes = response.data.rule_attributes
})
this.e1 = 2
console.info(this.form.values)
} else {
console.info(this.form.values)
}
},
validate2() {
this.$refs.form2.validate()
if (this.$refs.form2.validate()) {
let data = {
id: this.form.values.id,
name: this.form.values.name,
description: this.form.values.description,
start_date: this.form.values.startDate,
end_date: this.form.values.endDate,
priority: '100',
status_id: 1,
type_id: 1
}
let body = {
$root: 'vc_campaign',
op: 'update',
brand: 'COLM',
campaigns: [data],
_SESSION: localStorage.getItem('session')
}
// this.$store
// .dispatch('editCampaign', body)
// .then(() => {
// this.$router.push({
// path: `/campaigns`
// })
// })
// .catch((err) => {
// console.log('Something went wrong: ', err)
// })
} else {
console.info(this.form.values)
}
},
displayTime(time) {
time = time.split(':')[0]
if (time > 12) {
return 'PM'
} else {
return 'AM'
}
},
getCampaign() {
let filters = 'id:' + this.$route.params.id
let body = {
$root: 'vc_campaign',
op: 'read',
brand: 'COLM',
selection: {
filters: [filters]
},
_SESSION: localStorage.getItem('session')
}
axios.defaults.headers['Content-Type'] = 'applcation/json'
axios
.post(`${process.env.VUE_APP_API_ENDPOINT_URL}`, body)
.then((response) => {
if (response.data.status == 0) {
this.campaign = response.data.campaigns[0]
} else {
alert(response.data.statustext)
reject(response.data.statustext)
}
})
.catch((err) => {
console.log('Something went wrong: ', err)
})
}
}
}
</script>
<style></style>
You are basically trying to access a variable which is not defined yet. data() is called only once when you initialize the component. This happens way before you get the response from api and assign a value to this.campaign.
That's why this line doesn't work:
name: this.campaign.name
What you can do instead is something like this:
data() {
return {
campaign: {},
form: {
errors: {},
values: {
name: "",
...
getCampaign() {
...
axios.post(`${process.env.VUE_APP_API_ENDPOINT_URL}`, body)
.then((response) => {
if (response.data.status == 0) {
this.campaign = response.data.campaigns[0]
this.form.values.name = this.campaign.name
...
Keeping your requirements in mind, you can use watch property to keep both the values in sync
Set the initial form.values.name to ''
data() {
return {
campaign: {},
form: {
errors: {},
values: {
name: '',
...
and to keep the values in sync, you can do something like this:
watch: {
campaign: {
handler(newVal) {
this.form.values.name = newVal.name
},
immediate: true
}
}
Try
<p>Campaign Name : {{ campaign?.name }}</p>

How to add two v-text-fields when I click a button dynamically using vuetify

How can I add two v-text-fields when I click on a button, and if I need more v-text-fields I click on the button and it appears in my content.
I would like something like this
I hope you get the idea.
<v-container fluid>
<v-row align="center" >
<v-col >
<v-text-field color="info" v-model="new.name" label="Name" required></v-text-field>
</v-col>
<v-col>
<v-select color="info" :items="arrResp" v-model="new.idResp" label="Boss" required></v-select>
</v-col>
</v-row>
</v-container>
Thank you for your help.
Codepen
<div id="app">
<v-app id="inspire">
<div
v-for="(textField, i) in textFields"
:key="i"
class="text-fields-row"
>
<v-text-field
:label="textField.label1"
v-model="textField.value1"
></v-text-field>
<v-text-field
:label="textField.label2"
v-model="textField.value2"
></v-text-field>
<v-btn #click="remove(i)" class="error">delete</v-btn>
</div>
<v-btn #click="add" class="primary">add</v-btn>
</v-app>
</div>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
textFields: []
}
},
methods: {
add () {
this.textFields.push({
label1: "foo",
value1: "",
label2: "bar",
value2: ""
})
},
remove (index) {
this.textFields.splice(index, 1)
}
}
})
.text-fields-row {
display: flex;
}

how extract id and send it in axios

i have vuetify
<v-col cols="12" md="8">
<v-select :items="driverName" v-bind:id="editedItem.driverId" v-model="editedItem.score" label="score"></v-select>
</v-col>
and me need know resulr id v-bind:id="editedItem.driverId" in :items keep
<v-data-table
:headers="headers"
:items="desserts"
sort-by="calories"
class="elevation-1"
>
i get data with api in axios
here my code https://github.com/ivan556258/crm/blob/master/src/views/table/AppBillAll.vue
<v-col cols="12" md="8">
<v-select :items="drivers" item-value="_id" item-text="lastname" v-model="editedItem.score" label="Счёт">
</v-select>
</v-col>
console.log(this.editedItem.score); // here id

Categories

Resources