Agregar botón Crear en la selección de búsqueda
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 agregar compatibilidad para crear entradas mediante un cuadro emergente y, tras una presentación exitosa, agregarlas a las opciones.
Esta funcionalidad funciona de forma inmediata con los componentes internos de CRUD y de configuración, sin necesidad de realizar más modificaciones de código. Esto significa que, si tienes, por ejemplo, un componente de 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 entender mejor cómo se hacen las cosas, quizá quieras seguir leyendo.
Principio de funcionamiento
Una cosa importante a tener en cuenta es que tus implementaciones deben cargar los campos de forma asíncrona. Esto garantiza que los campos se puedan volver a cargar 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 pasan como propiedades (es un componente de Vue 3).
Configuración de campo
Todos los componentes CRUD proporcionan su configuración como un arreglo usando el método getFormConfig. Cuando creamos nuestro campo, debemos proporcionar dos entradas adicionales: "component" y "props". El componente puede ser cualquier componente que quieras.
Si quieres usar tu componente, debes 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 creado sobre NexoPOS para renderizar un formulario CRUD.
Así es como definirás entonces 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 a support for a create button
'component' => 'nsCrudForm',
'props' => ProductCategoryCrud::getFormConfig()
]
];
Tenga en cuenta que usamos la clase ProductCategoryCrud para recuperar su configuración. A partir de 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 asíncrona. 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 un callback 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 deben usarse como opciones. De forma predeterminada, 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 un pop-up, NexoPOS proporciona un prop adicional, “popup”. Esto 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 a nuestro componente. Dos de esos parámetros son «resolve» y «reject». Nos aseguramos de ambos para devolver la respuesta del servidor.