Componente de Aba Personalizada
O NexoPOS oferece uma forma rápida de criar um formulário com abas e campos personalizados, mas também é possível renderizar um componente Vue personalizado em vez do conteúdo das abas. Nesse cenário, você controla como os campos são exibidos, dando mais flexibilidade para criar um layout exclusivo para seu componente de CRUD.
Para que seu componente funcione perfeitamente com o NexoPOS, você precisa fornecer detalhes de validação para seu componente de aba personalizado. Lembre-se de que o componente personalizado deve se comportar como uma aba com campos. Isso garantirá que, quando o formulário estiver sendo enviado, os dados sejam verificados quanto à segurança.
Registrar componente de visualização personalizado
O primeiro passo é registrar seu componente nos objetos globais de componentes: nsExtraComponents. Consulte a documentação sobre injetar um componente Vue.
Requisitos
Para que os componentes personalizados funcionem, há algumas coisas que precisam ser fornecidas e levadas em consideração:
- O componente ns-crud-form.vue fornece props personalizados para o seu componente chamado “tab”. Esta é a definição do formulário conforme feita na classe PHP CRUD (verifique o método getForm).
- Seus dados devem incluir uma matriz de erros com um valor vazio, conforme definido no método data() do componente de visualização.
- Quando o componente for montado, você deve definir se ele é válido ou não. Em seguida, você emitirá um evento "invalid" com o array de erros.
- Usando as props “tab”, você pode acessar o erro armazenado no seu componente tab e exibi-lo (estes são os erros emitidos, mas como não é recomendado mutar as props, prosseguimos com a emissão do evento).
Exemplo Concreto
Veja como deve ficar a sua aba de 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 dados do formulário para o componente pai
Agora que o usuário interagiu com o seu componente de aba personalizado, talvez você queira enviar os dados dele para o componente ns-crud-form para que ele possa enviá-los ao servidor. A melhor abordagem aqui é emitir um evento “changed” com os campos (um array de campos com uma definição específica, compartilharemos isso mais tarde). Faremos isso porque o componente ns-crud-form não consegue obter os dados do formulário sob demanda. O seu componente é então responsável por fornecê-los.
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 explicar o que está acontecendo aqui:
- Carregaremos os campos do nosso endpoint (mas pode ser codificado de forma fixa, como você quiser);
- Vamos criar os campos usando a classe FormValidation, que está disponível globalmente no painel.
- Vamos acompanhar as alterações nos nossos campos e emitir eventos de alteração para o componente pai, para que ele possa mesclar os seus dados de campo com o formulário inteiro. Mas faça isso apenas se for válido.
Estrutura do Campo
Se você não quiser usar o componente ns-field, mas sim um elemento personalizado que criou, ainda assim é necessário seguir a estrutura do campo para que os dados do seu formulário sejam enviados corretamente. Os dados do formulário do seu componente devem ser fornecidos como um objeto de campos. Aqui está a estrutura de um campo:
{
type: 'text',
name: 'email',
description: 'field description',
validation: 'required',
value: 'field value.'
}
Os atributos mais importantes aqui são “name” e “value”.
Restaurar o estado ao mudar de aba
Um formulário CRUD geralmente consiste em várias abas. No estado atual, se você alternar de uma aba para outra, seu componente personalizado perderá o estado. Isso acontece principalmente porque o componente é montado e desmontado ao mudar de aba e, em seguida, perde o estado.
Quando você emite um "changed" com os campos do seu componente, eles ficam disponíveis em uma propriedade (aba) injetada no seu 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 );
})
},
}
}