Clone element form - vue.js

I am trying to unsuccessfully duplicate form items
Hello everyone.
I have a form and I need a button to duplicate fields every time the user clicks.
My form:
<v-layout v-for="(phone, index) in people.phones" :key="index" row
wrap>
<v-flex md7>
<v-text-field v-model="phone.number" label="Phone number*" required>
</v-text-field>
</v-flex>
<v-flex md5 class="pl-3">
<v-select v-model="phone.type" :rules="phone.tipoRules" required
:items="['WhatsApp', 'Commercial', 'Home']" label="Phone type*">
</v-select>
</v-flex>
</v-layout>

You just have to add an button to your template and define a #click function for it, which adds a new item to your people.phones array.
Template:
<button #click="addNumber">
add number
</button>
Vue:
methods: {
addNumber: function(){
this.people.phones.push({number: "", type: ""});
}
}
Simplified example: http://jsfiddle.net/wpako31u/

Related

Modify drop down value with preset value

I'm designing a form that can both used to create and edit something.
The form has a dropdown, which isn't initialized when created, but is set with a value when used for editing.
I want to be able to modify the value of the drop down, both for creating & updating, yet is only working when the mode is CREATE.
Here's my template:
<template>
<v-row justify="center">
<v-form ref="form" v-model="valid" lazy-validation>
<v-text-field v-model="title" label="Title*" :rules="rules.fieldRules" prepend-icon="mdi-text">
</v-text-field>
<v-text-field v-model="website_link" label="URL" prepend-icon="mdi-web">
</v-text-field>
<h3>Description</h3>
<text-editor #update:modelValue="getValue" :rules="rules.fieldRules" :modelValue="description">
</text-editor>
<br />
<v-select v-model="selectedState" :readonly="false" :items="items" filled label="Which state?*" prepend-icon="mdi-help"></v-select>
<v-file-input v-model="files" prepend-icon="mdi-camera" multiple label="File input"></v-file-input>
<v-layout v-for="file of files" :key="file">
<v-img :src="generateUrl(file)" max-width="10%" max-height="10%">
</v-img>
</v-layout>
<v-combobox v-model="tags" prepend-icon="mdi-lightbulb" label="Tags" chips clearable multiple filled
rounded></v-combobox>
<v-btn :disabled="mode == 'EDIT' ? false : !valid" color="success" class="mr-4" #click="validate">
Validate
</v-btn>
<v-btn color="blue" class="mr-4" #click="backToProfile">
Back
</v-btn>
</v-form>
</v-row>
</template>
selectedState is a computed method described as below here:
selectedState: {
get() {
if (this.mode == 'CREATE') {
return this.state
} else {
const state = this.items.filter((item) => item.value = this.currentConcept.state)[0].title;
this.setState(state);
return this.state;
}
},
set(value) {
console.log(`value: ${value}`)
this.state = value;
}
}
Am I missing something?
TIA

Uniquely identify button click for individual v-cards in vuejs

I am using vuejs with vuetify 1.5 i am little bit stuck in my code the issue here is i have an array of objects and based on that multiple v-cards getting generated for all the values present in the array of objects.
In multiple cards i have a button expand so by default i want to show only 4 values and onclicking expand the rest of values will be shown in the cards and that expand button but the issue is all cards will have the same expand button so on clicking expand all cards are expanding and its values are shown but I want uniquely that means when i click expand only one cards value gets expanded rest of the cards will not expand.
here is my code :-
expandToggleHandler() {
this.isExpand = !this.isExpand
},
<v-card
style="display: inline-block;"
class="cardView"
:key="rowIndex"
#sort="onSort"
#click.native = "onRowClicked(row)"
>
<v-layout wrap>
<v-flex xs12 style="text-align: center; font-weight: bold;" :style="fixedColumn && clickableColumn || clickableColumn ? 'color: #ad00ff !important;' : 'color: #3399bb'">
{{row[Object.keys(row)[0]]}}
<br />
</v-flex>
</v-layout>
<v-layout wrap>
<template v-if="!isExpand">
<template v-for= "(key, idx) of cardViewColumn">
<template v-for="(col, i) of key">
<template v-if="idx <= 1">
<v-flex xs6 sm6 md6 style="text-align: center;">
<span style="font-weight: bold;">{{ col }}</span> <br /> {{row[col]}}
</v-flex>
</template>
</template>
</template>
</template>
<template v-if="isExpand">
<template v-for= "(key, idx) of cardViewColumn">
<template v-for="(col, i) of key">
<v-flex xs6 sm6 md6 style="text-align: center;">
<span style="font-weight: bold;">{{ col }}</span> <br /> {{row[col]}}
</v-flex>
</template>
</template>
</template>
<md-button #click.stop="expandToggleHandler">{{ toggleExpandAndCollapse }}</md-button>
</v-layout>
</v-card>
and here is the image :-
in image you can see i have pressed expand button for single cards but event is getting fired for other cards too.
How can i resolve it any help with example would be appreciated.
You are using the single variable isExpand for multiple v-card components. To solve your problem I suggest to convert the variable to an array and use rowIndex as the index.
Your variable declaration should look like this:
isExpand: []
Your templates would use it like this.
<template v-if="!isExpand[rowIndex]">
</template>
<template v-else>
</template>
Please note that I replaced the second v-if with a v-else so the isExpand variable isn't checked twice.
The method would become:
expandToggleHandler(rowIndex) {
this.isExpand[rowIndex] = !this.isExpand[rowIndex]
}
And you access it like this:
<md-button #click.stop="expandToggleHandler(rowIndex)">{{ isExpand[rowIndex] ? 'Collapse' : 'Expand'}}</md-button>
I didn't know what toggleExpandAndCollapse does but I guess it handles the button label.

Datepicker doesn't get validated on input

I'm currently using the datepicker component in one of my projects. The component is supposed to throw an error message if I click in and out of the empty textfield of the datepicker menu. So far the error message only works if I enter a value and then remove it again.
There are already rules which check if the date-value of the textfield is longer than 0 Digits or not null.
HTML
<div id="app">
<v-app id="inspire">
<v-container grid-list-md>
<v-form v-model='validForm'>
<v-layout row wrap>
<v-flex xs12 lg6>
<v-text-field
v-model="text"
clearable
label="Regular Textfield"
:rules="rulesDatefield"
v-on="on"
></v-text-field>
<v-menu
v-model="menu1"
:close-on-content-click="false"
full-width
max-width="290"
>
<template v-slot:activator="{ on }">
<v-text-field
v-model='date'
clearable
label="Datefield"
readonly
:rules="rulesDatefield"
v-on="on"
></v-text-field>
</template>
<v-date-picker
v-model="date"
#change="menu1 = false"
></v-date-picker>
</v-menu>
</v-flex>
</v-layout>
</v-form>
<v-btn :disabled="!validForm" #click='printValues()' color='primary'>Create</v-btn>
</v-container>
</v-app>
</div>
JS
new Vue({
el: '#app',
data: () => ({
validForm: false,
text: '',
date: '',
menu1: false,
rulesDatefield: [
v => String(v).length > 0 || 'Field is empty!',
v => v !== null || 'Field is empty!'
]
}),
methods: {
printValues: function() {
window.alert('Entered Text: ' + this.text + '\nEntered Date:' + this.date)
}
}
})
Codepen: https://codepen.io/anon/pen/XLLNZM?&editable=true&editors=101
I expect an error message from the date-textfield like in the regular textfield above if I enter and exit the datepicker without selecting a date.
<v-text-field
v-model="date"
clearable
readonly
label="Datefield"
:rules="rulesDatefield"
v-on="on"
#blur="date = date || null"
></v-text-field>
Seems strange but works, as you intended.

Using Vuelidate with v-for and props

How are you all using Vuelidate with v-for. I can't seem to get it to work correctly. It either validates each of the text-fields in my form, or it throws an error. I only want it to validate the field that is being entered, and not other fields that are created from v-for.
In the below template you can see the creds in amazonCredsArray are props passed in from the parent component. Depending on the number of hashes in the amazonCredsArray is the number of forms that are created. With the below setup, the text-field below is created multiple times, and Vuelidate validates ALL these fields when just 1 is entered. I have :key defined on the field but it doesn't help.
Template
<template>
<v-container fluid grid-list-lg class="come_closer">
<v-layout row wrap>
<v-flex xs12 v-for="creds in amazonCredsArray" :key="creds.id" class="pb-4">
<v-card class="lightpurple">
<v-card-title>
<v-icon class="my_dark_purple_text">language</v-icon>
<h1 class="title oswald my_dark_purple_text pl-2 pr-5">ENTER YOUR AMAZON CREDENTIALS BELOW</h1>
</v-card-title>
<v-form>
<v-layout xs12 row wrap class="mx-auto" >
<v-flex xs12>
<v-text-field
:error-messages="sellerIdErrors"
required
:key="creds.seller_id"
color="indigo"
label="Amazon Seller Id"
v-model="creds.seller_id"
prepend-icon="person"
#input="$v.seller_id.$touch()"
#blur="$v.seller_id.$touch()"
></v-text-field>
</v-flex>
And my offending script:
Script
import { validationMixin } from 'vuelidate';
import { required } from 'vuelidate/lib/validators';
var url = "https://bc-only-rates-trimakas.c9users.io";
export default {
mixins: [validationMixin],
validations: {
seller_id: { required }
},
props: ["amazonCredsArray"],
computed:{
sellerIdErrors () {
const errors = []
if (!this.$v.seller_id.$dirty) return errors
!this.$v.seller_id.checked && errors.push('Please provide us your seller id')
return errors
},
},

How to trigger a method at component opening in vuejs?

I have a main component that is used to display items using a loop:
<v-list-tile v-for="(item, index) in items" :key="item.title">
...
<report type="item.type"> </report>
</v-list>
The report component is used to report abuse on the system, and report type may vary depending on the item from the parent loop.
As users are very unlikely to use report on a regular basis I would like to only load v-select elements when the Dialog (modal) is opened.
Using created or mounted triggers the loading method everytime the report component is generated and not when the report component is opened.
Is there a smart way to prevent this and only have the loading method within report being triggered only when the component is opened.
=== Report.vue file ===
=== This file is loaded in the parent component
<template lang="html">
<v-dialog v-model="dialog" persistent max-width="800px" lazy>
<v-btn icon slot="activator">
<v-icon>error_outline</v-icon>
</v-btn>
<v-card>
<v-card-title>
<div class="headline"><v-icon large>error_outline</v-icon> Reporting</div>
</v-card-title>
<v-card-text>You are about to report the following {{ reportType }}: "<i>{{ reportContent.title }}</i>"
<v-container v-if="this.$store.getters['report/getLoadedState']" grid-list-md >
<v-layout wrap>
<v-flex xs12 sm12>
<v-select
label="Select a reason"
required
cache-items
:items="items"
item-text="title"
item-value="id"
></v-select>
</v-flex>
<v-flex xs12 sm12>
<v-text-field
label="Please provide additional information here"
multi-line></v-text-field>
</v-flex>
</v-layout>
</v-container>
<v-container v-else grid-list-md>
<v-layout>
<v-flex xs12 sm12>
Loading
</v-flex>
</v-layout>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="green darken-1" flat="flat" #click.native="cancel">Cancel</v-btn>
<v-btn color="green darken-1" flat="flat" #click.native="report">Report</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
export default {
name: 'report',
data () {
return {
dialog: false,
items: this.$store.getters['report/getItems']
}
},
props: ['reportType', 'reportContent'],
methods: {
cancel () {
this.dialog = false
},
report () {
this.dialog = false
},
loadReasons (type) {
if (!this.$store.getters['report/getLoadedState']) {
this.$store.dispatch('report/setItems', type)
}
}
}
}
</script>
<style lang="css" scoped>
</style>
PS 1: I'm not using JQuery and do not intend to use it
PS 2: Calling the method outside of the report component is not an option as I want to maximize reusability of this compenent and only pass arguments to it using props
How I have done this in the past is to use a "dynamic component." Vue uses a special syntax for dynamic components <component v-bind:is="currentView"></component> see: Vue dynamic components
You can set the "currentView" property to null and then on a button click another event set the currentView to report. Doing it this way will allow you to use the mounted method as the component is not rendered or created until it is dynamically called.
<component :is="myComponent"></component>
<v-btn #click="loadComponent">Show Report</v-btn>
then...
data:{
myComponent: null;
},
methods: {
loadComponent: function(){
this.myComponent = 'report';
}
}
P.S. You can of course use this method to render any other components in the same place. i.e. you can set the 'currentView' to the name of any available component and it will be instantly rendered in its place.
I ended up using a watch on the boolean managing the dialog...
Make a function which loads the v-select. Don't initialize it just create it. Now whenever user clicks the report model you can initialize multiple functions using v-on:click or #click.
For example :
<div v-on:click="return function() { fn1('foo');fn2('bar'); }()"> </div>
This solution can also be found on :
Stackoverflow Link