Hone logo
Hone
Problems

Angular Table Sorting

This challenge requires you to implement interactive table sorting functionality within an Angular application. Users should be able to click on table headers to sort the displayed data in ascending or descending order. This is a fundamental feature for any data-driven interface, improving user experience by allowing them to quickly find and analyze information.

Problem Description

You need to create an Angular component that displays a table of data and allows users to sort the data by clicking on the column headers.

Key Requirements:

  1. Data Display: The component should accept an array of objects as input, where each object represents a row and its properties represent the columns.
  2. Sortable Headers: Each table header (corresponding to an object property) should be clickable.
  3. Sorting Logic:
    • Clicking a header should sort the data in ascending order based on the selected column.
    • Clicking the same header again should sort the data in descending order.
    • Subsequent clicks on other headers should reset the sort order to ascending for the new column.
  4. Visual Feedback: Provide visual cues to indicate which column is currently sorted and in which direction (e.g., up/down arrows).
  5. Component Structure: Implement this logic within a reusable Angular component.

Expected Behavior:

When the component loads, the table should display the data as provided. Upon clicking a header:

  • The table data should reorder accordingly.
  • An arrow icon should appear next to the header, pointing up for ascending and down for descending.
  • Clicking the same header again reverses the sort direction and updates the arrow.
  • Clicking a different header sorts by that new column in ascending order and updates the visual feedback.

Edge Cases:

  • Empty Data: Handle cases where the input data array is empty. The table should display gracefully.
  • Non-Comparable Data Types: Consider how to handle sorting for columns with mixed data types or types that are not easily comparable (e.g., objects within objects). For this challenge, assume basic comparable types like strings, numbers, and dates.
  • Case-Insensitive Sorting: For string comparisons, sorting should ideally be case-insensitive.

Examples

Let's consider a simple data set representing products:

interface Product {
  id: number;
  name: string;
  price: number;
  inStock: boolean;
}

const sampleProducts: Product[] = [
  { id: 1, name: 'Laptop', price: 1200, inStock: true },
  { id: 2, name: 'Mouse', price: 25, inStock: false },
  { id: 3, name: 'Keyboard', price: 75, inStock: true },
  { id: 4, name: 'Monitor', price: 300, inStock: true },
  { id: 5, name: 'Webcam', price: 50, inStock: false },
];

Example 1: Initial Display

Input: sampleProducts

Output: A table displaying the products as listed above. No column is sorted initially, so no arrows are shown.

Explanation: The component renders the data in its original order.

Example 2: Sorting by 'price' (Ascending)

Input: Click the 'price' header.

Output: The table data reordered by price ascending:

[
  { id: 2, name: 'Mouse', price: 25, inStock: false },
  { id: 5, name: 'Webcam', price: 50, inStock: false },
  { id: 3, name: 'Keyboard', price: 75, inStock: true },
  { id: 4, name: 'Monitor', price: 300, inStock: true },
  { id: 1, name: 'Laptop', price: 1200, inStock: true }
]

The 'price' header will have an upward-pointing arrow.

Explanation: The data is sorted based on the price property in ascending order.

Example 3: Sorting by 'price' (Descending)

Input: Click the 'price' header again.

Output: The table data reordered by price descending:

[
  { id: 1, name: 'Laptop', price: 1200, inStock: true },
  { id: 4, name: 'Monitor', price: 300, inStock: true },
  { id: 3, name: 'Keyboard', price: 75, inStock: true },
  { id: 5, name: 'Webcam', price: 50, inStock: false },
  { id: 2, name: 'Mouse', price: 25, inStock: false }
]

The 'price' header will have a downward-pointing arrow.

Explanation: The data is sorted based on the price property in descending order.

Example 4: Sorting by 'name' (Ascending) after sorting by 'price'

Input: After sorting by 'price' descending (as in Example 3), click the 'name' header.

Output: The table data reordered by name ascending:

[
  { id: 1, name: 'Laptop', price: 1200, inStock: true },
  { id: 3, name: 'Keyboard', price: 75, inStock: true },
  { id: 2, name: 'Mouse', price: 25, inStock: false },
  { id: 4, name: 'Monitor', price: 300, inStock: true },
  { id: 5, name: 'Webcam', price: 50, inStock: false }
]

The 'name' header will have an upward-pointing arrow. The 'price' header will have no arrow.

Explanation: Clicking a new header resets the sort to ascending for that column.

Constraints

  • The input data array will contain at least 0 and at most 1000 objects.
  • Each object in the input array will have at least 3 and at most 10 properties.
  • Property values will be of primitive types: string, number, or boolean. Assume dates are represented as Date objects or parsable date strings.
  • The component should be performant enough to handle up to 1000 rows without noticeable lag.

Notes

  • Consider using Angular's sort() method on arrays.
  • You'll need to manage the current sort column and direction state within your component.
  • For visual feedback, you can use simple text characters (e.g., ▲, ▼) or CSS classes to represent arrows.
  • Think about how to dynamically generate table headers and rows based on the input data's keys.
  • For string comparisons, localeCompare() is a good choice for case-insensitive and locale-aware sorting.
Loading editor...
typescript