Componente de pestaña personalizado
NexoPOS ofrece una forma rápida de crear un formulario con pestañas y campos personalizados, pero también es posible renderizar un componente Vue personalizado en lugar del contenido de las pestañas. En este escenario, controlas cómo se muestran los campos, lo que te brinda una mayor flexibilidad para crear un diseño único para tu componente CRUD.
Para que tu componente funcione sin problemas con NexoPOS, necesitas proporcionar los detalles de validación para tu componente de pestaña personalizado. Recuerda que el componente personalizado debe comportarse como una pestaña con campos. Esto garantizará que, cuando se envíe el formulario, se compruebe la seguridad de los datos.
Registrar componente de vista personalizado
El primer paso es registrar tu componente en los objetos globales de componentes: nsExtraComponents. Consulta la documentación sobre inyectar un componente de Vue.
Requisitos
Para que los componentes personalizados funcionen, hay algunas cosas que deben proporcionarse y tenerse en cuenta:
- El componente ns-crud-form.vue proporciona props personalizados a tu componente llamado «tab». Esta es la definición del formulario tal como se hizo en la clase CRUD PHP (consulta el método getForm).
- Tus datos deben incluir un arreglo de errores con un valor vacío, tal como se define en el método data() de tu componente de vista.
- Cuando el componente se monta, debes definir si es válido o no. Luego emitirás un evento "invalid" con el arreglo de errores.
- usando las props de «tab» puedes acceder al error almacenado en tu componente tab y mostrarlo (estos son los errores emitidos, pero como no se recomienda mutar las props, procedemos con la emisión del evento).
Ejemplo concreto
Así es como debe verse la pestaña de tu componente personalizado.
export default {
props: [ 'tab' ],
data() {
return {
errors: []
}
},
template: `
<div v-if="tab.instance.errors.length > 0" class="mb-2">
<ns-notice v-for="error of tab.instance.errors">
<template v-slot:title>{{ __m( 'Warning', 'YourModule' ) }}</template>
<template v-slot:description>{{ error.message }}</template>
</ns-notice>
</div>
`,
mounted() {
this.checkValidity();
},
methods: {
checkValidity() {
this.errors.push({
identifier: 'invalid_email', // identifier of the error, this must be unique
message: 'You must provide a valid email',
name: 'email', // name of the field
});
this.$emit( 'invalid', this.errors );
}
}
}
Emitir datos de formulario al componente principal
Ahora que el usuario ha interactuado con tu componente de pestaña personalizado, es posible que quieras enviar sus datos al componente ns-crud-form para que pueda enviarlos al servidor. El mejor enfoque aquí es emitir un evento «changed» con los campos (un array de campos con una definición específica, lo compartiremos más adelante). Lo haremos así porque el componente ns-crud-form no puede requerir los datos del formulario bajo demanda. Tu componente es entonces responsable de proporcionarlos.
export default {
props: [ 'tab' ],
data() {
return {
errors: [],
fields: [],
validation: new FormValidation
}
},
template: `
<div>
<div v-if="tab.instance.errors.length > 0" class="mb-2">
<ns-notice v-for="error of tab.instance.errors">
<template v-slot:title>{{ __m( 'Warning', 'YourModule' ) }}</template>
<template v-slot:description>{{ error.message }}</template>
</ns-notice>
</div>
<ns-field field="field" v-for="field of fields"/>
</div>
`,
mounted() {
// ...
},
watch: {
// we carefully check fields change and emit event to the parent component
fields: {
deep: true,
handle() {
if ( this.validation.validateFields( this.fields ) ) {
this.$emit( 'changed', this.fields );
}
}
}
},
methods: {
// we're loading fields from our endpoint
loadCustomFields() {
nsHttpClient.get( '/api/mymodule/fields' ).subscribe({
next: fields => {
this.fields = this.validation.createFields( fields );
})
},
}
}
Vamos a explicar qué está pasando aquí:
- Cargaremos los campos desde nuestro endpoint (pero se puede codificar de forma fija si lo deseas);
- Crearemos los campos usando la clase FormValidation, que está disponible globalmente en el panel.
- Vigilaremos los cambios en nuestros campos y emitiremos eventos de cambios al componente principal para que pueda combinar tus datos de campo con todo el formulario. Pero hazlo solo si es válido.
Estructura del campo
Si no quieres usar el componente ns-field, sino un elemento personalizado que creaste, aún necesitas seguir la estructura del campo si quieres que los datos de tu formulario se envíen correctamente. Los datos del formulario de tu componente deben proporcionarse como un objeto de campos. Esta es la estructura de un campo:
{
type: 'text',
name: 'email',
description: 'field description',
validation: 'required',
value: 'field value.'
}
Los atributos más importantes aquí son «name» y «value».
Restaurar el estado al cambiar de pestaña
Un formulario CRUD normalmente consta de varias pestañas. En el estado actual, si cambias de una pestaña a otra, tu componente personalizado perderá su estado. Esto se debe principalmente a que el componente se monta y se desmonta al cambiar de pestaña, y luego pierde su estado.
Cuando emites un "changed" con los campos de tu componente, estos se ponen a disposición en una propiedad (pestaña) inyectada en tu componente.
export default {
props: [ 'tab' ],
data() {
return {
errors: [],
fields: [],
state: {},
validation: new FormValidation
}
},
template: `
<div>
<div v-if="tab.instance.errors.length > 0" class="mb-2">
<ns-notice v-for="error of tab.instance.errors">
<template v-slot:title>{{ __m( 'Warning', 'YourModule' ) }}</template>
<template v-slot:description>{{ error.message }}</template>
</ns-notice>
</div>
<ns-field field="field" v-for="field of fields"/>
</div>
`,
mounted() {
// if the tab has received our state
if ( this.tab.fields.length > 0 ) {
// in case you emit a "changed" event with only one field
// you can get the value of that field
this.state = this.tab.fields[0].value;
}
},
watch: {
// we carefully check fields change and emit event to the parent component
fields: {
deep: true,
handle() {
if ( this.validation.validateFields( this.fields ) ) {
this.$emit( 'changed', this.fields );
}
}
}
},
methods: {
// we're loading fields from our endpoint
loadCustomFields() {
nsHttpClient.get( '/api/mymodule/fields' ).subscribe({
next: fields => {
this.fields = this.validation.createFields( fields );
})
},
}
}