fancy-crud

FancyCrud es una librería pensada para la creación de formularios y presentación de datos, en tablas utilizando Quasar Framework, gestionando el CRUD sobre registros.

Usage no npm install needed!

<script type="module">
  import fancyCrud from 'https://cdn.skypack.dev/fancy-crud';
</script>

README

Descripción

FancyCrud es una librería pensada para la creación de formularios y presentación de datos, en tablas utilizando Quasar Framework, gestionando el CRUD sobre registros.

La librería se compone de 3 elementos principales:

  • Formularios
  • Tablas
  • Filtros

Instalación

npm install fancy-crud

Configuración

//main.js

import { createApp } from 'vue'
import { Quasar } from 'quasar'
import axios from 'axios'
import quasarOptions from '@/plugins/quasar'
import FancyCrud from 'fancy-crud'

import App from './App.vue'

import '@quasar/extras/material-icons/material-icons.css'
import 'quasar/src/css/index.sass'

const app = createApp(App)

app.use(Quasar, quasarOptions)
app.use(FancyCrud, {
  axios,
  Notify
})

app.mount('#app')

FancyForm

Este componente permite la creación de formularios de manera dinámica, estableciendo los campos del formulario en un objeto javascript. El FancyForm utiliza los Form Components proporcionados por Quasar que puedes encontrar en su documentación oficial, el tipo de campo es especificado a través de la llave inputType y estos campos pueden utilizar la mayoría de las propiedades que se detallen en la documentación de Quasar, a continuación se listan los tipos de inputs disponibles y el componente de Quasar que utiliza:

inputTypes

Para comprender de mejor su forma de uso, vamos a simular la comunicación con un API que gestiona el CRUD sobre géneros musicales, artistas, álbumes y canciones.

Comencemos creando un componente que contenga un formulario, para ingresar nuevos géneros musicales. El API necesita que le enviemos los siguientes valores:

{
    "name": "NOMBRE DEL NUEVO GÉNERO MUSICAL",
    "is_active": "ESTATUS CON EL QUE SE VA A CREAR EL REGISTRO [true | false]"
}

De tal manera que nuestro componente quedará similar al siguiente:

// GenresForm.vue
<template>
  <f-form v-model="form.fields" v-bind="form.settings"></f-form>
</template>

<script lang="ts">
import { defineComponent, reactive } from 'vue'

export default defineComponent({
  setup() {
    const form = reactive({
      fields: {
        name: {
          label: 'Nombre'
        },
        is_active: {
          label: 'Estatus',
          modelValue: true,
          inputType: 'checkbox'
        },
      },
      settings: {
        url: 'genres/'
      }
    })

    return {
      form
    }
  }
})

</script>

Para entender mejor el componente vamos a describir la estructura del objeto que utiliza el FancyForm

const form = reactive({
/*`fields`, esta es la llave donde deben ir todos
 los campos del formulario a generar.
 Cada llave dentro de fields corresponde a la
 llave que se enviará en la petición POST, PUT
 or PATCH. De manera que la petición POST de
 este formulario, sería la siguiente:
 { name: 'VALOR INGRESADO', is_active: true }*/
  fields: {

 /*Observe que en la llave name no se indica
 el inputType, así como tampoco se indica
 el modelValue. Esto es porque son llaves
 predeterminadas, el inputType por defecto
 de un field es `textfield` y para el
 el modelValue es `null`*/
    name: {
      label: 'Nombre'
  },

/*En este field especificamos el modelValue
    esto indica que este campo se mostrara
    con ese valor por defecto en el formulario
    y también se indica que este campo tiene
    que mostrarse como un checkbox de Quasar*/
    is_active: {
      label: 'Estatus',
      modelValue: true,
      inputType: 'checkbox'
    },
  },
  settings: {
/*Indica el endpoint al que debe enviar la petición.
    Considere que debe haber indicado el baseUrl en
    las configuraciones del axios, de otra manera,
    debe indicar el dominio y el endpoint al que 
    va apuntar la petición.*/
    url: 'genres/'
  }
})

Props

modelValue

type: Object

required: true

Los campos especificados en la llave fields, que serán utilizados para generar el formulario.

Ejemplo:

fields: {
    campo1: {
        label: 'Titulo del campo 1'
    },
    campo1: {
        label: 'Titulo del campo 2'
    }
}

mode

type: String

required: false

Valor predeterminado: 'CREATE_MODE'

Establece el tipo de petición que realizará el formulario. 'CREATE_MODE' para realizar una petición POST y UPDATE_MODE para realizar una petición PATCH.

Los dos modos se pueden importar directamente desde el paquete de fancy-crud el siguiente ejemplo demuestra como realizar dicha acción:

import { CREATE_MODE, UPDATE_MODE } from "fancy-crud"

url

type: String

required: true

URL que utilizará el formulario para enviar los datos. En el caso de que no se halla indicado el baseUrl en el axios config, deberá indicar protocolo HTTP seguido del dominio donde realizará la petición.

Ejemplo:

settings: {
    url: 'albums/'
}

// En caso de no haber indicado el baseUrl en el axios config
{
    url: 'https://example.com/albums'
}

record

type: Object

required: false

Valor predeterminado: {}

Objeto que se utilizará para establecer los valores por defecto en el formulario, en caso de que el formulario se establezca en modo de actualización. Entienda este campo como el registro que se encuentra almacenado en la base de datos y que va a proceder a editar.

Ejemplo:

record: {
    id: 23,
    name: 'Pop',
    is_active: true,
    created_at: '2021-11-02',
    updated_at: '2021-11-05'
}

lookupField

type: String

required: false

Valor predeterminado: 'id'

Es el campo que se encuentra en el objeto del props record y se utilizará para para agregar el identificador en el endpoint.

Ejemplo:

/*Considere el siguiente objeto que obtuve desde la base de datos,
    el valor predeterminado del lookupField es `id`, entonces la url
    que se va a generar a partir de la que se encuentra establecida
    en el `settings` es la siguiente: 'genres/23/'

record: {
    id: 23,
    name: 'Pop',
    is_active: true,
    created_at: '2021-11-02',
    updated_at: '2021-11-05'
}
*/

settings: {
    url: 'genres/'
}

titles

type: Object

required: false

Valor predeterminado:

settings: {
    titles: {
        create: 'Crear elemento',
        update: 'Actualizar elemento',
        hidden: false
    }
}

Ejemplo:

settings: {
    titles: {
        create: 'Crear album',
        update: 'Actualizar album'
    }
}

buttons

type: Object

required: false

Valor predeterminado:

{
    main: {
    createLabel: 'Crear nuevo',
    updateLabel: 'Actualizar registro',
    color: 'primary',
    fullwidth: false,
    hidden: false,
    icon: null
    },
    aux: {
        createLabel: 'Crear nuevo',
    updateLabel: 'Actualizar registro',
    color: 'primary',
    fullwidth: false,
    hidden: false,
    icon: null
    },
    invertedPosition: boolean,
    align: string,
    class: {}
}

messages

type: Object

required: false

Valor predeterminado:

{
  create: {
    position: 'top-right',
    message: 'Elemento creado con éxito',
    color: 'positive',
    display: true,
  },
  update: {
    position: 'top-right',
    message: 'Elemento actualizado con éxito',
    color: 'positive',
    display: true,
  },
  delete: {
    position: 'top-right',
    message: 'Elemento eliminado con éxito',
    color: 'positive',
    display: true,
  },
  error: {
    position: 'top-right',
    message: 'Error inesperado, contacte con soporte técnico',
    color: 'negative',
    display: true,
    ...messages.error
  }
}

Este objeto realiza la configuración para las notificaciones que se lanzan al crear un nuevo registro, actualizar un registro existente, eliminar un registro o cuando sucede un error.

Slots

form-header

Sobreescribe la cabecera del formulario. Útil cuando se requiere utilizar encabezados más elaborados, si lo único que necesita es cambiar el texto del encabezado, se recomienda utilizar la propiedad titles

Scope

title se define dependiendo del modo en el que se encuentra el formulario, ya sea CREATE_MODE o UPDATE_MODE.

Ejemplo de uso del slot form-header

// Utilizando el scope `title`, de esta manera unicamente
// cambiamos la etiqueta del titulo
<f-form v-model="form.fields" v-bind="form.settings">
  <template v-slot:form-header="{ title }">
    <h5>{{ title }}</h5>
  </template>
</f-form>

// Utilizando el slot, pero sin hacer uso del scope `title`
<f-form v-model="form.fields" v-bind="form.settings">
  <template v-slot:form-header="{ title }">
    <h3>Cambiando el titulo por un texto diferente</h3>
  </template>
</f-form>

form-footer

Este slot nos provee de la habilidad para sobreescribir la sección del formulario donde se encuentran los botones.

Scope

buttons: Este scope nos devuelve un objeto que contiene las llaves main y aux que son los dos botones por defecto que tiene el formulario. La estructura de estos botones es la misma que se maneja para la propiedad buttons.

on: contiene un objeto con dos funciones, triggerCreate y triggerUpdate. Puede utilizar cualquiera de estas dos funciones en el evento click del botón.

before-[field]

Tenemos disponible un slot por cada campo de nuestro formulario, este slot se ubica, antes de cada campo.

after-[field]

Este slot es igual que el slot before-[field], pero con la diferencia de que se ubica, después de cada campo