Using example scrollToErrors gives error TypeError: onSubmitInvalid is not a function #1018
fdverwoerd
started this conversation in
General
Replies: 3 comments 1 reply
-
My vue component: <script setup lang="ts">
import Swal from 'sweetalert2';
import {useAddressAutocomplete} from "./useAddressAutocomplete";
import {useFieldsTransformToRequest} from "./useFieldsTransformToRequest";
import {ref, inject, onMounted, watch} from 'vue';
import { getNode } from '@formkit/core'
import {token} from '@formkit/utils';
import type {Child} from "./types/Child";
// @see _formjson script tag.
// This contains all the config for the app.
// These options correlate with fields on the element.
// These are choice field with radio and required inputs. And a default value. As to make sure these values are always present.
type LisyFieldOption = "required" | "optional" | "hidden";
type LisyFreeField = {
label: string,
type: "text" | "textarea" | "number",
}
type LisyConfig = {
endpoint: string|false,
foundationId: string|false,
fieldOptions: {
fieldOptionsFamilyNumber: LisyFieldOption,
fieldOptionsChildCount: LisyFieldOption,
fieldOptionsParentCount: LisyFieldOption,
fieldOptionsIncomeAmount: LisyFieldOption,
fieldOptionsIncomePeriod: LisyFieldOption,
fieldOptionsRemarkParent: LisyFieldOption,
fieldOptionsHelperInfo: LisyFieldOption,
fieldOptionsRemarkChild: LisyFieldOption,
fieldOptionsSchool: LisyFieldOption,
fieldOptionsClass: LisyFieldOption,
},
freeFields: LisyFreeField[]
}
const debug = ref(true);
const lisyConfig = inject<LisyConfig>("lisyConfig")!;
// Request composable. Here we transform the FormKit data to required format for Lisy Post endpoint.
const { transformToRequest, amenityRequestBody, filesArray } = useFieldsTransformToRequest();
// Address autocomplete stuff.
const { addressAutocomplete, postalCodeInput, housenumberInput, streetInput, localityInput } = useAddressAutocomplete();
const makeAmenityRequest = async (fields: any) => {
// Fake timeout loading...
transformToRequest(fields);
console.log('OUTSIDE', amenityRequestBody.value);
const endpoint = lisyConfig.endpoint as string; // When here it should be string and not false. The false is only present for when it's not set.
await fetch(endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(amenityRequestBody.value),
})
.then((response) => {
console.log(response);
if (response.status === 400) {
console.error('Status 400', response);
}
if (response.ok) {
console.info('Swooosh, request sent!');
Swal.fire({
position: 'center',
icon: 'success',
title: 'Je aanvraag is verstuurd!',
showConfirmButton: false,
timer: 1500
})
}
return response.json()
})
.then((data) => {
// Log the response.
console.log('Response', data);
logErrors(data);
})
.catch(error => {
console.log('error', error);
})
function logErrors(errorObjects: any) {
// Extract and print the error messages
errorObjects.forEach((item: any) => {
// This is latest output from the API
if ('outputs' in item) {
item.outputs.errors.forEach((error: any) => {
console.info(`Error: ${error.path}`);
console.table(error)
});
} else {
console.info(`Error: ${item.path}`);
console.table(item)
}
});
}
}
const lisyForm = ref();
const lisyFormRef = ref();
// watch works directly on a ref
watch(lisyForm, async (newLisyForm, oldLisyForm) => {
if (newLisyForm !== oldLisyForm) {
// console.log('lisyForm changed', lisyForm.value);
// console.log(JSON.parse(JSON.stringify(lisyForm.value)))
}
})
// Just and array of tokens to keep track of the children for rendering the same amount of input groups.
const childItems = ref([{token: token(), requestsPerChild: [{token: token()}]}]);
const addChild = () => {
childItems.value.push({token: token(), requestsPerChild: [{token: token()}]})
console.log(childItems.value);
}
const removeItem = (e: any) => {
console.log('e', e);
e.preventDefault();
Swal.fire({
title: 'Weet je het zeker?',
text: "Dit verwijderd alle ingevulde gegevens.",
icon: 'warning',
width: 600,
confirmButtonText: 'Ja verwijder kindgegevens',
showCancelButton: true,
customClass: {
confirmButton: 'btn outline-solid',
cancelButton: 'btn white'
},
buttonsStyling: false,
}).then((result) => {
if (result.isConfirmed) {
const key = e.target.dataset.id;
childItems.value = childItems.value.filter(item => {
return item.token !== key;
})
}
});
}
const removeRequest = (child: Child, e: any) => {
console.log('child', child);
console.log('e', e);
e.preventDefault();
Swal.fire({
title: 'Weet je het zeker?',
text: "Dit verwijderd deze aanvraag.",
icon: 'warning',
width: 600,
confirmButtonText: 'Ja verwijder aanvraag',
showCancelButton: true,
customClass: {
confirmButton: 'btn outline-solid',
cancelButton: 'btn white'
},
buttonsStyling: false,
}).then((result) => {
if (result.isConfirmed) {
const key = e.target.dataset.id;
child.requestsPerChild = child.requestsPerChild.filter((item:any) => {
return item.token !== key;
})
}
});
}
// Better typing.
function addRequest(child: { token: string, requestsPerChild: [{token: string, [key: string]: string|number}]}) {
child.requestsPerChild.push({token: token()});
}
const pId = ref("PID-TEST-"+Date.now());
onMounted(() => {
console.info('Lisy mounted and config: ', lisyConfig);
/**
* Helper function to populate form with debug values.
*/
if (debug) {
const debugValues = {
firstName: "Rick",
infix: "van der op",
lastName: "test",
zipcode: "1111 AB",
housenumber: "11a",
city: "Amsterdam",
email: "[email protected]",
address: "Streett",
phoneNumber: "0612345678",
childCount: 3,
parentCount: 121720000,
incomeAmount: "1337,69",
incomePeriod: "year",
remark: "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium dicta distinctio doloribus eaque eos esse fugit ipsa, ipsum magnam nemo nesciunt non nostrum placeat quam quis quisquam sit. Expedita, itaque.",
// remark: "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium dicta distinctio doloribus eaque eos esse fugit ipsa, ipsum magnam nemo nesciunt non nostrum placeat quam quis quisquam sit. Expedita, itaque.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium dicta distinctio doloribus eaque eos esse fugit ipsa, ipsum magnam nemo nesciunt non nostrum placeat quam quis quisquam sit. Expedita, itaque.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium dicta distinctio doloribus eaque eos esse fugit ipsa, ipsum magnam nemo nesciunt non nostrum placeat quam quis quisquam sit. Expedita, itaque.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium dicta distinctio doloribus eaque eos esse fugit ipsa, ipsum magnam nemo nesciunt non nostrum placeat quam quis quisquam sit. Expedita, itaque.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium dicta distinctio doloribus eaque eos esse fugit ipsa, ipsum magnam nemo nesciunt non nostrum placeat quam quis quisquam sit. Expedita, itaque.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium dicta distinctio doloribus eaque eos esse fugit ipsa, ipsum magnam nemo nesciunt non nostrum placeat quam quis quisquam sit. Expedita, itaque.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium dicta distinctio doloribus eaque eos esse fugit ipsa, ipsum magnam nemo nesciunt non nostrum placeat quam quis quisquam sit. Expedita, itaque.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium dicta distinctio doloribus eaque eos esse fugit ipsa, ipsum magnam nemo nesciunt non nostrum placeat quam quis quisquam sit. Expedita, itaque.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium dicta distinctio doloribus eaque eos esse fugit ipsa, ipsum magnam nemo nesciunt non nostrum placeat quam quis quisquam sit. Expedita, itaque.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium dicta distinctio doloribus eaque eos esse fugit ipsa, ipsum magnam nemo nesciunt non nostrum placeat quam quis quisquam sit. Expedita, itaque.",
childrenList: [
{
"gender": "2",
"firstName": "Voornaam",
"lastName": "Achternaam",
"birthdate": "2010-11-12",
"requestsPerChild": [
{
"voorziening": "Mountainbike",
"requestAmount": "123,45",
"aanbieder": "Bergbikes",
"helperInfo": "Coach"
}
]
}
]
}
// debugValues
Object.entries(debugValues).forEach(([key, value]) => {
// Using FormKit getNode and input.
const node = getNode(key);
node?.input(value);
})
}
// const a = new AmenityRequest();
// console.info('Amenity request: ', 1);
})
function test() {
const zipcodeNode = getNode('zipcode');
console.log("log", zipcodeNode);
zipcodeNode?.input("3816 WD");
}
// Define a function to read a single file and return a Promise that resolves with its content as base64
function readFileAsBase64(file: File): Promise<string> {
return new Promise<string>((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
if (reader.result && typeof reader.result === "string") {
const base64Content = btoa(reader.result);
resolve(base64Content);
} else {
reject(new Error("Failed to read the file as base64."));
}
};
reader.readAsBinaryString(file);
});
}
// Define a function to read multiple files and create the desired object
async function processFiles(files: FileList): Promise<{ name: string, content: string }[]> {
const outputList: { name: string, content: string }[] = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
const content = await readFileAsBase64(file);
outputList.push({ name: file.name, content });
}
return outputList;
}
async function onFileChange(event: Event) {
if (!event.target) {
return;
}
console.log(event.target);
const target = event.target as HTMLInputElement;
const files = target.files;
if (files) {
const result = await processFiles(files);
console.log(result);
filesArray.value = result;
}
}
</script>
<template>
<div class="lisy-form-wrapper form-grid" v-if="lisyConfig.endpoint !== false && lisyConfig.foundationId !== false">
<FormKit type="form"
lang="nl"
ref="lisyFormRef"
v-model="lisyForm"
form-class="lisy-form form-grid"
id="lisy_form"
submit-label="Verstuur aanvraag"
:submit-attrs="{
inputClass: 'btn orange',
wrapperClass: 'btn__wrapper btn__wrapper--right',
}"
@submit="makeAmenityRequest"
:actions="true"
>
<FormKit name="id"
id="id"
type="hidden"
:value="pId"></FormKit>
<FormKit name="stichtingId"
id="stichtingId"
type="hidden"
:value="lisyConfig.foundationId"></FormKit>
<FormKit type="group" name="partner">
<h2>Partner</h2>
<!-- address-input-group is used for the locality fields. @see address_autocomplete.ts -->
<div class="form-grid address-input-group">
<FormKit v-if="lisyConfig.fieldOptions.fieldOptionsFamilyNumber !== 'hidden'"
type="text"
name="familyNumber"
id="familyNumber"
:validation="[
['lisy_required', lisyConfig.fieldOptions.fieldOptionsFamilyNumber],
['length', 1,5]
]"
label="Gezinsnummer"
outer-class="form-grid-column-12"
></FormKit>
<FormKit type="text"
name="firstName"
id="firstName"
label="Voornaam"
validation="required|length:1,100"
outer-class="form-grid-column-8"
></FormKit>
<FormKit type="text"
name="infix"
id="infix"
label="Tussenvoegsel"
validation="length:0,100"
outer-class="form-grid-column-4"
></FormKit>
<FormKit type="text"
name="lastName"
id="lastName"
label="Achternaam"
validation="required|length:1,100"
outer-class="form-grid-column-12"
></FormKit>
<!-- Special Address form which autocompletes. -->
<FormKit type="text"
name="zipcode"
id="zipcode"
label="Postcode"
v-model="postalCodeInput"
outer-class="form-grid-column-5"
input-class="js-postal-code"
placeholder="1234 AA"
:validation="[['required'], ['matches', /^[1-9][0-9]{3} ?(?!sa|sd|ss)[a-z]{2}$/i]]"
:validation-messages="{
matches: 'Postcode moet voldoen aan format: 1234 AA',
}"
@change="addressAutocomplete"
></FormKit>
<FormKit type="text"
name="housenumber"
id="housenumber"
v-model="housenumberInput"
label="Huisnummer en toevoeging"
input-class="js-housenumber"
outer-class="form-grid-column-7"
placeholder="10a"
validation="required|length:1,100"
@change="addressAutocomplete"
></FormKit>
<FormKit type="text"
name="city"
id="city"
v-model="localityInput"
label="Plaats"
input-class="js-locality"
outer-class="form-grid-column-12"
validation="required"
></FormKit>
<FormKit type="text"
name="address"
id="address"
v-model="streetInput"
label="Straatnaam"
input-class="js-street"
outer-class="form-grid-column-12"
validation="required|length:1,100"
></FormKit>
<FormKit type="email"
name="email"
id="email"
label="Je e-mailadres"
outer-class="form-grid-column-12"
validation="required|length:1,100"
></FormKit>
<FormKit type="tel"
name="phoneNumber"
id="phoneNumber"
label="Je telefoonnummer"
outer-class="form-grid-column-12"
validation="required|length:1,100"
></FormKit>
<FormKit v-if="lisyConfig.fieldOptions.fieldOptionsChildCount !== 'hidden'"
type="text"
number="integer"
name="childCount"
id="childCount"
label="Aantal kinderen"
min="1"
max="100"
validation-visibility="live"
:validation="[
['*number'],
['lisy_required', lisyConfig.fieldOptions.fieldOptionsChildCount],
]"
outer-class="form-grid-column-12"
></FormKit>
<FormKit v-if="lisyConfig.fieldOptions.fieldOptionsParentCount !== 'hidden'"
type="select"
:validation="[
['lisy_required', lisyConfig.fieldOptions.fieldOptionsParentCount],
]"
name="parentCount"
id="parentCount"
label="Aantal ouders"
outer-class="form-grid-column-12"
placeholder="Kies een optie"
:options="{
121720000: '1 ouder',
121720001: '2 ouders',
121720002: 'Anders',
}"></FormKit>
<FormKit v-if="lisyConfig.fieldOptions.fieldOptionsIncomeAmount !== 'hidden'"
:validation="[
['lisy_required', lisyConfig.fieldOptions.fieldOptionsIncomeAmount],
]"
type="number"
name="incomeAmount"
id="incomeAmount"
label="Inkomen bedrag"
step=".01"
outer-class="form-grid-column-12"
></FormKit>
<FormKit v-if="lisyConfig.fieldOptions.fieldOptionsIncomePeriod !== 'hidden'"
:validation="[
['lisy_required', lisyConfig.fieldOptions.fieldOptionsIncomePeriod],
]"
type="select"
name="incomePeriod"
id="incomePeriod"
label="Inkomen periode"
help="Over welke periode was dit inkomen?"
:options="{
month: 'Maand',
year: 'Jaar',
fake: 'TODO? Wat is dit?',
}"/>
<FormKit v-if="lisyConfig.fieldOptions.fieldOptionsRemarkParent !== 'hidden'"
:validation="[
['lisy_required', lisyConfig.fieldOptions.fieldOptionsRemarkParent],
['length', 0,2000]
]"
type="textarea"
name="remark"
id="remark"
label="Opmerking"
rows="5"
/>
<FormKit
type="file"
label="Bestanden"
name="files"
help="Voeg optioneel bestand(en) toe."
multiple="true"
@change="onFileChange"
/>
</div>
</FormKit>
<FormKit type="list" name="childrenList">
<h2>Kindgegevens</h2>
<p>Gegevens van kind(eren) voor wie je een aanvraag doet</p>
<FormKit
v-for="(child, index) in childItems"
:key="child.token"
:id="child.token"
:name="child.token"
type="group"
>
<div class="lisy-form-child fieldset form-grid">
<h3 class="form-grid-column-6">Kind {{index+1}}</h3>
<FormKit v-if="index !== 0" type="button" @click="removeItem" prefix-icon="trash" input-class="btn outline" :data-id="child.token"
wrapper-class="btn__wrapper btn__wrapper--right" outer-class="form-grid-column-6">
Verwijder
</FormKit>
<FormKit
type="radio"
name="gender"
validation="required"
label="Geslacht"
:options="{
1: 'Jongen',
2: 'Meisje',
12720000: 'X',
}"
required
/>
<div class="form-grid">
<FormKit type="text"
name="firstName"
label="Voornaam"
value="Voornaam"
validation="required"
outer-class="form-grid-column-8"
></FormKit>
<FormKit type="text"
name="infix"
label="Tussenvoegsel"
outer-class="form-grid-column-4"
></FormKit>
<FormKit type="text"
name="lastName"
label="Achternaam"
value="TEST"
validation="required"
outer-class="form-grid-column-12"
></FormKit>
</div>
<FormKit type="date"
name="birthdate"
label="Geboortedatum"
value="2010-11-12"
validation="required"
></FormKit>
<FormKit type="list" name="requestsPerChild">
<FormKit
v-for="(request, index) in child.requestsPerChild"
:key="request.token"
:id="request.token"
:name="request.token"
type="group"
>
<div class="lisy-form-request form-grid fieldset">
<h4 class="form-grid-column-6">Aanvraag {{index+1}}</h4>
<FormKit v-if="index !== 0" type="button" @click="removeRequest(child, $event)" prefix-icon="trash" input-class="btn outline" :data-id="request.token"
wrapper-class="btn__wrapper btn__wrapper--right" outer-class="form-grid-column-6">
Verwijder
</FormKit>
<FormKit type="textarea"
name="voorziening"
validation="required"
label="Wat vraag je aan?"
rows="5"></FormKit>
<FormKit type="number"
label="Bedrag van je aanvraag?"
value="321.99"
step=".01"
validation="required|number"
name="requestAmount"
outer-class="form-grid-column-6"
help="Indien het bedrag niet bekend is vul je 0,- in."></FormKit>
<FormKit type="text"
name="aanbieder"
label="Aanbieder"
value="Aanbieder"
validation="required"
outer-class="form-grid-column-6"
help="Vul hier de school, sportclub of andere organisatie in."></FormKit>
<FormKit v-if="lisyConfig.fieldOptions.fieldOptionsHelperInfo !== 'hidden'"
:validation="[
['lisy_required', lisyConfig.fieldOptions.fieldOptionsHelperInfo],
['length', 0,2000]
]"
type="text"
name="helperInfo"
label="Helper gegevens"
value="Helper X"
help="Gegevens van begeleider/coach"
outer-class="form-grid-column-12"></FormKit>
<FormKit v-if="lisyConfig.fieldOptions.fieldOptionsRemarkChild !== 'hidden'"
:validation="[
['lisy_required', lisyConfig.fieldOptions.fieldOptionsRemarkChild],
['length', 0,2000]
]"
type="textarea"
name="remark"
label="Opmerking"
outer-class="form-grid-column-12"></FormKit>
<FormKit v-if="lisyConfig.fieldOptions.fieldOptionsSchool !== 'hidden'"
:validation="[
['lisy_required', lisyConfig.fieldOptions.fieldOptionsSchool]
]"
type="text"
name="school"
label="School"
outer-class="form-grid-column-6"></FormKit>
<FormKit v-if="lisyConfig.fieldOptions.fieldOptionsClass !== 'hidden'"
:validation="[
['lisy_required', lisyConfig.fieldOptions.fieldOptionsClass]
]"
type="text"
name="class"
label="Klas"
outer-class="form-grid-column-6"></FormKit>
</div>
</FormKit>
<FormKit
type="button"
@click="addRequest(child)"
prefix-icon="add"
input-class="btn purple"
wrapper-class="btn__wrapper btn__wrapper--right"
>Voeg aanvraag toe</FormKit>
</FormKit>
</div>
<hr>
</FormKit>
<FormKit
type="button"
@click="addChild"
prefix-icon="add"
input-class="btn purple"
wrapper-class="btn__wrapper btn__wrapper--right"
>Voeg kind toe</FormKit>
</FormKit>
<FormKit
v-if="false"
type="checkbox"
name="voorwaardenCheck"
:options="['Ja, ik ga akkoord met de voorwaarden']"
label="Please agree to the terms and conditions."
validation="required"
/>
<h2>Vrije velden</h2>
<FormKit v-if="lisyConfig.freeFields.length > 0"
name="freeFields"
type="group"
>
<FormKit v-for="(freeField, index) in lisyConfig.freeFields"
:key="freeField.label"
:id="freeField.label"
:name="freeField.label"
:label="freeField.label"
:type="freeField.type"
>
</FormKit>
<!-- copilot Write a loop here for the free fields.-->
</FormKit>
</FormKit>
<pre style="
font-size: small; overflow-x: scroll;">
L:{{childItems.length}}
{{lisyForm}}
</pre>
</div>
<div v-else>
<p><small>Lisy Endpoint en/of Stichting ID is niet goed ingesteld.</small></p>
</div>
</template>
<style lang="scss"></style> |
Beta Was this translation helpful? Give feedback.
0 replies
-
Formkit.config import type {DefaultConfigOptions} from '@formkit/vue'
import { nl } from '@formkit/i18n'
import lisy_required from './rules/lisy_required';
const config: DefaultConfigOptions = {
// Add custom ruleszzz.
rules: {
lisy_required
},
// Define additional locales
locales: { nl },
// Define the active locale
locale: 'nl',
messages: {
nl: {
validation: {
lisy_required({ name }) {
return `${name} is verplicht.`
},
required({ name }) {
return `${name} is verplicht.`
}
}
}
},
plugins: [
addAsteriskPlugin,
scrollToErrors
]
}
/**
* A little plugin that automatically scrolls to the first error.
**/
function scrollToErrors(node: any) {
if (node.props.type === 'form') {
console.log("is node a form", node.props.isForm);
console.log("is node a form", node.props);
function scrollTo(node: any) {
const el = document.getElementById(node.props.id)
if (el) {
el.scrollIntoView()
}
}
function scrollToErrors () {
node.walk((child: any) => {
// Check if this child has errors
if (child.ledger.value('blocking') || child.ledger.value('errors')) {
// We found an input with validation errors
scrollTo(child)
// Stop searching
return false
}
}, true)
}
const onSubmitInvalid = node.props.onSubmitInvalid
node.props.onSubmitInvalid = () => {
onSubmitInvalid(node)
scrollToErrors()
}
node.on('unsettled:errors', scrollToErrors)
}
return false
}
const isCheckboxAndRadioMultiple = (node: any) => (node.props.type === 'checkbox' || node.props.type === 'radio') && node.props.options
function addAsteriskPlugin (node: any) {
node.on('created', () => {
const isRequired = node.props.parsedRules.some((rule:any) => rule.name === 'required' || rule.name === 'lisy_required' && rule.args[0] === 'required');
if (!isRequired) return
const isMultiOption = isCheckboxAndRadioMultiple(node)
// if we're going to modify the schema then we need
// to update the schemaMemoKey so we don't get an
// invalid cached schema.
node.props.definition.schemaMemoKey = `required_${isMultiOption ? 'multi_' : ""}${node.props.definition.schemaMemoKey}`
const schemaFn = node.props.definition.schema;
node.props.definition.schema = (sectionsSchema = {}) => {
if (isRequired) {
if(isMultiOption) {
// @ts-ignore
sectionsSchema.legend = {
children: ['$label', '*']
}
} else {
// @ts-ignore
sectionsSchema.label = {
children: ['$label', '*']
}
}
}
return schemaFn(sectionsSchema);
}
})
}
export default config |
Beta Was this translation helpful? Give feedback.
0 replies
-
If youd like to provide a minimal reproduction i could look at it, but I dont think i can be much help sorting through those hundreds of lines of code. That said you could just check if the variable is a function before calling it: const onSubmitInvalid = node.props.onSubmitInvalid;
node.props.onSubmitInvalid = () => {
if (typeof onSubmitInvalid === 'function') {
onSubmitInvalid(node);
}
scrollToErrors();
}; |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
I tried to use https://formkit.com/playground?fkv=latest&fileTab=Playground.vue&files=jc%5B%28%27name%21%27Playground.vue%60%3CscripDsetup%3E5GESM+importzarZsupported+from+URLsHhttps%3A%2F%2Fcdn...%7D5Gazwell+azsecondary+playground+filesH.%2FOtherFile.vue%7D.5consDlogX+console.log5%24script%3E55%3C%2B3%3C%25t0type%3D7form70%40submit-invalid%3D7log753N0142014ed703validation%3D7requir2014201420142014201420142014201420142014201420142014ed70%2F%3E053%24%25t%3E5%24%2B5%3CstylZscoped%3E5%2F*5vanilla+CSS+caQgo+here.5Keep+stylezscoped+to+avoid+multiplZfiles5overwriting+each+other+iQthZrender+output.5*%2F5%24style%3E5%27%3B%2C%28%27name%21%27formkit.config.js%60%2F**5+*+A+littlZplugiQthaDautomatically+_zto+thZfirsDerror.5+**%2F5%236%5E9%2853ifHJtypeX%3D%3D+%22form%229%280%23_To%5E9%2803consDelX+document.getElementById%7BJid%7D03ifHel9%28033el._IntoView%7B%7D03%290%2900%236H9%2803node.walk%7BchildX%3E+%28033GCheck+if+thizchild+haz%26033ifHYblocking%229%7C%7C+Y%26%22%7D9%280333GWZfound+aQinpuDwith+validatioQ%260333_To%7Bchild%7D0333GStop+searching033%3F033%2903%29%2C+true%7D0%2900consD8X+J80J8XH9%3D%3E+%28038%5E%7D036%7B%7D0%290node.on%7B%22unsettled%3A%26%22%2C+6%7D53%295%3F5%29555exporDdefaulD%2853plugins%3A+%5B6%5D5%295%27%7Eremovable%21true%7Esilent%21false%3B%5D053313label%3D7%25DInput703help%3D7ediDmZt2ed70%2FN3++4o+geDstart5%5Cn6_ToErrors7%5C%278onSubmitInvalid9%7D+Dt+G%2F%2F+H+%7BJnode.props.N%3E0%3C%25t03type%3D7text7Qn+X+%3DYchild.ledger.value%7B%22Ze+_scrollzs+%23functioQ%24%3C%2F%25FormKi%26errors%2Btemplate%3E5%3B%7Eadded%21true%29%3F3returQfalse%5E%7Bnode%60%27%7Eeditor%21%27%01%60%5E%3F%3B%2B%26%25%24%23z_ZYXQNJHGD9876543210_&imports=jc%28%27name%21%27ImportMap%27%7Eeditor%21%27%28*+1vue%5C%211https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Fvue%403%2Fdist%2Fvue.esm-browser.min.js0*%29*%27%29*%5Cn0%5C%271+0%0110*_&css-framework=genesis
But I get
TypeError: onSubmitInvalid is not a function and I do not understand.
I have a custom validation rule running, but removing that doesnt fix it.
I have a rather complex form with groups in groups though.
But shouldnt the node.props.onSubmitInvald always be a function because the example checks if it is of type 'form'?
Any idea as why this is not a function?
So the error points to this part:
Beta Was this translation helpful? Give feedback.
All reactions