Adicionar botão Criar na seleção de pesquisa
Um “search-select” é um componente que ajuda a filtrar uma lista de opções e facilita a seleção. Por padrão, o componente não permite criar novas entradas que depois sejam adicionadas à lista de opções. Com algumas configurações, você pode adicionar suporte para criar entradas via um pop-up e, após o envio bem-sucedido, adicioná-las às opções.
Este recurso funciona imediatamente com os componentes internos de CRUD e de configurações, sem necessidade de mais nenhuma modificação no código. Isso significa que, se você tiver, por exemplo, um componente de CRUD que permite selecionar produtos, basta definir o suporte no campo search-select — é só isso. No entanto, se você quiser ter um controle mais profundo ou entender melhor como as coisas são feitas, talvez você queira continuar lendo.
Princípio de Funcionamento
Um ponto importante a observar é que suas implementações devem carregar os campos de forma assíncrona. Isso garante que os campos possam ser recarregados a qualquer momento sem recarregar a página (é assim que os campos do componente CRUD são carregados no NexoPOS).
Agora, ao definir as estruturas do seu campo, você vai defini-las no lado do backend. A partir daí, você vai definir qual componente deve ser carregado quando o botão “+” for clicado e as configurações que serão passadas como propriedades (é um componente Vue 3).
Configuração do Campo
Todos os componentes CRUD fornecem sua configuração como um array usando o método getFormConfig. Quando criamos nosso campo, devemos fornecer duas entradas extras: “component” e “props”. O componente pode ser qualquer componente que você quiser.
Se você quiser usar seu componente, deverá registrá-lo primeiro. Além disso, esse componente resolve a resposta de um servidor (o que é útil para selecionar a entrada que foi criada automaticamente). No entanto, no nosso exemplo, usaremos “nsCrudForm”, um componente criado no NexoPOS para renderizar um formulário CRUD.
Veja como você definirá, então, a configuração do seu campo de pesquisa-seleção.
<?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()
]
];
Você notará que usamos a classe ProductCategoryCrud para recuperar sua configuração. A partir do NexoPOS 5, esse método é fornecido a todos os componentes CRUD disponíveis. A variável $fields deve então ser retornada como resposta em uma chamada de API.
Configurando o Componente Vue
Suponha que você não esteja usando nossos componentes nsSettings ou nsCrudForm. Nesse caso, você terá que fornecer uma ponte de comunicação entre o seu componente Vue que renderiza o formulário, o campo search-select e o componente usado para criar uma entrada. Como você pode imaginar, nesse cenário temos 3 componentes Vue. Vamos começar com o componente que renderiza o formulário.
<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>
Conforme mencionado acima, estamos carregando os campos de forma assíncrona. Agora, para garantir que as opções sejam preenchidas, toda vez que o componente que cria a entrada resolver a resposta do servidor, precisamos adicionar um callback ao elemento <ns-field> assim:
<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 obter a configuração real do componente Crud que está sendo carregado. Nesse objeto, temos “optionsAttributes”, que definem qual propriedade deve ser considerada como rótulo ou qual deve ser usada como valor. Observe que essas duas propriedades devem ser usadas como opções. Por padrão, o NexoPOS assume que você está usando “id” como valor e “name” como rótulo. Você pode alterar esse comportamento editando “optionsAttributes” no componente crud.
Se você não estiver usando o nsCrudForm para criar uma entrada, mostraremos como criar seu componente personalizado que será exibido em um pop-up. Quando um componente é aberto como um pop-up, o NexoPOS fornece uma prop adicional, “popup”. Isso pode então ser usado para detectar se ele está sendo exibido em um pop-up ou não. Veja como vamos definir nosso 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 a propriedade “popup”, temos acesso a vários parâmetros fornecidos ao nosso componente. Dois desses parâmetros são “resolve” e “reject”. Garantimos ambos para retornar a resposta do servidor.