## 6: Filter tasks

In this step, you will filter your tasks by status and show the number of pending tasks.

### 6.1: Reactive State

First, you will add a button to show or hide the completed tasks from the list.

In Solid, we manage component state using signals for reactivity. Solid's fine-grained reactivity will automatically update the UI when the state changes.

We'll add a `hideCompleted` variable to the `App.jsx` component and a function to toggle it.

::: code-group

```jsx [imports/ui/App.jsx]
import { createSignal, For, Show } from "solid-js";
import { Meteor } from "meteor/meteor";
import { Tracker } from "meteor/tracker";
import { TasksCollection } from "../api/TasksCollection";
import { Task } from "./Task.jsx";

export const App = () => {
  const [newTask, setNewTask] = createSignal('');
  const [hideCompleted, setHideCompleted] = createSignal(false); // [!code highlight]

  const addTask = async (event) => {
    event.preventDefault();
    if (newTask().trim()) {
      await Meteor.callAsync("tasks.insert", {
        text: newTask(),
        createdAt: new Date(),
      });
      setNewTask('');
    }
  };

  const toggleHideCompleted = () => { // [!code highlight]
    setHideCompleted(!hideCompleted()); // [!code highlight]
  }; // [!code highlight]

  const subscription = Meteor.subscribe("tasks");
  const [isReady, setIsReady] = createSignal(subscription.ready());
  const [tasks, setTasks] = createSignal([]);

  Tracker.autorun(async () => {
    setIsReady(subscription.ready());
    setTasks(await TasksCollection.find({}, { sort: { createdAt: -1, _id: -1 } }).fetchAsync());
  });

  // markup will be updated in next steps
};
```
:::

Then, add the button in the markup to toggle the state:

::: code-group

```jsx [imports/ui/App.jsx]
// ... javascript above remains the same

return (
  <div class="app">
    <header>
      <div class="app-bar">
        <div class="app-header">
          <h1>📝️ Todo List</h1>                    
        </div>
      </div>
    </header>

    <div class="main">
      <form class="task-form" onSubmit={addTask}>
        <input
          type="text"
          placeholder="Type to add new tasks"
          value={newTask()}
          onInput={(e) => setNewTask(e.currentTarget.value)}
        />
        <button type="submit">Add Task</button>
      </form>

      <div class="filter"> // [!code highlight]
        <button onClick={toggleHideCompleted}> // [!code highlight]
          <Show // [!code highlight]
            when={hideCompleted()} // [!code highlight]
            fallback="Hide Completed" // [!code highlight]
          > // [!code highlight]
            Show All // [!code highlight]
          </Show> // [!code highlight]
        </button> // [!code highlight]
      </div> // [!code highlight]

      <Show
        when={isReady()}
        fallback={<div>Loading ...</div>}
      >
        <ul class="tasks">
          <For each={tasks()}>
            {(task) => (
              <Task task={task} />
            )}
          </For>
        </ul>
      </Show>
    </div>
  </div>
);
```
:::

You may notice we’re using `<Show>` for the button text. You can learn more about Solid's conditional rendering [here](https://docs.solidjs.com/reference/components/show).

### 6.2: Button style

You should add some style to your button so it does not look gray and without a good contrast. You can use the styles below as a reference:

::: code-group

```css [imports/ui/main.css]
.filter {
  display: flex;
  justify-content: center;
}

.filter > button {
  background-color: #62807e;
}
```

:::

### 6.3: Filter Tasks

Now, update the reactive tasks fetch to apply the filter if `hideCompleted` is true. We'll also add a reactive signal for the incomplete count using another Tracker.autorun.

::: code-group

```jsx [imports/ui/App.jsx]
import { createSignal, For, Show } from "solid-js";
import { Meteor } from "meteor/meteor";
import { Tracker } from "meteor/tracker";
import { TasksCollection } from "../api/TasksCollection";
import { Task } from "./Task.jsx";

export const App = () => {
  const [newTask, setNewTask] = createSignal('');
  const [hideCompleted, setHideCompleted] = createSignal(false);

  const addTask = async (event) => {
    event.preventDefault();
    if (newTask().trim()) {
      await Meteor.callAsync("tasks.insert", {
        text: newTask(),
        createdAt: new Date(),
      });
      setNewTask('');
    }
  };

  const toggleHideCompleted = () => {
    setHideCompleted(!hideCompleted());
  };

  const subscription = Meteor.subscribe("tasks");
  const [isReady, setIsReady] = createSignal(subscription.ready());
  const [tasks, setTasks] = createSignal([]);

  Tracker.autorun(async () => {
    setIsReady(subscription.ready());
    const query = hideCompleted() ? { isChecked: { $ne: true } } : {}; // [!code highlight]
    setTasks(await TasksCollection.find(query, { sort: { createdAt: -1, _id: -1 } }).fetchAsync()); // [!code highlight]
  });

  // Reactive incomplete count // [!code highlight]
  const [incompleteCount, setIncompleteCount] = createSignal(0); // [!code highlight]
  Tracker.autorun(async () => { // [!code highlight]
    setIncompleteCount(await TasksCollection.find({ isChecked: { $ne: true } }).countAsync()); // [!code highlight]
  }); // [!code highlight]

  // markup remains the same
};
```

:::

### 6.4: Meteor Dev Tools Extension

You can install an extension to visualize the data in your Mini Mongo.

[Meteor DevTools Evolved](https://chrome.google.com/webstore/detail/meteor-devtools-evolved/ibniinmoafhgbifjojidlagmggecmpgf) will help you to debug your app as you can see what data is on Mini Mongo.

<img width="800px" src="/tutorials/solid/assets/step06-extension.png"/>

You can also see all the messages that Meteor is sending and receiving from the server, this is useful for you to learn more about how Meteor works.

<img width="800px" src="/tutorials/solid/assets/step06-ddp-messages.png"/>

Install it in your Google Chrome browser using this [link](https://chrome.google.com/webstore/detail/meteor-devtools-evolved/ibniinmoafhgbifjojidlagmggecmpgf).

### 6.5: Pending tasks

Update the App component in order to show the number of pending tasks in the app bar.

You should avoid adding zero to your app bar when there are no pending tasks. Use the reactive `incompleteCount` in the header:

::: code-group

```jsx [imports/ui/App.jsx]
// ... javascript with incompleteCount remains the same

return (
  <div class="app">
    <header>
      <div class="app-bar">
        <div class="app-header">
          <h1>📝️ To Do List {incompleteCount() > 0 ? `(${incompleteCount()})` : ''}</h1> // [!code highlight]
        </div>
      </div>
    </header>

    // rest of markup
  </div>
);
```

:::

### 6.6: Make the Hide/Show toggle work

If you try the Hide/Show completed toggle button you'll see that the text changes but it doesn't actually do anything to the list of tasks. The toggle button isn't triggering the expected filtering because the `hideCompleted` signal (from Solid) isn't integrated with Meteor's Tracker reactivity system. Tracker.autorun only re-runs when its internal dependencies (like subscription data or ReactiveVars) change—not when Solid signals change. So, updating `hideCompleted` via `setHideCompleted` changes the button text (via Solid's `<Show>`), but it doesn't re-execute the autorun to update the query and re-fetch tasks.

This is a common challenge when bridging Solid's fine-grained reactivity with Meteor's Tracker. I'll explain the fix below with minimal changes to your code.

To make Tracker react to changes in `hideCompleted`, we'll use Meteor's `ReactiveVar`
to hold the filter state. This makes the value reactive within Tracker, so the autorun re-runs automatically when it changes. We'll sync it with your Solid signal for the UI.

Add this import at the top of `App.jsx`
::: code-group

```jsx [imports/ui/App.jsx]
import { ReactiveVar } from 'meteor/reactive-var';
```

:::

Initialize a ReactiveVar and use a Solid `createEffect` to keep it in sync with your `hideCompleted` signal. Update your `App` component like this:

Add this import at the top of `App.jsx`
::: code-group

```jsx [imports/ui/App.jsx]
...
import { createSignal, For, Show, createEffect } from "solid-js"; // Updated import
...

export const App = () => {
  const [newTask, setNewTask] = createSignal('');
  const [hideCompleted, setHideCompleted] = createSignal(false);

  // New: ReactiveVar for Tracker integration
  const hideCompletedVar = new ReactiveVar(false); // [!code highlight]

  // New: Sync Solid signal to ReactiveVar (triggers Tracker re-run) // [!code highlight]
  createEffect(() => { // [!code highlight]
    hideCompletedVar.set(hideCompleted()); // [!code highlight]
  }); // [!code highlight]

  const addTask = async (event) => {
    event.preventDefault();
    if (newTask().trim()) {
      await Meteor.callAsync("tasks.insert", {
        text: newTask(),
        createdAt: new Date(),
      });
      setNewTask('');
    }
  };

  const toggleHideCompleted = () => {
    setHideCompleted(!hideCompleted());
  };

  const subscription = Meteor.subscribe("tasks");
  const [isReady, setIsReady] = createSignal(subscription.ready());
  const [tasks, setTasks] = createSignal([]);

  Tracker.autorun(async () => {
    setIsReady(subscription.ready());
    // Use ReactiveVar in the query for Tracker reactivity // [!code highlight]
    const query = hideCompletedVar.get() ? { isChecked: { $ne: true } } : {}; // [!code highlight]
    setTasks(await TasksCollection.find(query, { sort: { createdAt: -1, _id: -1 } }).fetchAsync());
  });

  // Reactive incomplete count (unchanged)
  const [incompleteCount, setIncompleteCount] = createSignal(0);
  Tracker.autorun(async () => {
    setIncompleteCount(await TasksCollection.find({ isChecked: { $ne: true } }).countAsync());
  });

  // Return statement remains the same
  return (
    // ... your JSX here, unchanged
  );
};
```

:::

Why this works:

1. `ReactiveVar` bridges the systems: When you toggle `hideCompleted` (Solid signal), the `createEffect` updates the `ReactiveVar`. This invalidates and re-runs the Tracker.autorun, which re-fetches tasks with the updated query.
2. No major rewrites: Your existing signals and UI logic stay intact.
3. Performance: Tracker handles the re-fetch efficiently, and Solid updates the UI via the `tasks` signal.


Your app should look like this:

<img width="200px" src="/tutorials/solid/assets/step06-all.png"/>
<img width="200px" src="/tutorials/solid/assets/step06-filtered.png"/>

In the next step we are going to include user access in your app.
