# How to Enable or Disable a Data Layer Using DataLayerManager in God’s Eye View

> Learn to enable or disable data layers in God's Eye View using DataLayerManager. Control layer visibility programmatically or with user-driven toggles for efficient data management.

- Repository: [Bilawal Sidhu/gods-eye-view](https://github.com/bilawalsidhu/gods-eye-view)
- Tags: how-to-guide
- Published: 2026-09-09

---

**Use `DataLayerManager.setEnabled(layerId, true|false)` for explicit programmatic control or `DataLayerManager.toggle(layerId)` for user-driven state inversion, both of which serialize requests through per-layer toggle chains and broadcast visibility events.**

The **DataLayerManager** class in `bilawalsidhu/gods-eye-view` serves as the central orchestrator for real-time geospatial overlays. Located in [`src/data/manager.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/data/manager.js), it registers layer modules and manages their complete lifecycle—from initialization through activation, periodic updates, and teardown. Every data layer conforms to a standard interface exposing `init`, `enable`, `disable`, `update`, and `getStats` methods, allowing the manager to treat heterogeneous data sources uniformly.

## Understanding the DataLayerManager Architecture

When you instantiate `DataLayerManager` with a Cesium viewer reference, it creates isolated **toggle chains** for each registered layer. These Promise chains ensure that concurrent visibility requests never interleave, preventing race conditions during asynchronous initialization. The manager tracks internal state through properties like `enabled`, `lifecycleState`, and `visibilityIntentEpoch`, emitting granular events that upstream UI components consume to reflect current layer status.

## Programmatic Control with `setEnabled()`

For deterministic on/off behavior, invoke `setEnabled()` with the target layer ID and boolean flag. This method triggers the private `_setEnabledWithIntent()` routine, which increments a visibility intent epoch to supersede stale requests and queues the operation on the layer’s dedicated `toggleChain`.

```javascript
import { DataLayerManager } from './src/data/manager.js';
import cctvLayer from './src/data/cctv.js';

const dataMgr = new DataLayerManager(viewer);
dataMgr.register(cctvLayer);

// Explicitly enable the CCTV layer
await dataMgr.setEnabled('cctv', true, {
  origin: 'programmatic',      // 'user', 'voice', or 'tool'
  signal: abortController.signal,  // Optional AbortSignal
  notificationToken: 'ui-btn-01'   // Optional correlation token
});

```

The `origin` parameter proves critical for audit trails and analytics, distinguishing between automated scripts, user clicks, and voice commands. Supplying an `AbortSignal` allows cancellation mid-flight; if aborted during enablement, the manager automatically invokes the layer’s `disable` method to ensure clean resource cleanup. See the implementation details in [`src/data/manager.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/data/manager.js) lines 558-568.

## User-Driven Toggling with `toggle()`

When building UI buttons that simply flip the current state, use `toggle()` rather than manually checking `isEffectivelyEnabled()`. This convenience method inverts the effective visibility and forwards the request to `_setEnabledWithIntent()` with `notifyWillChangeBeforeEffective: true`, guaranteeing that `visibility-will-change` events fire before state mutation.

```javascript
document.getElementById('cctv-toggle-btn').addEventListener('click', async () => {
  // Automatically switches between enabled/disabled based on current state
  const success = await dataMgr.toggle('cctv', { 
    origin: 'user',
    notificationToken: 'toggle-btn-click' 
  });
  console.log('Toggle resolved:', success);
});

```

Because `toggle()` relies on the same internal pipeline as `setEnabled()`, it inherits identical serialization guarantees and abort handling without requiring boilerplate state inspection code.

## Listening to Visibility Lifecycle Events

Both `setEnabled()` and `toggle()` broadcast rich event payloads that you can subscribe to for UI synchronization or logging. The subscription callback receives objects containing `type`, `layerId`, `enabled`, and `origin` fields.

```javascript
dataMgr.subscribe(change => {
  if (change.layerId === 'cctv') {
    switch (change.type) {
      case 'visibility-will-change':
        console.log('About to toggle CCTV...');
        break;
      case 'visibility':
        console.log(`CCTV is now ${change.enabled ? 'ON' : 'OFF'}`);
        break;
      case 'visibility-failed':
        console.error('CCTV toggle failed:', change.error);
        break;
    }
  }
});

```

These events enable robust UI patterns such as loading spinners during initialization, error toasts on failure, and optimistic toggle states that revert if the lifecycle encounters an exception.

## Summary

- **Use `setEnabled()`** when you need explicit control over the target state (on vs. off) and want to specify provenance through the `origin` parameter.
- **Use `toggle()`** for binary switch UI elements; it automatically queries current effective state and flips it while emitting pre-change notifications.
- **Both methods serialize** requests per-layer through internal `toggleChain` queues, preventing race conditions during concurrent operations.
- **Pass an `AbortSignal`** to either method to cancel pending operations gracefully; the manager handles partially completed lifecycles by invoking `disable` cleanup routines.
- **Subscribe to visibility events** to keep UI components synchronized without polling internal state.

## Frequently Asked Questions

### What is the difference between `setEnabled()` and `toggle()` in DataLayerManager?

`setEnabled()` requires you to specify the desired end state explicitly (`true` or `false`), making it ideal for programmatic workflows like voice commands or automated scene transitions. `toggle()` inspects the current effective state via `isEffectivelyEnabled()` and inverts it, making it perfect for simple UI buttons that just need to flip a layer on or off without knowing the current status.

### How does DataLayerManager handle concurrent enable or disable requests?

Each registered layer maintains a private `toggleChain` Promise sequence. When you call `setEnabled()` or `toggle()`, the manager appends the operation to this chain via `_setEnabledWithIntent()`. This architecture ensures that even if a user rapidly clicks a toggle button while a previous initialization is still pending, requests execute serially rather than interleaving, preventing duplicate resources or partial initialization states.

### Can I cancel a layer enable operation after calling `setEnabled()`?

Yes. Pass an `AbortSignal` through the options object when invoking `setEnabled()`. If the signal aborts before the lifecycle completes, the manager catches the cancellation and automatically executes the layer’s `disable` method to release any partially allocated resources. The system emits a `visibility-cancelled` event that you can observe to update UI indicators.

### Where is the DataLayerManager instantiated in the God’s Eye View application?

The manager is instantiated in [`src/main.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/main.js) during application bootstrap, receiving the Cesium viewer instance as a constructor argument. From there, it is injected into subsystems including voice command handlers ([`src/voice/gevActions.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/voice/gevActions.js)) and UI controls ([`src/ui.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/ui.js)), which demonstrate real-world usage patterns for enabling and disabling data layers programmatically and interactively.