Hi I got the error while using the package of jsonforms with vue2 seed. Also I've used vue2 with laravel 5.8.
Encountering a TypeError: Cannot read properties of undefined (reading 'code') error in Vue 2 application using JSONForms when processing dynamic form data.
Below are my package.json file:
{ "private": true, "scripts": { "dev": "npm run development", "development": "cross-env NODE_ENV=development NODE_OPTIONS='--openssl-legacy-provider' node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", "watch": "npm run development -- --watch", "watch-poll": "npm run watch -- --watch-poll", "hot": "cross-env NODE_ENV=development NODE_OPTIONS='--openssl-legacy-provider' node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", "prod": "npm run production", "production": "cross-env NODE_ENV=production NODE_OPTIONS='--openssl-legacy-provider' node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", "storybook": "start-storybook -p 9000" }, "devDependencies": { "axios": "^0.19", "bootstrap": "^4.1.0", "cross-env": "^5.1", "jquery": "^3.2", "laravel-mix": "^4.0.7", "lodash": "^4.17.13", "popper.js": "^1.12", "resolve-url-loader": "^2.3.1", "sass": "^1.15.2", "sass-loader": "^7.1.0", "vue": "^2.6.14", "vue-template-compiler": "^2.6.14" }, "dependencies": { "@jsonforms/core": "^2.4.0", "@jsonforms/vue2": "^2.4.0", "@jsonforms/vue2-vanilla": "^2.4.0", "@vue/composition-api": "^1.7.2", "ajv": "^6.12.6", "ajv-formats": "^1.5.1", "core-js": "^3.6.5", "regenerator-runtime": "^0.14.1", "tslib": "^2.8.1", "uuid": "^9.0.0" } }
Below my component code:
`
<button
v-for="tab in tabs"
:key="tab.id"
:class="['tab-button', { active: activeTab === tab.id }]"
@click="switchTab(tab.id)"
>
{{ tab.label }} 1
<!-- Tab Content -->
<div class="tab-content">
<!-- All Fields Tab -->
<div v-if="activeTab === 'all'" class="tab">
<h3>All Fields Tab</h3>
<div v-if="isSchemaReady && uiSchema" class="form-container">
<json-forms
v-bind:uischema="uiSchema"
v-bind:schema="effectiveSchema"
v-bind:ajv="schemaValidator"
v-bind:renderers="renderers"
v-bind:data="data"
@change="onChange"
/>
</div>
<div v-else class="no-form-message">
<p>No form available. Check console for errors.</p>
</div>
</div>
<!-- Required Fields Tab -->
<div v-if="activeTab === 'required'" class="tab">
<h3>Required Fields Tab</h3>
<div v-if="!requiredUiSchema" class="fallback-message">
<p>Required fields view is not available. Showing all fields instead.</p>
</div>
<div v-if="isSchemaReady && (requiredUiSchema || uiSchema)" class="form-container">
<json-forms
v-bind:uischema="requiredUiSchema || uiSchema"
v-bind:schema="effectiveSchema"
v-bind:ajv="schemaValidator"
v-bind:renderers="renderers"
v-bind:data="data"
@change="onChange"
/>
</div>
<div v-else class="no-form-message">
<p>No form available. Check console for errors.</p>
</div>
</div>
</div>
</div>
</div>
<script>
import { generateDefaultUISchema } from '@jsonforms/core';
import { JsonForms } from '@jsonforms/vue2';
import { cloneDeep } from "lodash";
import { vanillaRenderers } from '@jsonforms/vue2-vanilla';
import Ajv from 'ajv';
import addFormats from "ajv-formats";
import { entry as arrayListEntry } from './Custom/ArrayList.vue';
export default {
name: 'JsonFormsComponent',
components: {
JsonForms,
},
data() {
return {
data: {},
ID_SUFFIX: "/Augmented",
schemaValidator: null,
renderers: [],
uiSchema: null,
requiredUiSchema: null,
activeTab: 'all',
tabs: [
{ id: 'all', label: 'All Fields' },
{ id: 'required', label: 'Required Fields' }
],
loadedSchema: null
};
},
methods: {
cleanUpSchemaForPresentation(schema) {
if (!schema || typeof schema !== 'object') {
return schema;
}
// For simplified schemas, we don't need aggressive cleaning
// Just ensure we have a valid schema structure
const clonedSchema = cloneDeep(schema);
// Only clean problematic properties if they exist
if (clonedSchema.allOf) {
delete clonedSchema.allOf;
}
if (clonedSchema.anyOf) {
delete clonedSchema.anyOf;
}
if (clonedSchema.oneOf) {
delete clonedSchema.oneOf;
}
// Ensure we have a valid ID
if (!clonedSchema.$id) {
clonedSchema.$id = this.generateUuid();
}
return clonedSchema;
},
generateUISchema(schema) {
return generateDefaultUISchema(this.cleanUpSchemaForPresentation(schema));
},
generateUuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0;
const v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
},
generateRequiredUISchema(schema) {
try {
const clonedSchema = cloneDeep(schema);
const requiredSchema = this.filterRequiredFields(clonedSchema);
const uiSchema = generateDefaultUISchema(requiredSchema);
return uiSchema;
} catch (error) {
console.error('Error generating required UI schema:', error);
// Fallback to main UI schema if there's an error
return this.uiSchema;
}
},
filterRequiredFields(schema) {
if (!schema || typeof schema !== 'object') {
return schema;
}
const filteredSchema = { ...schema };
if (schema.properties) {
const requiredProps = schema.required || [];
const filteredProperties = {};
Object.keys(schema.properties).forEach(propName => {
const prop = schema.properties[propName];
if (requiredProps.includes(propName) || this.hasRequiredFields(prop)) {
filteredProperties[propName] = this.filterRequiredFields(prop);
}
});
filteredSchema.properties = filteredProperties;
filteredSchema.required = requiredProps.filter(propName =>
filteredProperties.hasOwnProperty(propName)
);
}
return filteredSchema;
},
hasRequiredFields(schema) {
if (!schema || typeof schema !== 'object') {
return false;
}
if (schema.required && schema.required.length > 0) {
return true;
}
if (schema.properties) {
return Object.values(schema.properties).some(prop => this.hasRequiredFields(prop));
}
return false;
},
switchTab(tabId) {
this.activeTab = tabId;
},
initializeSchemaValidator() {
this.schemaValidator = new Ajv({
allErrors: true,
verbose: true,
strict: false,
validateSchema: false,
});
addFormats(this.schemaValidator);
},
initializeRenderers() {
// Try putting custom renderer at the end for higher priority
this.renderers = [...vanillaRenderers, arrayListEntry];
this.renderers = Object.freeze(this.renderers);
},
onChange(e) {
try {
// Ensure the event object is valid before accessing properties
if (e && typeof e === 'object' && e.data !== undefined) {
this.data = e.data;
} else {
console.warn('Invalid change event received:', e);
this.data = {};
}
} catch (error) {
console.error('Error in onChange handler:', error);
this.data = {};
}
},
loadHerbSchema() {
try {
// Try to load from the correct path first
let response = fetch('/storage/herb.json');
if (!response.ok) {
// Fallback to test schema if herb.json fails
throw new Error('HTTP error! status: '+response.status);
}
const schema = response.json();
return schema;
} catch (error) {
console.error('Error loading schema:', error);
}
},
getValidationErrors() {
if (!this.schemaValidator || !this.loadedSchema || !this.data) {
return [];
}
try {
this.schemaValidator.validate(this.loadedSchema, this.data);
return this.schemaValidator.errors || [];
} catch (error) {
console.error('Error getting validation errors:', error);
return [];
}
},
getRequiredFieldErrors() {
const errors = this.getValidationErrors();
return errors.filter(error => {
// Filter for errors that indicate missing required fields
return error.keyword === 'required' ||
(error.keyword === 'minLength' && error.params && error.params.limit === 0) ||
(error.keyword === 'minItems' && error.params && error.params.limit > 0);
});
}
},
mounted() {
this.initializeSchemaValidator();
this.initializeRenderers();
// Load schema from herb.json
this.loadedSchema = this.loadHerbSchema();
if (this.loadedSchema) {
try {
// Clean and prepare the schema
const cleanedSchema = this.cleanUpSchemaForPresentation(this.loadedSchema);
// Ensure the schema has properties
if (!cleanedSchema.properties || Object.keys(cleanedSchema.properties).length === 0) {
cleanedSchema.properties = {
fallback_message: {
type: 'string',
title: 'Schema Information',
description: 'The schema was loaded but contains no displayable properties',
readOnly: true
}
};
cleanedSchema.required = [];
}
// Generate UI schema
try {
this.uiSchema = this.generateUISchema(cleanedSchema);
} catch (error) {
console.error('Error generating UI schema:', error);
// Create a simple fallback UI schema
this.uiSchema = {
type: 'VerticalLayout',
elements: Object.keys(cleanedSchema.properties || {}).map(propName => ({
type: 'Control',
scope: `#/properties/${propName}`
}))
};
}
// Generate required UI schema
try {
this.requiredUiSchema = this.generateRequiredUISchema(cleanedSchema);
} catch (error) {
console.error('Error generating required UI schema:', error);
// Use main UI schema as fallback for required fields
this.requiredUiSchema = this.uiSchema;
}
} catch (error) {
console.error('Error generating schemas in mounted:', error);
}
} else {
console.error('Failed to load schema');
}
},
computed: {
effectiveSchema() {
// Use loaded schema from herb.json
const schema = this.loadedSchema;
return schema;
},
isSchemaReady() {
return this.loadedSchema
&& Object.keys(this.loadedSchema
).length > 0 && this.uiSchema;
},
requiredFieldsCount() {
const schema = this.loadedSchema;
if (!schema || !schema.properties) {
return 0;
}
let count = 0;
const errors = this.getValidationErrors();
count = errors.length;
return count;
}
},
};
</script>`
Requirements
- I don't want to upgrade the packages version of vue, vue-template-compiler & laravel-mix.
Please help me figure out this error.