Filter Modal
The Filter Component is a reusable modal that provides a menu with customizable filter options. It allows users to filter data based on different criteria and apply those filters to the parent component.
Features
- Popup overlay menu with filter options
- Support for dropdown select filters
- Filter clearing functionality
- Reset all filters option
- Apply filters button
Usage
ModalFilterMenu.vue- This is the main filter menu component that renders a popup overlay with filter options.
<template>
<OverlayPanel
ref="op"
id="overlay_menu"
:popup="true"
class="w-[240px] rounded-lg"
>
<!-- Modal Header -->
<div>
<div
class="flex items-center justify-between px-4 py-[10px] bg-neutral-20"
>
<div class="flex items-center gap-3">
<h5 class="body-normal font-medium text-neutral-500">Filter</h5>
</div>
<button @click="toggle">
<i
class="pi pi-times text-neutral-500 text-xs hover:bg-primary-50 p-2 hover:rounded-full"
/>
</button>
</div>
</div>
<div class="p-4">
<div v-for="(item, index) in items" :key="index" class="mb-4">
<div class="mb-2 flex justify-between items-center">
<label class="body-small">{{ item.label }} </label>
<p
@click="handleClear(index)"
class="body-small text-primary-500 cursor-pointer"
>
Clear
</p>
</div>
<FormSelect
v-if="item.field === 'Select'"
v-model="selectedValues[index]"
optionLabel="name"
item-value="value"
placeholder="All"
required
class="h-[36px]"
:options="item.options"
:value="selectedValues[index]"
name="field"
@change="handleSelectChange(index)"
/>
</div>
<!-- Modal Footer -->
<div class="flex items-center gap-4 pt-4 border-t border-neutral-100">
<div class="w-full">
<CommonButton
title="Reset"
bgColor="bg-neutral-30"
textColor="text-neutral-500 font-semibold text-sm h-8"
type="button"
@click="resetModal"
/>
</div>
<div class="w-full">
<CommonButton
title="Apply"
bgColor="bg-primary-300 text-neutral-500 h-8"
textColor="font-semibold text-sm"
type="submit"
:loading="isLoading"
@click="onPrimaryAction"
/>
</div>
</div>
</div>
</OverlayPanel>
</template>
<script setup>
import { ref } from "vue";
import FormSelect from "~/components/common/input/FormSelect.vue";
const op = ref(null);
const selectedValues = ref([]); // Store selected values for each item
const isLoading = ref(false);
// Define props for the component
const props = defineProps({
items: {
type: Array,
required: true,
},
});
// Emit events for toggling the menu and reset
const emit = defineEmits(["toggle", "reset"]);
// Define the toggle function
const toggle = (event) => {
op.value.toggle(event);
emit("toggle", event);
};
// Handle select change
const handleSelectChange = (index) => {
console.log("Selected value:", selectedValues.value);
};
// Handle clear button click
const handleClear = (index) => {
selectedValues.value[index] = null; // Reset the selected value
};
// Reset all filters
const resetModal = () => {
selectedValues.value = []; // Reset all selected values
emit("reset"); // Emit reset event
op.value.hide(); // Hide the menu after reset
};
// Apply filters
const onPrimaryAction = () => {
const filteredValues = [...selectedValues.value];
emit("toggle", filteredValues);
op.value.hide(); // Hide menu after applying
};
// Expose the toggle function to the parent component
defineExpose({
toggle,
});
</script>
Basic Implementation
<template>
<!-- Filter Button -->
<button
class="h-[48px] px-5 rounded-[8px] flex justify-center items-center bg-none border border-neutral-100 text-neutral-200 font-normal text-sm hover:bg-primary-75 hover:border-primary-75"
@click="toggle"
aria-haspopup="true"
aria-controls="overlay_menu"
>
<span class="mr-2">
<BaseCustomIcon name="filter" />
</span>
<p>Filter</p>
</button>
<!-- Filter Menu Component -->
<ModalFilterMenu
ref="reusableMenu"
:items="menuItems"
@toggle="handleMenuToggle"
/>
</template>
<script setup>
import { ref } from "vue";
import ModalFilterMenu from "~/components/ModalFilterMenu.vue";
// Reference to the filter menu
const reusableMenu = ref();
// Define menu items
const menuItems = ref([
{
label: "Staff",
field: "Select",
options: [
{ name: "Pending", value: "Pending" },
{ name: "Completed", value: "Completed" },
],
},
{
label: "Feature",
field: "Select",
options: [
{ name: "Credit", value: "Credit" },
{ name: "Debit", value: "Debit" },
],
},
]);
// Function to toggle the menu
const toggle = (event) => {
reusableMenu.value.toggle(event);
};
// Handle menu toggle event
const handleMenuToggle = (event) => {
console.log("Menu toggled", event);
};
</script>