---
title: "Vue Timeline Load Resources on Demand Example | Mobiscroll"
component: "Timeline"
framework: "Vue"
library_version: "6.1.5"
url: "https://demo.mobiscroll.com/vue/timeline/load-resources-on-demand"
---

# Load Resources on Demand - Vue Timeline demo

Build hierarchical resource scheduling interfaces with on-demand data loading — the Vue Timeline fetches child resources. For Vue and Nuxt.

- [Live demo](https://demo.mobiscroll.com/vue/timeline/load-resources-on-demand)
- [View SFC JS code on GitHub](https://github.com/acidb/mobiscroll-demos-vue/tree/main/src/demos/eventcalendar/timeline/load-resources-on-demand)
- [View SFC TS code on GitHub](https://github.com/acidb/mobiscroll-demos-vue-ts/tree/main/src/demos/eventcalendar/timeline/load-resources-on-demand)
- This demo in other frameworks: [JavaScript](https://demo.mobiscroll.com/javascript/timeline/load-resources-on-demand.md), [jQuery](https://demo.mobiscroll.com/jquery/timeline/load-resources-on-demand.md), [Angular](https://demo.mobiscroll.com/angular/timeline/load-resources-on-demand.md), [React](https://demo.mobiscroll.com/react/timeline/load-resources-on-demand.md)

## Description

The resources can be populated on initialization or in case of a bigger hierarchy, the more efficient way is to load the child resources and their events on demand.

Getting the resources and the events in real time as the user navigates improves load performance.

Use the [`resource-expand`](https://mobiscroll.com/docs/vue/eventcalendar/api#event-onResourceExpand) lifecycle event to load the data runtime. You can [learn about lifecycle events](https://demo.mobiscroll.com/vue/timeline/event-hooks) and places where to drop logic to customize the experience.

## What this demo shows

- A desktop timeline with hours arranged horizontally and a hierarchical resource tree arranged vertically on the left.
- **Loading resources on demand** Expanding a resource group loads its child resources and events at runtime instead of loading the full hierarchy on initialization.
- **Loading feedback** A `Resources loaded` toast appears at the bottom center of the timeline after child resources are loaded.
- **Header navigation** The month and year label opens date navigation, the previous and next arrows move between days, and the Today button returns to the current date.
- **Day view** The strip below the header shows the selected days, with the current date highlighted.
- **Timeline grid** The timeline displays hourly columns from 12 AM to 12 PM.
- **Resources** The left side shows expandable and collapsible resource groups, including parent groups.
- **Resource hierarchy** Nested resources are grouped under parent rows, such as Group 1 and Group 2, before listing individual resources.
- **Current time** A vertical blue line with a time label marks the current time.
- **Hover behavior** Hovering over the time grid shows a time indicator that follows the cursor in 15-minute increments.
- **Event cards** Events appear as colored cards with a colored stripe on the left, the event title in bold, and the exact start and end time displayed below the title.
- **Date positioning** Events are positioned by their assigned resource and exact date range.
- **Event interaction** Events highlight on hover and show drag and resize handles for repositioning or changing duration.
- **Event selection** Clicking an event selects and highlights it.
- **Event creation** New events can be created by double-clicking the timeline or by clicking and dragging across a time range.
- **Scrolling** The timeline supports horizontal and vertical scrolling for navigating through time and resources.

## Best for

- **Large resource hierarchies** Scheduling interfaces where loading every resource and event at startup would slow down the initial view.
- **Expandable team structures** Workforce planning tools with departments, teams, and individual staff members grouped under parent rows.
- **Facility and room scheduling** Calendars where buildings, floors, rooms, or equipment groups only need to load when the user expands them.
- **Field service planning** Dispatch boards with regional groups, crews, vehicles, or technicians that can be loaded as the planner navigates.
- **Asset and equipment booking** Resource timelines with many machines, vehicles, devices, or shared assets organized into nested groups.
- **Enterprise scheduling systems** Applications that need to keep the first load fast while still supporting deeper resource trees and event data.

## API used in this demo

- [`theme`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-theme) - option
- [`themeVariant`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-themeVariant) - option
- [`clickToCreate`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-clickToCreate) - option
- [`dragToCreate`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-dragToCreate) - option
- [`dragToMove`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-dragToMove) - option
- [`dragToResize`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-dragToResize) - option
- [`eventDelete`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-eventDelete) - option
- [`view`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-view) - option
- [`data`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-data) - option
- [`resources`](https://mobiscroll.com/docs/vue/eventcalendar/api#opt-resources) - option
- [`resource-expand`](https://mobiscroll.com/docs/vue/eventcalendar/api#event-onResourceExpand) - event
- [`close`](https://mobiscroll.com/docs/vue/notifications/toast#event-onClose) - event

## Code

### SFC JS

```vue
<script setup>
import {
  getJson,
  MbscEventcalendar,
  MbscToast,
  setOptions
} from '@mobiscroll/vue'
import { ref } from 'vue'

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

const toastMessage = ref('')
const isToastOpen = ref(false)

const myEvents = ref([
  {
    start: '2026-10-25T10:00',
    end: '2026-10-25T13:00',
    title: 'Event 14',
    resource: 6
  },
  {
    start: '2026-10-25T15:00',
    end: '2026-10-25T17:30',
    title: 'Event 15',
    resource: 7
  },
  {
    start: '2026-10-25T09:00',
    end: '2026-10-25T11:00',
    title: 'Event 16',
    resource: 8
  },
  {
    start: '2026-10-25T17:00',
    end: '2026-10-25T20:00',
    title: 'Event 17',
    resource: 9
  }
])

const myResources = ref([
  {
    id: 1,
    name: 'Group 1',
    collapsed: true,
    eventCreation: false,
    children: [
      {
        id: 11,
        color: '#e20000',
        name: 'Resource 1'
      },
      {
        id: 12,
        color: '#76e083',
        name: 'Resource 2'
      },
      {
        id: 13,
        color: '#4981d6',
        name: 'Resource 3'
      }
    ]
  },
  {
    id: 2,
    name: 'Group 2',
    collapsed: true,
    eventCreation: false,
    children: [
      {
        id: 21,
        name: 'Loading...'
      }
    ]
  },
  {
    id: 3,
    name: 'Group 3',
    collapsed: true,
    eventCreation: false,
    children: [
      {
        id: 31,
        name: 'Loading...'
      }
    ]
  },
  {
    id: 4,
    name: 'Group 4',
    collapsed: true,
    eventCreation: false,
    children: [
      {
        id: 41,
        name: 'Loading...'
      }
    ]
  },
  {
    id: 5,
    name: 'Group 5',
    collapsed: true,
    eventCreation: false,
    children: [
      {
        id: 51,
        color: '#af0000',
        name: 'Resource 12'
      },
      {
        id: 52,
        color: '#446f1c',
        name: 'Resource 13'
      },
      {
        id: 53,
        color: '#1dab2f',
        name: 'Resource 14'
      }
    ]
  },
  {
    id: 6,
    name: 'Resource 17',
    color: '#167593'
  },
  {
    id: 7,
    name: 'Resource 18',
    color: '#93166c'
  },
  {
    id: 8,
    name: 'Resource 19',
    color: '#e5e923'
  },
  {
    id: 9,
    name: 'Resource 20',
    color: '#935028'
  }
])

const myView = {
  timeline: {
    type: 'day'
  }
}

function loadChildResources(args) {
  const resource = args.resourceObj

  if (!resource.loaded) {
    getJson(
      'https://trial.mobiscroll.com/load-resources/?res=' + args.resource,
      (data) => {
        const newEvents = [...myEvents.value, ...data.events]

        resource.children = data.resources
        resource.loaded = true

        myEvents.value = newEvents
        myResources.value = [...myResources.value]

        toastMessage.value = 'Resources loaded'
        isToastOpen.value = true
      },
      'jsonp'
    )
  }
}

function handleToastClose() {
  isToastOpen.value = false
}
</script>

<template>
  <MbscEventcalendar :clickToCreate="true" :dragToCreate="true" :dragToMove="true" :dragToResize="true" :eventDelete="true"
    className="md-load-resources-on-demand"
    :view="myView"
    :data="myEvents"
    :resources="myResources"
    @resource-expand="loadChildResources"
  />
  <MbscToast :message="toastMessage" :isOpen="isToastOpen" @close="handleToastClose" />
</template>

<style>
.md-load-resources-on-demand .mbsc-timeline-parent {
  height: 34px;
}
</style>
```

### SFC TS

```vue
<script setup lang="ts">
import {
  getJson,
  MbscEventcalendar,
  MbscToast,
  setOptions
} from '@mobiscroll/vue'
import type { MbscCalendarEvent, MbscEventcalendarView, MbscResource } from '@mobiscroll/vue'
import { ref } from 'vue'

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

const toastMessage = ref<string>('')
const isToastOpen = ref<boolean>(false)

const myEvents = ref<MbscCalendarEvent[]>([
  {
    start: '2026-10-25T10:00',
    end: '2026-10-25T13:00',
    title: 'Event 14',
    resource: 6
  },
  {
    start: '2026-10-25T15:00',
    end: '2026-10-25T17:30',
    title: 'Event 15',
    resource: 7
  },
  {
    start: '2026-10-25T09:00',
    end: '2026-10-25T11:00',
    title: 'Event 16',
    resource: 8
  },
  {
    start: '2026-10-25T17:00',
    end: '2026-10-25T20:00',
    title: 'Event 17',
    resource: 9
  }
])

const myResources = ref<MbscResource[]>([
  {
    id: 1,
    name: 'Group 1',
    collapsed: true,
    eventCreation: false,
    children: [
      {
        id: 11,
        color: '#e20000',
        name: 'Resource 1'
      },
      {
        id: 12,
        color: '#76e083',
        name: 'Resource 2'
      },
      {
        id: 13,
        color: '#4981d6',
        name: 'Resource 3'
      }
    ]
  },
  {
    id: 2,
    name: 'Group 2',
    collapsed: true,
    eventCreation: false,
    children: [
      {
        id: 21,
        name: 'Loading...'
      }
    ]
  },
  {
    id: 3,
    name: 'Group 3',
    collapsed: true,
    eventCreation: false,
    children: [
      {
        id: 31,
        name: 'Loading...'
      }
    ]
  },
  {
    id: 4,
    name: 'Group 4',
    collapsed: true,
    eventCreation: false,
    children: [
      {
        id: 41,
        name: 'Loading...'
      }
    ]
  },
  {
    id: 5,
    name: 'Group 5',
    collapsed: true,
    eventCreation: false,
    children: [
      {
        id: 51,
        color: '#af0000',
        name: 'Resource 12'
      },
      {
        id: 52,
        color: '#446f1c',
        name: 'Resource 13'
      },
      {
        id: 53,
        color: '#1dab2f',
        name: 'Resource 14'
      }
    ]
  },
  {
    id: 6,
    name: 'Resource 17',
    color: '#167593'
  },
  {
    id: 7,
    name: 'Resource 18',
    color: '#93166c'
  },
  {
    id: 8,
    name: 'Resource 19',
    color: '#e5e923'
  },
  {
    id: 9,
    name: 'Resource 20',
    color: '#935028'
  }
])

const myView: MbscEventcalendarView = {
  timeline: {
    type: 'day'
  }
}

function loadChildResources(args: any) {
  const resource = args.resourceObj!

  if (resource && !resource.loaded) {
    getJson(
      'https://trial.mobiscroll.com/load-resources/?res=' + args.resource,
      (data: any) => {
        const newEvents = [...myEvents.value, ...data.events]

        resource.children = data.resources
        resource.loaded = true

        myEvents.value = newEvents
        myResources.value = [...myResources.value]

        toastMessage.value = 'Resources loaded'
        isToastOpen.value = true
      },
      'jsonp'
    )
  }
}

function handleToastClose() {
  isToastOpen.value = false
}
</script>

<template>
  <MbscEventcalendar :clickToCreate="true" :dragToCreate="true" :dragToMove="true" :dragToResize="true" :eventDelete="true"
    className="md-load-resources-on-demand"
    :view="myView"
    :data="myEvents"
    :resources="myResources"
    @resource-expand="loadChildResources"
  />
  <MbscToast :message="toastMessage" :isOpen="isToastOpen" @close="handleToastClose" />
</template>

<style>
.md-load-resources-on-demand .mbsc-timeline-parent {
  height: 34px;
}
</style>
```

## Implementation notes

- Use `timeline: { type: 'day' }` - a single-day view. Apply CSS class `md-load-resources-on-demand` to the calendar and add `.md-load-resources-on-demand .mbsc-timeline-parent { height: 34px }` to keep group header rows compact.
- **Initial resource tree** (9 top-level entries):
  - **Group 1** (id 1) - `collapsed: true`, `eventCreation: false`, 3 real children pre-loaded: Resource 1 (`#e20000`), Resource 2 (`#76e083`), Resource 3 (`#4981d6`)
  - **Group 2** (id 2) - `collapsed: true`, `eventCreation: false`, one placeholder child: `{ id: 21, name: 'Loading...' }`
  - **Group 3** (id 3) - same placeholder pattern: `{ id: 31, name: 'Loading...' }`
  - **Group 4** (id 4) - same placeholder pattern: `{ id: 41, name: 'Loading...' }`
  - **Group 5** (id 5) - `collapsed: true`, `eventCreation: false`, 3 real children pre-loaded: Resource 12 (`#af0000`), Resource 13 (`#446f1c`), Resource 14 (`#1dab2f`)
  - Four standalone leaf resources: Resource 17 (id 6, `#167593`), Resource 18 (id 7, `#93166c`), Resource 19 (id 8, `#e5e923`), Resource 20 (id 9, `#935028`)
  - Placeholder children (`Loading...`) are needed so the group shows an expand arrow before real children arrive.
- Include 4 initial timed events today spread across the 4 standalone leaf resources.
- **`onResourceExpand` handler** (`loadChildResources`):
  1. Get `args.resourceObj` - the expanded group's resource object.
  2. Guard with `if (!resource.loaded)` to prevent re-fetching an already-expanded group.
  3. Fetch `https://trial.mobiscroll.com/load-resources/?res={args.resource}` (JSONP, where `args.resource` is the group's id).
  4. On response: mutate `resource.children = data.resources` and `resource.loaded = true`, then merge `data.events` into the existing events array.
  5. Update both events and resources state with the merged arrays (spread to signal change), and show a Toast `"Resources loaded"`; for the imperative API, call `inst.setOptions({ data: newEvents, resources: newResources })`.

## 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-vue.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 vue
   ```

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

   ```
   npm install
   ```

6. Run the project:

   ```
   npm run dev
   ```

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

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

## Related demos

- Previous: [Virtual Scrolling](https://demo.mobiscroll.com/vue/timeline/load-events-on-scroll.md) - Load events on scroll with a virtualized Vue Timeline — only the visible date range is fetched, keeping large resource timelines responsive.
- Next: [Load Resources on Scroll](https://demo.mobiscroll.com/vue/timeline/load-resources-on-scroll.md) - Build responsive large-resource scheduling timelines with the Vue Timeline — use virtual scrolling to load only visible resource rows on demand.
