Componente di scheda personalizzata
NexoPOS offre un modo rapido per creare un modulo a schede con campi personalizzati, ma è anche possibile eseguire il rendering di un componente Vue personalizzato al posto del contenuto delle schede. In questo scenario, controlli come vengono visualizzati i campi, offrendoti una maggiore flessibilità per creare un layout unico per il tuo componente CRUD.
Per far funzionare il tuo componente in modo fluido con NexoPOS, devi fornire i dettagli di validazione per il tuo componente di scheda personalizzato. Ricorda che il componente personalizzato deve comportarsi come una scheda con campi. Questo garantirà che, quando il modulo viene inviato, venga verificata la sicurezza dei dati.
Registrare il componente di visualizzazione personalizzato
Primo passo: registra il tuo componente negli oggetti globali dei componenti: nsExtraComponents. Fai riferimento alla documentazione su l’iniezione di un componente Vue.
Requisiti
Affinché i componenti personalizzati funzionino, ci sono alcune cose che devono essere fornite e prese in considerazione:
- il componente ns-crud-form.vue fornisce proprietà personalizzate al componente denominato "tab". Questa è la definizione del modulo così come viene creata nella classe CRUD PHP (controlla il metodo getForm).
- I tuoi dati devono includere un array di errori con un valore vuoto, come definito nel metodo data() del componente di visualizzazione.
- Quando il componente viene montato, dovresti definire se è valido o meno. Successivamente, emetterai un evento "invalid" con l’array degli errori.
- Utilizzando le prop "tab" puoi accedere all’errore memorizzato nel tuo componente tab e visualizzarlo (Questi sono gli errori emessi, ma poiché non è consigliato mutare le prop, procediamo con l’emissione dell’evento).
Esempio concreto
Ecco come dovrebbe apparire la scheda del componente personalizzato.
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 );
}
}
}
Invia i dati del modulo al componente padre
Ora che l’utente ha interagito con il tuo componente di scheda personalizzato, potresti voler inviare i suoi dati al componente ns-crud-form, così che possa inviarli al server. L’approccio migliore qui è emettere un evento “changed” con i campi (un array di campi con una definizione specifica, che condivideremo più avanti). Lo faremo così perché il componente ns-crud-form non è in grado di richiedere i dati del form su richiesta. Il tuo componente è quindi responsabile di fornirli.
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 );
})
},
}
}
Spieghiamo cosa sta succedendo qui:
- Caricheremo i campi dal nostro endpoint (ma può anche essere codificato in modo statico, come preferisci);
- Costruiremo i campi utilizzando la classe FormValidation, disponibile globalmente nella dashboard.
- Moniteremo le modifiche ai nostri campi ed emetteremo eventi di modifica al componente padre, così potrà unire i tuoi dati di campo con l’intero modulo. Ma fallo solo se è valido.
Struttura del campo
Se non vuoi usare il componente ns-field ma invece un elemento personalizzato che hai creato, devi comunque seguire la struttura del campo se vuoi che i dati del tuo modulo vengano inviati correttamente. I dati del modulo del tuo componente devono essere forniti come un oggetto di campi. Ecco la struttura di un campo:
{
type: 'text',
name: 'email',
description: 'field description',
validation: 'required',
value: 'field value.'
}
Gli attributi più importanti qui sono "name" e "value".
Ripristino dello stato al cambio di scheda
Un modulo CRUD di solito è composto da più schede. Nello stato attuale, se passi da una scheda a un’altra, il tuo componente personalizzato perderà il suo stato. Questo avviene principalmente perché il componente viene montato e smontato al cambio di scheda e quindi perde il suo stato.
Quando emetti un "changed" con i campi del tuo componente, questi vengono resi disponibili su una proprietà (scheda) iniettata nel tuo 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 );
})
},
}
}