DEV Community

Samiullah Khan
Samiullah Khan

Posted on • Originally published at technbuzz.com on

Add Sorting to Your Table Using Angular Signals

In the previous guide we populated HTML table with Angular httpResource API. You can read more about it. This time we will make the table interactive. We will find out how well httpResource and Angular Signals plays together when it comes to sorting.

What are we building with Angular Signals

Here is how the final sortable table behaves


A quick look of how sorting interaction feels in the browser

How we gonna build it

We will expand on our previous achievements. On template side we have a table. We need to add

  1. Properties to track sorting
  2. Sort Indicators in template
  3. Reacting to Angular Signals for Sorting
  4. Sorting trigger on the column

Properties to Track Sorting

We will need few properties (of course Angular signals) to track the

  • Column to Sort ( Post ID , Name )
  • Sort Direction (ascending or descending)
sort = signal('');
order = signal('asc');

// or one object to consolidate both properties
Enter fullscreen mode Exit fullscreen mode

Sort Indicators in template

We have table headers, we will pick one of them. Let’s choose PostId as our subject

<th>Post ID</th>
Enter fullscreen mode Exit fullscreen mode

For simplicity I am using unicode characters to illustrate ascending and descending order ↑ and ↓ respectively.

<th>
 <span>Post ID</th>
 @if(order() === 'asc') {
   <span></span>
 } @else {
   <span></span>
 }
</th>
Enter fullscreen mode Exit fullscreen mode

Since th is not limited to text nodes, we need to use span to group our new additions of sort order icons. Here we are checking for angular signal order() and showing icon accordingly.

But we need to show Sort indicators only when it’s necessary. Let’s expand our template

<th>
 <span>Post ID</th>
 @if(sort() === 'postId') {
   @if(order() === 'asc') {
     <span></span>
   } @else {
     <span></span>
   }
 }
</th>

Enter fullscreen mode Exit fullscreen mode

Line 3 wraps all the previous control flow code in yet another @if block. This is to confirm the sorting behavior only when current header is active.

Reacting to Angular Signals for Sorting

comments = httpResource<Comment[]>(() => ({
    url: 'https://jsonplaceholder.typicode.com/comments',
    params: {
      _limit: 10,
    }
  }), {defaultValue: []},
);

Enter fullscreen mode Exit fullscreen mode

All the magic happens in the params object. After adding new params from the JSONPlaceholder api, our code becomes

comments = httpResource(() => ({
  //..
  params: {
    _limit: 10,
    _sort: this.sort(),
    _order: this.order()
  }
  //..
 );

Enter fullscreen mode Exit fullscreen mode

The params are reactive, as soon as the sort or order signal updates, the httpResource will re run bringing new slice. That eventually updates our table on the HTML.

The whole purpose of this article was to illustrate this exact point. How our httpResource reacts to signals. It automatically fetches new set of data, matching the sorted column and direction that we chose.

We do need a way to update those two properties

Implementing the Sort trigger

We need to make our column clickable.

<th (click)="sortBy('postId')">
  <span>Post ID</span>
  // ...
</th>

Enter fullscreen mode Exit fullscreen mode

Our sortBy handles the sort logic. It basically updates the appropriate signals.

sortBy(field: string) {
  if(this.sort() === field) {
    const newDir = this.order() === 'asc' ? 'desc' : 'asc';
    this.order.set(newDir)
    return
  }

  this.sort.set(field);
  this.order.set('asc');
}
Enter fullscreen mode Exit fullscreen mode

If the column is already sorted then we need to only change the direction. Otherwise we set the currency active sorted column by updating sort and order signals

The feel of declarative programming. We didn’t forced or did any kind of manually plumbing to fetch the data and update the column.

How angular signals sorts update the comments httpResource that in turn updates our HTML table

We have successfully added the Sort feature to Post ID column. Let’s add to one more column.

<th (click)="sortBy('email')">
  <span>Email</span>
  @if(sort() === 'email') {
    @if(order() === 'asc') {
      <span></span>
    } @else {
      <span></span>
    }
  }
</th>
Enter fullscreen mode Exit fullscreen mode

Now email is also a sortable column. The result becomes.


A demo video representing column interaction of Table of User Comments

The UX here feels jittery, because httpResource resets to an empty array during loading state. Previously the workaround was to use linkedSignal to always show previous state, but hold Angular has much better solution.

Resource composition with Snapshot

Angular came up with Resource Snapshot. By combining previous and next snapshot using linkedSignal, we always have that is not empty. People at Angular love did an amazing job in explaining it.

We have little change in our code.

function withPreviousValue<T>(input: Resource<T>):Resource<T> {

  const derived = linkedSignal<ResourceSnapshot<T>, ResourceSnapshot<T>>({
    source: input.snapshot,
    computation: (snap, previous) => {
      if (snap.status === 'loading' && previous && previous.value.status !== 'error') {
        return { status: 'loading' as const, value: previous.value.value }
      }
      return snap
    }
  })

  return resourceFromSnapshots(derived) 
}

// ....
commentsRes = httpResource<Comment[]>(() => ({
    url: 'https://jsonplaceholder.typicode.com/comments',
    params: {
      _limit: 10,
      _sort: this.sort(),
      _order: this.order()
    }
  }), {defaultValue: []},
);

comments = withPreviousValue(this.commentsRes);
//...
Enter fullscreen mode Exit fullscreen mode

We call our original resource a commentRes, we pass it along to withPreviousValue function. We need a way to look for previous snapshot, if it exits and has a value we return that other we swap it with newer snapshot. LinkedSignal is perfect candidate for this purpose. It declaratively takes the best decision.

Final Result

With sorting in place, our table is interactive and reactive

Next Steps (Coming Soon)

Every time we make a column sortable, we have to add extra markup. This can be moved to reusable logic, into a composable directive.

Resources & Repo Links

The post Add Sorting to Your Table Using Angular Signals appeared first on Technbuzz.com.

Top comments (0)