I am attempting to use Vuelidate nested validations, but I am surely missing something.
I have a simple component that only contains an input, and a validation making that input required.
<template>
<input type="text" v-model="value" />
</template>
<script>
import useVuelidate from "#vuelidate/core";
import { required } from "#vuelidate/validators";
export default {
name: "MyInput",
setup() {
return { v$: useVuelidate() };
},
props: {
modelValue: String,
},
computed: {
value: {
get() {
return this.modelValue;
},
set(value) {
this.$emit("update:modelValue", value);
},
},
},
validations() {
return {
value: { required },
};
},
};
</script>
And my app just includes two instances of this component, and prints the Vuelidate object for my inspection.
<template>
<pre>{{ v$ }}</pre>
<my-input v-model="myValue1"></my-input>
<br />
<my-input v-model="myValue2"></my-input>
</template>
<script>
import useVuelidate from "#vuelidate/core";
import MyInput from "./components/my-input.vue";
export default {
name: "App",
components: {
MyInput,
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
myValue1: "",
myValue2: "",
};
},
};
</script>
<style scoped>
</style>
This is what's getting printed:
{
"$dirty": false,
"$path": "__root",
"$model": null,
"$error": false,
"$errors": [],
"$invalid": true,
"$anyDirty": false,
"$pending": false,
"$silentErrors": [
{
"$propertyPath": "value",
"$property": "value",
"$validator": "required",
"$uid": "value-required",
"$message": "Value is required",
"$params": {
"type": "required"
},
"$response": false,
"$pending": false
}
],
"$validationGroups": {},
"_vuelidate_undefined": {
"$dirty": false,
"$path": "__root",
"$model": null,
"$error": false,
"$errors": [],
"$invalid": true,
"$anyDirty": false,
"$pending": false,
"$silentErrors": [
{
"$propertyPath": "value",
"$property": "value",
"$validator": "required",
"$uid": "value-required",
"$message": "Value is required",
"$params": {
"type": "required"
},
"$response": false,
"$pending": false
}
],
"$validationGroups": {},
"value": {
"$dirty": false,
"$path": "value",
"required": {
"$message": "Value is required",
"$params": {
"type": "required"
},
"$pending": false,
"$invalid": true,
"$response": false
},
"$externalResults": [],
"$invalid": true,
"$pending": false,
"$error": false,
"$silentErrors": [
{
"$propertyPath": "value",
"$property": "value",
"$validator": "required",
"$uid": "value-required",
"$message": "Value is required",
"$params": {
"type": "required"
},
"$response": false,
"$pending": false
}
],
"$errors": [],
"$model": "",
"$anyDirty": false
}
}
}
Only the second input component is showing up- updating the second input makes the data update, but not the first one. Also note the property "_vuelidate_undefined" which looks like something went wrong. Is some sort of key missing on my components? Am I supposed to namespace the properties I'm validating somehow?
Sandbox with this code can be found here.
Related
How to make this kinda search filter in ag grid vue?
Link for photo: https://ibb.co/cwVq7DD
Docs link: https://www.ag-grid.com/vue-data-grid/tool-panel-columns/#read-only-functions
I tried to use but this search filter not displaying.
<template>
<div>
<ag-grid-vue
style="width: 1270px; height: 175px"
class="ag-theme-alpine"
:columnDefs="columnDefs"
#grid-ready="onGridReady"
:defaultColDef="defaultColDef"
:autoGroupColumnDef="autoGroupColumnDef"
:pivotMode="true"
:sideBar="sideBar"
:rowGroupPanelShow="rowGroupPanelShow"
:pivotPanelShow="pivotPanelShow"
:rowData="rowData"
:alwaysShowHorizontalScroll="true"
:alwaysShowVerticalScroll="true">
</ag-grid-vue>
</div>
</template>
Also You can see vue scripts for ag-grid, that I tried to run for html template :
<script>
import "ag-grid-community/styles/ag-grid.css";
import "ag-grid-community/styles/ag-theme-alpine.css";
import { AgGridVue } from "ag-grid-vue3";
export default {
name: "WbCardDetail",
components: {
AgGridVue,
},
setup() {
return {
columnDefs: [
{ headerName: "№", field: "position", filter: 'agTextColumnFilter', filterParams: {
textMatcher: ({filter, value, filterText}) => {
// custom matching logic that returns a boolean
}
} },
{ headerName: "Фото", field: "thumb", filter: 'agTextColumnFilter' },
{ headerName: "Цена ставки", field: "cpm", filter: 'agTextColumnFilter' },
{ headerName: "SKU", field: "id", filter: 'agTextColumnFilter' },
],
rowData: [
{ position: "1", thumb: "Photo", cpm: "120"},
],
defaultColDef: {
flex: 1,
minWidth: 100,
filter: true,
sortable: true,
enablePivot: true,
enableValue: true,
enableRowGroup: true,
resizable: true,
}
}
},
created() {
this.autoGroupColumnDef = {
minWidth: 200,
};
this.sideBar = {
toolPanels: [
{
id: 'columns',
labelDefault: 'Столбцы',
labelKey: 'columns',
iconKey: 'columns',
toolPanel: 'agColumnsToolPanel',
toolPanelParams: {
suppressRowGroups: true,
suppressValues: true,
suppressPivots: true,
suppressPivotMode: true,
suppressColumnFilter: true,
suppressColumnSelectAll: true,
suppressColumnExpandAll: true,
},
},
],
defaultToolPanel: 'columns',
};
},
}
</script>
Thanks!
I found the answer, search works only on non-free version of ag-grid!
I want to use vue-meta to import a 3rd party SwiperJS script into my nuxt website.
The script is loaded only after mounted()-hook is called so I also initialize it on update(). This kind of works but the v-if on the wrapper does not update.
<template>
<section
class="swiper"
v-if="isSwiperLoaded"
>
<div class="swiper-wrapper"> ... </div>
</section>
</template>
<script>
export default {
data() {
return { swiperLoaded: false, swiperInitialized: false }
},
computed: {
isSwiperLoaded: {
get() {
return this.swiperLoaded
},
set(value) {
this.swiperLoaded = value
},
},
isSwiperInitialized: {
get() {
return this.swiperInitialized
},
set(value) {
this.swiperInitialized = value
},
},
},
head() {
return {
script: [
{
hid: 'swiper',
src: 'https://cdn.jsdelivr.net/npm/swiper#8/swiper-bundle.min.js',
defer: true,
// Changed after script load
callback: () => {
this.isSwiperLoaded = true
},
},
],
link: [
{
rel: 'stylesheet',
type: 'text/css',
href: 'https://cdn.jsdelivr.net/npm/swiper#8/swiper-bundle.min.css',
},
],
}
},
methods: {
initSwiper() {
const swiperOptions = {
...
}
let swiper = new Swiper(this.$el, swiperOptions)
},
},
mounted() {
if (!this.isSwiperInitialized && this.isSwiperLoaded) {
console.log('INIT LOADED')
this.initSwiper()
this.isSwiperInitialized = true
}
},
updated() {
if (!this.isSwiperInitialized && this.isSwiperLoaded) {
console.log('UPD LOADED')
this.initSwiper()
this.isSwiperInitialized = true
}
},
}
</script>
Also I noticed the computed values are normally for getting and setting values from store and not local values. Maybe there is an easier way of updating the variables.
I am rendering a jspreadsheet component with data fetched from fastapi.
<template>
<h1>Synthèse évaluation fournisseur</h1>
<VueJSpreadsheet v-model="data.table" :options="myOption" />
{{ data.columns }}
</template>
<script>
import { reactive, onMounted, isProxy, toRaw, ref } from "vue";
import VueJSpreadsheet from "vue3_jspreadsheet";
import "vue3_jspreadsheet/dist/vue3_jspreadsheet.css";
export default {
components: {
VueJSpreadsheet,
},
setup() {
// var intervalID = setInterval(init, 3000);
var data = reactive({
table: [],
columns: [],
});
async function load_data() {
const response = await fetch("http://LOCALHOST:8080/supplier_overview");
return await response.json();
}
load_data().then((response)=>{
data.table=JSON.parse(response.result.data)
data.columns=(response.result.columns)
});
console.log(data.columns)
const myOption = ref({
columns: data.columns,
search: true,
filters: true,
includeHeadersOnDownload: true,
includeHeadersOnCopy: true,
defaultColAlign: "left",
tableOverflow: true,
tableHeight: "800px",
parseFormulas: true,
copyCompatibility: true,
});
return {
data,
myOption,
};
},
};
</script>
whereas data.columns is rendered correctly in the template, I cannot pass it to myOptions .
The proxy is empty with console.log(data.columns) whereas {{data.columns}} returns the correct array :
[ { "title": "period" }, { "title": "fournisseur" }, { "title": "Qualité" }, { "title": "Rques Qualité" }, { "title": "Logistique" }, { "title": "Rques Logistique" }, { "title": "Cout" }, { "title": "Rques Cout" }, { "title": "Système" }, { "title": "Rques Système" }, { "title": "Mot QLCS" }, { "title": "Note" }, { "title": "Rques" } ]
Any ideas why I cannot passed it correctly to myOptions ?
This problem has nothing to do with the variable myOptions
setup() {
async function load_data() {
const response = await fetch("http://LOCALHOST:8080/supplier_overview");
return await response.json();
}
//the function is async, 1 will be called after 2, so the result is empty
load_data().then((response)=>{
data.table=JSON.parse(response.result.data)
//1
data.columns=(response.result.columns)
});
//2
console.log(data.columns)
}
I have select and input component with made by buefy. Everything is ok till I realize how can I get the data.
I'm sort of new on vuejs. So I will be glad if you help me out.
I'm getting dynamic form from backend
So my question is how can get values these inputs and submit to backend again with getOffer() methot.
Here is my codes;
Input.vue
<template>
<b-field :label="fieldLabel">
<b-input
:name="inputName"
:type="inputType"
:maxlength="inputType == 'textarea' ? 200 : null"
></b-input>
</b-field>
</template>
<script>
export default {
name: "Input",
props: {
inputType: {
type: String,
required: true,
default: "text",
},
inputName: {
type: String,
required: true,
},
fieldLabel: {
type: String,
required: true,
}
}
};
</script>
Home.vue
<template>
<div class="container is-max-desktop wrapper">
<div v-for="element in offer" :key="element.id">
<Input
v-model="element.fieldValue"
:value="element.fieldValue"
:fieldLabel="element.fieldLabel"
:inputType="element.fieldType"
:inputName="element.fieldName"
v-if="element.fieldType != 'select'"
class="mb-3"
/>
<Select
v-model="element.fieldValue"
:fieldLabel="element.fieldLabel"
:options="element.infoRequestFormOptions"
:selectName="element.fieldName"
v-if="element.fieldType == 'select'"
class="mb-3"
/>
</div>
<b-button type="is-danger" #click="getOffer()">GET</b-button>
</div>
</template>
<script>
import axios from "axios";
import Select from "../components/Select.vue";
import Input from "../components/Input.vue";
export default {
name: "Home",
data() {
return {
offer: [],
};
},
components: {
Select,
Input,
},
methods: {
getOfferForm() {
axios({
method: "get",
url: `/GETDYNAMICFORM`,
})
.then((response) => {
this.offer = response.data;
})
.catch(() => {
this.$buefy.toast.open({
duration: 3000,
message: "oops",
position: "is-bottom",
type: "is-danger",
});
});
},
getOffer() {
console.log(this.offer);
},
},
created() {
this.getOfferForm();
},
};
</script>
Example Dynamic Form Response like;
[
{
"id": 58,
"fieldLabel": "Name Surname",
"providerLabel": "Name Surname",
"fieldName": "nmsrnm",
"fieldType": "text",
"fieldValue": null,
},
{
"id": 60,
"fieldLabel": "E-mail",
"providerLabel": "E-mail",
"fieldName": "e_mail_60",
"fieldType": "email",
"fieldValue": null,
},
{
"id": 2,
"fieldLabel": "Budget",
"providerLabel": "Budget",
"fieldName": "bdget",
"fieldType": "select",
"fieldValue": "",
"infoRequestFormOptions": [
{
"id": 1,
"orderNum": 0,
"optionValue": 0,
"optionText": "Select",
"minValue": null,
"maxValue": null
},
{
"id": 2,
"orderNum": 1,
"optionValue": 1,
"optionText": "10-30",
"minValue": 10,
"maxValue": 30
}
]
}
]
I need to dynamically load (part of) a form schema asynchronously.
For example, I want to create the schema after a REST call.
I started using vue-form-generator,
I tried to manipulate the schema creating a component that:
creates a text input with a label Name-TEST-failed
asynchronously call a function that changes the label in Name-TEST-success
Code:
<template>
<div class="panel-body">
<vue-form-generator :schema="schema" :model="model" :options="formOptions"></vue-form-generator>
</div>
</template>
<script>
import Vue from 'vue';
import VueFormGenerator from "vue-form-generator";
Vue.use(VueFormGenerator);
export default {
created(){
setTimeout(() => {
console.log("start!");
Vue.set(this.$data.schema.fields,
[{
type: "input",
inputType: "text",
label: "Name-TEST-success",
model: "name",
placeholder: "Your name",
featured: true,
required: true
}]
)
console.log("end!");
}, 1000);
},
data() {
return {
model: {
name: "John Doe"
},
schema: {
fields: [{
type: "input",
inputType: "text",
label: "Name-TEST-failed",
model: "name",
placeholder: "Your name",
featured: true,
required: true
}]
},
formOptions: {
validateAfterLoad: true,
validateAfterChanged: true
}
}
}
}
</script>
both the messages start! and end! appear in the console, but the label of the input test does not change.
How can I change the schema (and the model) dynamically?
Just put the schema in a computed property and make it dependant on a data property. So the schema will change everytime you change a property on which it depends.
export default {
created(){
setTimeout(() => {
console.log("start!");
this.labelName = "Name-TEST-success"
}, 1000);
},
data() {
return {
model: {
name: "John Doe"
},
// Add a new property that you can change as you wish
labelName: 'Name-TEST-failed",
formOptions: {
validateAfterLoad: true,
validateAfterChanged: true
}
}
},
computed: {
schema () {
var result = {
fields: [{
type: "input",
inputType: "text",
label: this.labelName,
model: "name",
placeholder: "Your name",
featured: true,
required: true
}]
}
return result
}
}
}
UPDATE:
You don't need computed properties, they can lead to problems with validity check. Just manipulate the properties direclty.
PS: The $set method needs an index to work correct on arrays.
export default {
created(){
setTimeout(() => {
console.log("start!");
this.fieldObject.label = "Name-TEST-success"
}, 1000);
},
data() {
var fieldObject = {
type: "input",
inputType: "text",
label: this.labelName,
model: "name",
placeholder: "Your name",
featured: true,
required: true
}
return {
fieldObject, // now you can change label with "fieldObject.label = ..."
model: {
name: "John Doe"
},
schema: {
fields: [fieldObject]
},
formOptions: {
validateAfterLoad: true,
validateAfterChanged: true
}
}
}
}