Home
NexoPOS

Aggiungi il pulsante Crea nel campo di selezione della ricerca

Un „search-select” è un componente che aiuta a filtrare un elenco di opzioni e a facilitare la selezione. Per impostazione predefinita, il componente non consente di creare nuove voci, che vengono poi aggiunte all’elenco delle opzioni. Con alcune configurazioni, puoi aggiungere il supporto per la creazione di voci tramite un popup e, dopo l’invio riuscito, far sì che venga aggiunta alle opzioni.

Questa funzionalità funziona out of the box con componenti interni di CRUD e impostazioni, senza alcuna modifica aggiuntiva del codice. Ciò significa che, ad esempio, se hai un componente CRUD che consente di selezionare prodotti, devi semplicemente definire il supporto sul campo search-select: è tutto. Tuttavia, se vuoi avere un controllo più approfondito o una migliore comprensione di come vengono gestite le cose, potresti continuare a leggere questo.

Principio di funzionamento

Una cosa importante da notare è che le tue implementazioni devono caricare i campi in modo asincrono. Questo garantisce che i campi possano essere ricaricati in qualsiasi momento senza ricaricare la pagina (è così che vengono caricati i campi del componente CRUD su NexoPOS).

Ora, quando definisci le strutture del tuo campo, le definirai lato backend. Da lì, imposterai quale componente deve essere caricato quando viene cliccato il pulsante “+” e le configurazioni che vengono passate come proprietà (si tratta di un componente Vue 3).

Configurazione campo

Tutti i componenti CRUD forniscono la loro configurazione come un array utilizzando il metodo getFormConfig. Quando creiamo il nostro campo, dobbiamo fornire due voci aggiuntive: "component" e "props". Il componente può essere qualsiasi componente che desideri.

Se vuoi utilizzare il tuo componente, devi prima registrarlo. Inoltre, quel componente risolve la risposta proveniente da un server (cosa utile per selezionare la voce creata automaticamente). Tuttavia, nel nostro esempio useremo "nsCrudForm", un componente costruito su NexoPOS per visualizzare un form CRUD.

Ecco come definirai quindi la configurazione del campo di ricerca-selezione.

<?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()
    ]
];

Noterai che utilizziamo la classe ProductCategoryCrud per recuperare la sua configurazione. Da NexoPOS 5, questo metodo è fornito a tutti i componenti CRUD disponibili. La variabile $fields deve quindi essere restituita come risposta in una chiamata API.

Configurazione del componente Vue

Supponiamo che tu non stia utilizzando i nostri componenti nsSettings o nsCrudForm. In tal caso, dovrai fornire un ponte di comunicazione tra il tuo componente Vue che visualizza il modulo, il campo di ricerca-selezione e il componente utilizzato per creare un elemento. Come puoi immaginare, in questo scenario abbiamo 3 componenti Vue. Inizieremo con il componente che visualizza il modulo.

<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>

Come indicato sopra, stiamo caricando i campi in modo asincrono. Ora, per essere sicuri di popolare le opzioni, ogni volta che il componente che crea la voce risolve la risposta dal server, dobbiamo aggiungere una callback all’elemento <ns-field> in questo modo:

<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>

Stiamo usando field.props per ottenere la configurazione effettiva del componente Crud che viene caricato. Su quell’oggetto, abbiamo "optionsAttributes", che definiscono quale proprietà dovrebbe essere considerata come etichetta o quale dovrebbe essere usata come valore. Nota che queste due proprietà sono richieste per essere usate come opzione. Per impostazione predefinita, NexoPOS assume che tu stia usando "id" come valore e "name" come etichetta. Puoi modificare questo comportamento modificando "optionsAttributes" sul componente crud.

Se non stai utilizzando nsCrudForm per creare una voce, ti mostreremo come creare la tua componente personalizzata che verrà visualizzata in una finestra pop-up. Quando una componente viene aperta come pop-up, NexoPOS fornisce come prop aggiuntiva la variabile "popup"; questa può quindi essere usata per rilevare se viene visualizzata in un pop-up o meno. Ecco come definiremo la nostra 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>

Utilizzando la proprietà "popup" abbiamo accesso a vari parametri forniti dal nostro componente. Due di questi parametri sono "resolve" e "reject". Ci assicuriamo di entrambi per restituire la risposta del server.