---
title: "Angular Agenda Event Search Example | Mobiscroll"
component: "Agenda"
framework: "Angular"
library_version: "6.2.0"
url: "https://demo.mobiscroll.com/angular/agenda/searching-events-in-popup"
---

# Event Search - Angular Agenda demo

Add real-time event search to the Angular calendar header — type to filter events and show matching results in a popup agenda list.

- [Live demo](https://demo.mobiscroll.com/angular/agenda/searching-events-in-popup)
- [View code on GitHub](https://github.com/acidb/mobiscroll-demos-angular/tree/main/src/demos/eventcalendar/agenda/searching-events-in-popup)
- This demo in other frameworks: [JavaScript](https://demo.mobiscroll.com/javascript/agenda/searching-events-in-popup.md), [jQuery](https://demo.mobiscroll.com/jquery/agenda/searching-events-in-popup.md), [React](https://demo.mobiscroll.com/react/agenda/searching-events-in-popup.md), [Vue](https://demo.mobiscroll.com/vue/agenda/searching-events-in-popup.md)

## Description

Use the available real estate in the calendar header to add event search. With the [templating capabilities of the header](https://demo.mobiscroll.com/angular/agenda/customizing-calendar-header) you can easily add a search box and use a separate agenda instance to show the search results. This example is relying on a single API endpoint for getting the data onto the primary view and also for getting the filtered data based on the search terms.

[Events can be filtered in real time](https://demo.mobiscroll.com/angular/agenda/resource-filtering-in-header) so using an agenda view for the search results is an easy choice. It provides all the necessary styling and advanced features that you might need to customize the experience.

Alternatively, search can be implemented in a [sidebar next to the event calendar](https://demo.mobiscroll.com/angular/eventcalendar/searching-events-in-sidebar) using a similar search box with an inline agenda instead of a dropdown.

## What this demo shows

- Shows a monthly agenda view with events listed and grouped by date.
- **Header navigation** The month and year label in the top left opens date navigation. A centered search input and the previous and next arrows and the Today button on the right move between months and jump back to the current date.
- **Search input** The search field includes a search icon and the `Search events` placeholder text.
- **Search results popup** Typing into the search field opens a popup below the input with matching events in an agenda-style list.
- **Agenda results** Search results are grouped by date, and each event row shows a colored marker, the event title, and the event type, such as all-day or timed.
- **Result selection** Clicking an event in the agenda list closes the popup and navigates the month view to the date that contains the selected event.
- **Agenda list:** The area below the header lists events for the selected month. Events in the agenda are grouped by date.
- **Sticky day headers** As the agenda scrolls vertically, each day stays visible with a sticky date header while its events appear underneath.
- **Events:** Events appear as agenda cards with a colored strip on the left and the event title next to it. Start and end times are stacked on the right side of timed events. All-day events show the all-day label on the right.
- **Event interaction:** Hovering an event highlights it.
- **Event selection:** Clicking an event selects and highlights it.

## Best for

- **Search-heavy agendas** Interfaces where users need to quickly find events by person, keyword, event type, or absence period.
- **Admin and operations tools** Admin dashboards, employee scheduling tools, and internal planning interfaces where users review and search event-heavy agendas.
- **Enterprise planning** Multi-day planning scenarios where users need to move between agenda context and filtered event results without leaving the month view.

## API used in this demo

- [`theme`](https://mobiscroll.com/docs/angular/eventcalendar/api#opt-theme) - option
- [`themeVariant`](https://mobiscroll.com/docs/angular/eventcalendar/api#opt-themeVariant) - option
- [`display`](https://mobiscroll.com/docs/angular/popup/api#opt-display) - option
- [`focusOnClose`](https://mobiscroll.com/docs/angular/popup/api#opt-focusOnClose) - option
- [`maxHeight`](https://mobiscroll.com/docs/angular/popup/api#opt-maxHeight) - option
- [`scrollLock`](https://mobiscroll.com/docs/angular/popup/api#opt-scrollLock) - option
- [`showArrow`](https://mobiscroll.com/docs/angular/popup/api#opt-showArrow) - option
- [`showOverlay`](https://mobiscroll.com/docs/angular/popup/api#opt-showOverlay) - option
- [`width`](https://mobiscroll.com/docs/angular/popup/api#opt-width) - option
- [`navigateToEvent`](https://mobiscroll.com/docs/angular/eventcalendar/api#method-navigateToEvent) - method
- [`data`](https://mobiscroll.com/docs/angular/eventcalendar/api#opt-data) - option
- [`headerTemplate`](https://mobiscroll.com/docs/angular/eventcalendar/api#template-headerTemplate) - template
- [`selectedEvents`](https://mobiscroll.com/docs/angular/eventcalendar/api#opt-selectedEvents) - option
- [`selectMultipleEvents`](https://mobiscroll.com/docs/angular/eventcalendar/api#opt-selectMultipleEvents) - option
- [`view`](https://mobiscroll.com/docs/angular/eventcalendar/api#opt-view) - option
- [`onPageLoading`](https://mobiscroll.com/docs/angular/eventcalendar/api#event-onPageLoading) - event
- [`anchor`](https://mobiscroll.com/docs/angular/popup/api#opt-anchor) - option
- [`showControls`](https://mobiscroll.com/docs/angular/eventcalendar/api#opt-showControls) - option
- [`onEventClick`](https://mobiscroll.com/docs/angular/eventcalendar/api#event-onEventClick) - event

## Code

### Component

```ts
import { CommonModule } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { Component, ViewChild } from '@angular/core';
import {
  formatDate,
  MbscCalendarEvent,
  MbscEventcalendar,
  MbscEventcalendarView,
  MbscEventClickEvent,
  MbscInput,
  MbscModule,
  MbscPageLoadingEvent,
  MbscPopup,
  MbscPopupOptions,
  setOptions,
} from '@mobiscroll/angular';

setOptions({
  theme: 'ios',
  themeVariant: 'light'
});

@Component({
  selector: 'app-root', 
  templateUrl: './app.component.html',
  standalone: true,
  imports: [CommonModule, MbscModule],
})
export class AppComponent {
  constructor(private http: HttpClient) {}

  @ViewChild('searchInput', { static: false })
  set searchInputElm(elm: MbscInput) {
    setTimeout(() => {
      this.searchInput = elm.nativeElement;
    });
  }

  @ViewChild('calendar', { static: false })
  calendar!: MbscEventcalendar;

  @ViewChild('popup', { static: false })
  popup!: MbscPopup;

  calEvents: MbscCalendarEvent[] = [];
  calView: MbscEventcalendarView = { agenda: { type: 'month' } };
  listEvents: MbscCalendarEvent[] = [];
  listView: MbscEventcalendarView = { agenda: { type: 'year', size: 5 } };
  searchInput: HTMLElement | undefined;
  selectedEvent: MbscCalendarEvent[] = [];
  timer?: ReturnType<typeof setTimeout>;

  popupOptions: MbscPopupOptions = {
    contentPadding: false,
    display: 'anchored',
    focusOnClose: false,
    focusOnOpen: false,
    maxHeight: 500,
    scrollLock: false,
    showArrow: false,
    showOverlay: false,
    width: 400,
  };

  onInput(ev: Event): void {
    const searchText = (ev.target as HTMLInputElement).value;

    clearTimeout(this.timer);
    this.timer = setTimeout(() => {
      if (searchText.length > 0) {
        this.http
          .jsonp<MbscCalendarEvent[]>('https://trial.mobiscroll.com/searchevents/?text=' + searchText, 'callback')
          .subscribe((resp) => {
            this.listEvents = resp;
            this.popup.open();
          });
      } else {
        this.popup.close();
      }
    }, 200);
  }

  onFocus(ev: Event): void {
    if ((ev.target as HTMLInputElement).value.length > 0) {
      this.popup.open();
    }
  }

  onPageLoading(args: MbscPageLoadingEvent): void {
    const start = formatDate('YYYY-MM-DD', args.viewStart);
    const end = formatDate('YYYY-MM-DD', args.viewEnd);

    this.http
      .jsonp<MbscCalendarEvent[]>('https://trial.mobiscroll.com/searchevents/?start=' + start + '&end=' + end, 'callback')
      .subscribe((resp) => {
        this.calEvents = resp;
      });
  }

  onEventClick(args: MbscEventClickEvent): void {
    this.calendar.navigateToEvent(args.event);
    this.selectedEvent = [args.event];
    this.popup.close();
  }
}
```

### Template

```html
<mbsc-eventcalendar
  #calendar
  [data]="calEvents"
  [headerTemplate]="customHeader"
  [(selectedEvents)]="selectedEvent"
  [selectMultipleEvents]="true"
  [view]="calView"
  (onPageLoading)="onPageLoading($event)"
>
  <ng-template #customHeader>
    <mbsc-calendar-nav></mbsc-calendar-nav>
    <div class="mds-search-bar mbsc-flex-1-0">
      <mbsc-input
        #searchInput
        autocomplete="off"
        inputStyle="box"
        placeholder="Search events"
        startIcon="material-search"
        (input)="onInput($event)"
        (focusin)="onFocus($event)"
      ></mbsc-input>
    </div>
    <mbsc-calendar-prev></mbsc-calendar-prev>
    <mbsc-calendar-today></mbsc-calendar-today>
    <mbsc-calendar-next></mbsc-calendar-next>
  </ng-template>
</mbsc-eventcalendar>
<mbsc-popup #popup [anchor]="searchInput" [focusElm]="searchInput" [options]="popupOptions">
  <mbsc-eventcalendar
    class="mds-search-results"
    [data]="listEvents"
    [showControls]="false"
    [view]="listView"
    (onEventClick)="onEventClick($event)"
  ></mbsc-eventcalendar>
</mbsc-popup>
```

### CSS

```css
.mds-search-bar .mbsc-textfield-wrapper {
  max-width: 400px;
  margin: 8px auto;
}

.mds-search-bar .mbsc-textfield.mbsc-ios-dark {
  background: #313131;
}

.mds-search-results .mbsc-calendar-wrapper {
  margin-top: -1px;
}
```

## Implementation notes

- Use two Eventcalendar instances. The main calendar uses `view: { agenda: { type: 'month' } }` with `selectMultipleEvents: true`. The results list uses `view: { agenda: { type: 'year', size: 5 } }` with `showControls: false` - this renders as a flat scrollable event list with no calendar chrome.
- Load main calendar events on `onPageLoading`: use `formatDate('YYYY-MM-DD', args.viewStart)` and `formatDate('YYYY-MM-DD', args.viewEnd)` to build the URL, then JSONP from `https://trial.mobiscroll.com/searchevents/?start={start}&end={end}`. Angular: use `HttpClient.jsonp()`. For the imperative API, call `inst.setEvents()` in the callback.
- Build a custom header via `renderHeader` (Angular: `headerTemplate`, Vue: `header` slot) with `CalendarNav` on the left, a Mobiscroll `Input` (`autoComplete: 'off'`, `inputStyle: 'box'`, `startIcon: 'material-search'`, `placeholder: 'Search events'`) in the center (`mbsc-flex-1-0`), and `CalendarPrev`/`CalendarToday`/`CalendarNext` on the right.
- On input change: debounce 200ms. If the text is non-empty, JSONP `https://trial.mobiscroll.com/searchevents/?text={searchText}`, load results into the results Eventcalendar, and open the Popup. If empty, close the Popup. On input focus: if the current value is non-empty, reopen the Popup.
- Wrap the results Eventcalendar in a `Popup` anchored to the search input element: `display: 'anchored'`, `focusElm` = the input's native element, `focusOnOpen: false`, `focusOnClose: false`, `contentPadding: false`, `scrollLock: false`, `showArrow: false`, `showOverlay: false`, `width: 400`.
- On event click in the results list: call `inst.navigateToEvent(args.event)` on the main calendar to scroll it into view, set `selectedEvents: [args.event]` to highlight it, and close the Popup. Angular: use `@ViewChild` to get both the main calendar instance and the popup instance (`popup.open()` / `popup.close()`).

## Run it in your project

1. If not signed up yet, or don't own a license, you can [start a free trial](https://mobiscroll.com/starttrial).

2. Clone the repository:

   ```
   git clone https://github.com/acidb/mobiscroll-demos-angular.git
   ```

3. If not installed yet, install the Mobiscroll CLI from NPM:

   ```
   npm install -g @mobiscroll/cli
   ```

4. Config Mobiscroll - open a terminal window in the root directory and run:

   ```
   mobiscroll config angular
   ```

5. Install dependencies - open a terminal window in the root directory and run:

   ```
   npm install
   ```

6. Run the project:

   ```
   ng serve
   ```

On a trial, add `--trial` to the config command: `mobiscroll config angular --trial`.

Running a demo locally requires a Mobiscroll trial or a license; setup is per framework at https://mobiscroll.com/docs/angular/getting-started/installation

## Related demos

- Previous: [Multi-Timezone Display](https://demo.mobiscroll.com/angular/agenda/setting-the-timezone.md) - Show Angular Agenda events in any timezone — set data and display timezones, then let users switch with a timezone picker.
- Next: [External Date Navigation](https://demo.mobiscroll.com/angular/agenda/navigate-from-external-calendar.md) - Use a two-pane layout with a date picker and a Angular agenda view — selecting a date in the picker, sync the agenda.
