UNPKG

@ea-lab/reactive-json-docs

Version:

Complete documentation for Reactive-JSON - Components, examples and LLM-parsable guides

406 lines (332 loc) 11.2 kB
# Bulk Actions System This guide demonstrates how to implement a bulk action system that allows users to select multiple items in a list and perform actions on all selected items simultaneously. This pattern is commonly used in data tables, file managers, and admin interfaces. ## Core Concept The bulk action system uses a combination of: - **Selection state**: Track which items are selected using checkboxes - **Data attributes**: Mark selected rows in the DOM for CSS selector targeting - **Event delegation**: Use `triggerEvent` to programmatically trigger actions on multiple elements - **Conditional actions**: Ensure actions only execute on selected items ## Concepts We Will Use This pattern leverages several Reactive-JSON features: - **[Switch Component](../element/special/Switch.md)**: Iterate over a collection of items and render each with a template - **[SetAttributeValue Action](../action/Attribute/SetAttributeValue.md)**: Dynamically set HTML attributes (like `data-selected`) based on data state - **[triggerEvent Reaction](../reaction/triggerEvent.md)**: Programmatically dispatch events on multiple elements matching a CSS selector - **[Template Contexts](../getting-started/template-contexts-data-binding.md)**: Use `~.` for row-scoped data and `~~.` for global data - **[Conditional Actions](../getting-started/actions.md)**: Use `when` conditions to control when actions execute ## Prerequisites Before implementing bulk actions, you should understand: 1. **Template system**: How `Switch` renders items using templates 2. **Data binding**: The difference between `~.` (local template context) and `~~.` (global context) 3. **Actions and reactions**: How to define actions that respond to user interactions 4. **CSS selectors**: Basic understanding of attribute selectors like `[data-selected="true"]` ## Steps ### Step 1: Set Up Selection State Add a `selected` property to each item in your data array and a global `bulkAction` variable: ```yaml data: items: [] bulkAction: "" ``` Each item in the array should have a `selected` boolean property (can be initialized as `false` or added dynamically). ### Step 2: Add Selection Checkboxes Add checkboxes to each row to allow users to select individual items: ```yaml templates: itemRow: - type: tr content: - type: td content: - type: CheckBoxField dataLocation: ~.selected defaultFieldValue: false options: - label: "" value: true ``` ### Step 3: Mark Selected Rows with Data Attributes Use `setAttributeValue` action to add a `data-selected` attribute to rows when they are selected. This allows CSS selectors to target selected rows: ```yaml templates: itemRow: - type: tr actions: - what: setAttributeValue name: "data-selected" value: "true" mode: "replace" when: ~.selected is: true content: # ... row content ``` **Important**: Use `mode: "replace"` to ensure the attribute is removed when `selected` becomes `false`. You may also want to add an action to remove the attribute when not selected. ### Step 4: Add Action Buttons with Data Attributes Add `data-action` attributes to action buttons so they can be targeted by CSS selectors: ```yaml - type: button attributes: data-action: "process" type: "button" content: "Process" actions: - what: submitData on: click # ... action configuration ``` ### Step 5: Create Bulk Action Controls Add a bulk action selector and execute button in your main view: ```yaml renderView: - type: SelectField dataLocation: ~~.bulkAction defaultFieldValue: "" options: - value: "" label: "-- Choose action --" - value: "process" label: "Process selected items" - type: button content: "Execute" actions: - what: hide when: ~~.bulkAction isEmpty: true - what: triggerEvent on: click eventName: "click" selector: "tr[data-selected=\"true\"] button[data-action=\"process\"]" ``` ### Step 6: Add Safety Conditions Add conditions to prevent actions from executing on items that shouldn't be processed: ```yaml - type: button attributes: data-action: "process" actions: - what: hide when: ~.status is: "processed" # Hide button if already processed - what: submitData on: click # ... only executes if button is visible ``` ## Complete Example Here's a complete example of a file management table with bulk processing: ```yaml renderView: - type: table content: - type: tbody content: - type: Switch content: ~~.files singleOption: load: fileRow # Bulk action controls - type: div content: - type: SelectField dataLocation: ~~.bulkAction defaultFieldValue: "" options: - value: "" label: "-- Choose action --" - value: "process" label: "Process selected files" - type: button content: "Execute" actions: - what: hide when: ~~.bulkAction isEmpty: true - what: triggerEvent on: click eventName: "click" selector: "tr[data-selected=\"true\"] button[data-action=\"process\"]" templates: fileRow: - type: tr actions: - what: setAttributeValue name: "data-selected" value: "true" mode: "replace" when: ~.selected is: true - what: setAttributeValue name: "data-selected" value: "false" mode: "replace" when: ~.selected isNot: true content: # Checkbox column - type: td content: - type: CheckBoxField dataLocation: ~.selected defaultFieldValue: false options: - label: "" value: true # File name column - type: td content: ~.name # Status column - type: td content: ~.status # Actions column - type: td content: - type: button attributes: data-action: "process" type: "button" content: "Process" actions: - what: hide when: ~.status is: "processed" - what: setData on: click path: ~.status value: "processing" - what: submitData on: click url: "https://api.example.com/process?id=~.id" httpMethod: "post" allowConcurrent: true dataMapping: simpleMapping: stringMap: "~.status": value: "processed" data: files: - id: "file1" name: "document.pdf" status: "pending" selected: false - id: "file2" name: "image.jpg" status: "pending" selected: false bulkAction: "" ``` ## How It Works 1. **Selection**: Users check boxes to set `~.selected` to `true` for individual items 2. **Attribute marking**: `setAttributeValue` adds `data-selected="true"` to selected rows 3. **Bulk trigger**: When "Execute" is clicked, `triggerEvent` finds all `tr[data-selected="true"]` rows 4. **Action execution**: Within each selected row, it finds `button[data-action="process"]` and triggers a `click` event 5. **Individual processing**: Each button's `on: click` reactions execute, processing that specific item ## Go Further ### Select All Functionality Add a "Select All" checkbox in the table header: ```yaml - type: th content: - type: CheckBoxField dataLocation: ~~.selectAll defaultFieldValue: false options: - label: "" value: true actions: - what: setData on: change path: ~.selected value: ~~.selectAll # This would need to be in each row template ``` ### Multiple Action Types Support multiple bulk actions by using different `data-action` values: ```yaml - type: SelectField dataLocation: ~~.bulkAction options: - value: "process" label: "Process" - value: "delete" label: "Delete" - value: "archive" label: "Archive" # In triggerEvent, dynamically construct selector: - what: triggerEvent on: click eventName: "click" selector: ["tr[data-selected=\"true\"] button[data-action=\"", ~~.bulkAction, "\"]"] ``` ### Visual Feedback Add visual indicators for selected rows using CSS: ```yaml - type: tr attributes: class: "bg-white border-b" actions: - what: setAttributeValue name: "class" value: "bg-blue-100" mode: "append" when: ~.selected is: true ``` ### Prevent Double Processing Add conditions to prevent processing items that are already being processed: ```yaml - type: button attributes: data-action: "process" actions: - what: hide when: ~.status is: "processing" - what: hide when: ~.status is: "processed" # Actions only execute if button is visible ``` ### Count Selected Items Display the number of selected items: ```yaml - type: div content: - "Selected: " - type: Count jsonPathPattern: "$.files[?(@.selected == true)]" ``` ## Additional Notes ### Performance Considerations - **Concurrent requests**: Use `allowConcurrent: true` in `submitData` to process multiple items simultaneously - **Selector efficiency**: More specific selectors (like `tr[data-selected="true"]`) are faster than broad selectors - **Event delegation**: `triggerEvent` dispatches events sequentially using Promises to ensure reliability ### Accessibility - Ensure checkboxes have proper labels - Use ARIA attributes for screen readers: ```yaml - what: setAttributeValue name: "aria-selected" value: "true" when: ~.selected is: true ``` ### Error Handling Consider adding error handling for failed bulk operations: ```yaml - what: submitData on: click # ... submit configuration onError: - what: setData path: ~.status value: "error" ``` ### Alternative Approaches - **Message-based**: Use `postMessage` and `on: message` reactions (more complex but allows cross-component communication) - **Custom handlers**: Create a custom React component to handle bulk operations (more control but requires JavaScript) ### Best Practices 1. **Always use `mode: "replace"`** for `setAttributeValue` when toggling boolean attributes to ensure clean state 2. **Use specific selectors** to avoid unintended side effects 3. **Add safety conditions** to prevent actions on inappropriate items 4. **Provide visual feedback** so users know which items are selected 5. **Test with multiple selections** to ensure concurrent operations work correctly