- Crud operations
- Components for pagination and filtering
- Baz
Install the module to your Nuxt application with one command:
npx nuxi module add atom-nuxt
That's it! You can now use My Module in your Nuxt app ✨
Local development
# Install dependencies
npm install
# Generate type stubs
npm run dev:prepare
# Develop with the playground
npm run dev
# Build the playground
npm run dev:build
# Run ESLint
npm run lint
# Run Vitest
npm run test
npm run test:watch
# Release new version
npm run release
This repository provides a composable for managing CRUD operations and a Vue component for rendering a paginated list of items with filtering and actions.
The useCrudApi
composable provides a set of functions and reactive state management for performing CRUD operations against a specified API endpoint. It integrates authentication handling, pagination, filtering, and error management.
import { useCrudApi } from 'path/to/useCrudApi';
const { getItems, createItem, updateItem, deleteItem, items, currentPage } = useCrudApi('your/api/path');
-
path:
string
- The API endpoint path. -
watchPage:
boolean
(optional, default:true
) - Whether to watch the current page for changes. -
transformItem:
Function
(optional) - A function to transform a single item. -
transformItems:
Function
(optional) - A function to transform multiple items.
-
items:
Ref<Array>
- The list of items fetched from the API. -
currentPage:
Ref<number>
- The current page number. -
totalPages:
Ref<number>
- The total number of pages available. -
totalItems:
Ref<number>
- The total number of items available. -
perPage:
Ref<number>
- The number of items per page. -
filters:
Ref<Record<string, any>>[]
- The active filters. -
item:
Ref<any>
- The currently selected item. -
count:
Ref<number>
- The count of items. -
listErrors:
Ref<Record<string, any>>
- Errors encountered during list fetches. -
formErrors:
Ref<Record<string, any>>
- Errors encountered during form submissions. -
itemErrors:
Ref<Record<string, any>>
- Errors encountered when fetching or updating a single item. -
countErrors:
Ref<Record<string, any>>
- Errors encountered when fetching counts. -
exportErrors:
Ref<Record<string, any>>
- Errors encountered during export operations. -
hasFormErrors:
Ref<boolean>
- Indicates if there are form errors. -
hasItemErrors:
Ref<boolean>
- Indicates if there are item errors. -
hasCountErrors:
Ref<boolean>
- Indicates if there are count errors. -
hasExportErrors:
Ref<boolean>
- Indicates if there are export errors. -
listPending:
Ref<boolean>
- Indicates if a list fetch is pending. -
formPending:
Ref<boolean>
- Indicates if a form operation is pending. -
itemPending:
Ref<boolean>
- Indicates if fetching or updating an item is pending. -
countPending:
Ref<boolean>
- Indicates if a count fetch is pending. -
exportPending:
Ref<boolean>
- Indicates if an export operation is pending. -
getItems:
Function
- Fetches the items from the API. -
createItem:
Function
- Creates a new item in the API. -
updateItem:
Function
- Updates an existing item in the API. -
deleteItem:
Function
- Deletes an item from the API.
The CrudPaginatedLoader
component provides a UI for displaying a paginated list of items, along with options for filtering, creating, updating, and deleting items.
<script setup>
</script>
<template>
<crud-paginated-loader
path="your/api/path"
:custom-filters="{}"
create-title="Create Item"
update-title="Update Item"
delete-title="Delete Item"
:per-page="10"
:listeners="['onItemCreated']" <!-- List of events to listen for from useListenerService and reload results when the happen -->
:await="false" <!-- Set to true to wait for the fetchItems function to resolve before rendering -->
>
<!-- Your custom slots here -->
<template #before="{
items,
listPending,
createForm,
updateForm,
deleteForm,
formPending,
exportAction,
exportPending,
exportErrors
}">
<!-- Your custom content here -->
<v-btn @click="createForm">Open create form</v-btn>
<v-btn :loading="exportPending" @click="exportItems">Export filtered items</v-btn>
</template>
<template #default="{
items, // The list of items in current page
pending, // If the list is loading
updateForm, // Action to show the update form
deleteForm, // Action to show the delete form
formPending // If the form is loading
}">
<!-- Your item list here -->
<v-simple-table>
<template #default="{ items }">
<tr v-for="item in items" :key="item.id">
<td>{{ item.name }}</td>
<td>{{ item.email }}</td>
<td>
<v-btn @click="updateForm(item.id)">Edit</v-btn>
<v-btn @click="deleteForm(item.id)">Delete</v-btn>
</td>
</tr>
</template>
</v-simple-table>
</template>
<template #form="{
action, // The action to perform (create, update, delete)
item, // The item object to update prior to form submission
errors // The errors with any form submission
}">
<!-- Your form layout here typically in it's own component for neatness and reusability -->
<v-text-field
v-model="item.name"
label="Name"
:error="errors.name"
:error-messages="errors.name"
/>
<v-text-field
v-model="item.email"
label="Email"
:error="errors.email"
:error-messages="errors.email"
/>
</template>
</crud-paginated-loader>
</template>
-
fetchItems:
Function
- A function to fetch the items.
The useListenerService
is a utility service for managing event listeners in a JavaScript application. It allows you to add, remove, and notify listeners based on specific events.
This service is useful for applications that need to respond to various events without tightly coupling components. It provides a way to manage listeners dynamically, ensuring that they can be added or removed as needed.
type Listener = {
id: string; // Unique identifier for the listener
event: string; // Name of the event to listen for
callback: Function; // Function to call when the event occurs
};
This function initializes and returns the listener service, providing methods to manage listeners.
An object containing the following methods:
-
removeLocalListeners:
- Removes all listeners that were added during the current session.
-
removeLocalListenersWithEvent(event: string):
- Removes all local listeners associated with a specific event.
-
Parameters:
-
event
: The name of the event whose listeners should be removed.
-
-
addListener(event: string, callback: Function):
- Adds a new listener for the specified event.
-
Parameters:
-
event
: The name of the event to listen for. -
callback
: The function to call when the event is triggered.
-
- Returns: The unique identifier (ID) of the added listener.
-
removeListener(id: string):
- Removes a listener by its unique identifier.
-
Parameters:
-
id
: The unique identifier of the listener to be removed.
-
-
notify(key: string, data: any):
- Triggers all callbacks for listeners associated with the specified event.
-
Parameters:
-
key
: The name of the event to notify. -
data
: The data to pass to the callback functions.
-
const listenerService = useListenerService();
// Adding a listener
const listenerId = listenerService.addListener('myEvent', (data) => {
console.log('Event received:', data);
});
// Notifying listeners
listenerService.notify('myEvent', { key: 'value' });
// Removing a specific listener
listenerService.removeListener(listenerId);
// Removing all local listeners
listenerService.removeLocalListeners();
This composable provides a variety of utility functions for handling CRUD operations, formatting dates, converting files, and manipulating query strings in a Nuxt application.
Import useCrudConverters
where needed in your Nuxt components or composables.
import { useCrudConverters } from '~/path/to/composables';
Converts a local Date
object to a UTC ISO string formatted for database storage.
Performs a deep clone of the provided object.
Flattens nested objects into a single-level query string-compatible format.
Parses a query string into a JavaScript object.
Converts an object to a query string with configurable formatting options.
-
params
: The object to stringify. -
prefix
: Prefix for the query string. -
options
: Optional settings such asarrayFormat
andskipNull
.
Determines the file type based on its MIME type.
Maps MIME types to Material Design Icons.
Converts a file to a Base64-encoded string.
Concatenates address components into a formatted string.
Formats a date range string for display, adjusting based on current date context.
Formats a Date
object according to provided formatting options.
Formats a date string according to specified options.
Parses a date string into a Date
object.
Encodes filter values into a Base64-encoded JSON string.
Decodes a Base64 string back into a JavaScript object.
Extracts key-value pairs from an array of filter objects.
Constructs a URL for an uploaded file with specified size prefix (thumbnail
, medium
, large
).
Similar to uploadFilenameToUrl
but takes an object with a fileLocation
property.
Formats a UTC ISO date string from the database to the local timezone format.
Parses a date string in the local timezone and converts it to a UTC ISO date string for storage.
-
Flattening Query Parameters
const params = { user: { id: 1, name: "Alice" }, filters: { age: { min: 18, max: 30 }, isActive: true } }; const flatParams = flattenQuery(params); console.log(flatParams); // Output: { "user[id]": 1, "user[name]": "Alice", "filters[age][min]": 18, "filters[age][max]": 30, "filters[isActive]": true }
-
Encoding and Decoding Filters
const filters = { status: "active", roles: ["admin", "user"] }; const encodedFilters = filtersToBase64String(filters); const decodedFilters = base64StringToObj(encodedFilters); console.log(decodedFilters); // Output: { status: "active", roles: ["admin", "user"] }
-
Stringifying Query with Custom Options
const query = { name: "John", roles: ["admin", "user"], isActive: true }; const queryString = stringifyQuery(query, '', { arrayFormat: 'bracket' }); console.log(queryString); // Output: "name=John&roles[]=admin&roles[]=user&isActive=true"
-
Formatting Dates for Display and Storage
const dbDate = outputDateFromDb("2024-10-26T12:00:00Z", "dd MMM yyyy"); console.log(dbDate); // Output (localized): "26 Oct 2024" const isoDate = inputDateForDb("26/10/2024", "dd/MM/yyyy"); console.log(isoDate); // Output: "2024-10-26T00:00:00.000Z" (UTC format)
-
Converting a File to Base64
const fileInput = document.querySelector("input[type='file']"); fileInput.addEventListener('change', async (event) => { const file = event.target.files[0]; const base64String = await toBase64(file); console.log(base64String); });