Agregar botón Crear en el campo de búsqueda-selección
Un “search-select” es un componente que ayuda a filtrar una lista de opciones y facilita la selección. De forma predeterminada, el componente no permite crear nuevas entradas que luego se agreguen a la lista de opciones. Con algunas configuraciones, puedes añadir soporte para crear entradas mediante un cuadro emergente y, tras un envío exitoso, hacer que se agreguen a las opciones.
Esta función funciona de forma inmediata con los componentes internos de CRUD y de configuración, sin necesidad de ninguna modificación adicional del código. Esto significa que, por ejemplo, si tienes un componente CRUD que permite seleccionar productos, solo tienes que definir el soporte en el campo search-select; eso es todo. Sin embargo, si quieres tener un control más profundo o comprender mejor cómo se hacen las cosas, podrías seguir leyendo esto.
Principio de funcionamiento
Un punto importante a tener en cuenta es que tus implementaciones deben cargar los campos de forma asíncrona. Esto garantiza que los campos puedan recargarse en cualquier momento sin recargar la página (así es como se cargan los campos del componente CRUD en NexoPOS).
Ahora, al definir tus estructuras de campo, las definirás del lado del backend. A partir de ahí, establecerás qué componente debe cargarse cuando se haga clic en el botón “+” y las configuraciones que se pasarán como propiedades (es un componente de Vue 3).
Configuración del campo
Todos los componentes CRUD proporcionan su configuración como un arreglo usando el método getFormConfig. Cuando creemos nuestro campo, debemos proporcionar dos entradas adicionales: "component" y "props". El componente puede ser cualquier componente que quieras.
Si desea usar su componente, debe registrarlo primero. Además, ese componente resuelve la respuesta de un servidor (lo cual es útil para seleccionar la entrada que se creó automáticamente). Sin embargo, en nuestro ejemplo, usaremos "nsCrudForm", un componente construido sobre NexoPOS para renderizar un formulario CRUD.
Así es como definirás la configuración de tu campo de búsqueda y selección.
<?php
use App\Crud\ProductCategoryCrud;
$fields = [
[
'type' => 'search-select',
'name' => 'category_id',
'label' => 'Assigned Category',
'description' => 'any description you want goes here',
//Here is how to enable support for a create button
'component' => 'nsCrudForm',
'props' => ProductCategoryCrud::getFormConfig()
]
];
Tenga en cuenta que usamos la clase ProductCategoryCrud para recuperar su configuración. Desde NexoPOS 5, ese método se proporciona a todos los componentes CRUD disponibles. La variable $fields debe devolverse entonces como respuesta en una llamada a la API.
Configurar el componente de Vue
Supongamos que no estás usando nuestros componentes nsSettings o nsCrudForm. En ese caso, tendrás que proporcionar un puente de comunicación entre tu componente de Vue que renderiza el formulario, el campo search-select y el componente que se usa para crear una entrada. Como puedes imaginar, en este escenario tenemos 3 componentes de Vue. Empezaremos con el componente que renderiza el formulario.
<template>
<div>
<form>
<ns-field v-for="field in fields"/>
</form>
</div>
</template>
<script lang="ts">
declare const FormValidation;
export default {
data() {
return {
fields: [],
formValidation: new FormValidation,
};
},
methods; {
loadFields() {
nsHttpClient('/api/path/to/the/fields')
.subscribe({
next: fields => {
this.fields = this.formValidataion.createForm(fields);
},
error: error => {
// handle error here
});
}
}
created() {
this.loadFields();
},
};
</script>
Como se mencionó anteriormente, estamos cargando los campos de forma asincrónica. Ahora, para asegurarnos de que se rellenen las opciones, cada vez que el componente que crea la entrada resuelva la respuesta del servidor, necesitamos agregar una devolución de llamada al elemento <ns-field> de esta manera:
<template>
<div>
<form>
<ns-field @saved="handleSaveEvent( $event, field )" v-for="field in fields"/>
</form>
</div>
</template>
<script lang="ts">
declare const FormValidation;
export default {
data() {
return {
fields: [],
formValidation: new FormValidation,
};
},
methods: {
async handleSaveEvent( serverResponse, field ) {
try {
field.options.push({
label: serverResponse.data.entry[ field.props.optionAttributes.label ],
value: serverResponse.data.entry[ field.props.optionAttributes.value ]
});
field.value = serverResponse.data.entry[ field.props.optionAttributes.value ];
} catch ( exception ) {
// something went wrong
}
},
loadFields() {
return new Promise( ( resolve, reject ) => {
nsHttpClient('/api/path/to/the/fields')
.subscribe({
next: fields => {
resolve( fields );
this.fields = this.formValidataion.createForm(fields);
},
error: error => {
reject( error )
});
});
}
}
created() {
this.loadFields();
},
};
</script>
Estamos usando field.props para obtener la configuración real del componente Crud que se está cargando. En ese objeto, tenemos “optionsAttributes”, que definen qué propiedad debe considerarse como etiqueta o cuál debe usarse como valor. Ten en cuenta que esas dos propiedades son obligatorias para usarse como una opción. Por defecto, NexoPOS asume que estás usando “id” como valor y “name” como etiqueta. Puedes cambiar ese comportamiento editando “optionsAttributes” en el componente crud.
Si no estás usando nsCrudForm para crear una entrada, te mostraremos cómo crear tu componente personalizado que se mostrará en un pop-up. Cuando un componente se abre como pop-up, NexoPOS proporciona como prop adicional la variable "popup"; esta se puede usar para detectar si se está mostrando en un pop-up o no. Así es como definiremos nuestro componente:
<template>
<div>
<form>
<ns-field v-for="field in fields"/>
<button @click="createEntry()">Save</button>
</form>
</div>
</template>
<script lang="ts">
declare const FormValidation;
export default {
props: [ 'popup' ],
data() {
return {
fields: [],
formValidation: new FormValidation,
};
},
methods: {
createEntry() {
if ( this.formValidation.validateFields( this.fields ) ) {
const form = this.formValidation.extractFields( this.fields );
nsHttpClient.post( 'api/to/create/entry', form )
.subscribe({
next: response => {
this.popup.params.resolve( response );
},
error: error => {
this.popup.params.reject( error );
}
});
return; // stop it here
}
// form is not valid
},
loadFields() {
nsHttpClient('/api/path/to/the/fields')
.subscribe({
next: fields => {
this.fields = this.formValidataion.createForm(fields);
},
error: error => {
reject( error )
});
}
}
created() {
this.loadFields();
},
};
</script>
Usando la propiedad "popup", tenemos acceso a varios parámetros proporcionados en nuestro componente. Dos de esos parámetros son "resolve" y "reject". Nos aseguramos de ambos para devolver la respuesta del servidor.