Advanced directives: workers, WASM, channels, viewport

AngularTS advanced directives for Web Workers, WebAssembly, lazy loading, event channels, DOM references, and accessibility — all declarative in HTML.

AngularTS ships several advanced directives that expose modern browser APIs — Web Workers, WebAssembly, Intersection Observer, and custom event channels — directly in HTML without requiring JavaScript. These directives are registered as part of the core ng module and are available in every AngularTS application.

Controller and scope directives

ng-controller

Attaches a controller function to a section of the DOM, creating a new child scope populated by the controller.

  <p>{{ ctrl.title }}</p>
</div>
  .controller('TodoController', function($scope) {
    $scope.title = 'My Todos';
  });

ng-scope

Marks an explicit scope boundary. Useful for isolating a section of the page without a controller.

  <p>Hello {{ user.name }}</p>
</div>

ng-init

Initializes scope variables inline in the template. Best suited for simple one-off values or prototyping.

  Hello {{ name }}, count is {{ count }}
</div>

Tip: Prefer controllers or services over ng-init for any real application logic. ng-init is ideal for zero-JS demos and quick prototypes.

DOM reference directives

ng-el

Use ng-el when you only need the native DOM element. It is the simple DOM reference API and is usually the clearest choice for canvas, focus management, layout measurement, and pointer-driven UI.

<section ng-controller="BoardController as $ctrl">
  <canvas ng-el="$ctrl.boardEl"></canvas>
</section>
function BoardController() {
  this.boardEl = null;
}

ng-el="$ctrl.boardEl" stores the element on the controller. Use this form with controller-as syntax.

For simple scope shorthand, pass a bare name:

<canvas ng-el="boardEl"></canvas>

If the value is omitted, AngularTS uses the element id.

<canvas id="board" ng-el></canvas>

ng-ref

Use ng-ref when you need a component or directive controller reference, or when you need to assign the reference to a full expression such as $ctrl.child.

<search-box ng-ref="$ctrl.search"></search-box>
<button ng-click="$ctrl.search.clear()">Clear</button>

By default, ng-ref reads the component or element-directive controller when one exists, and falls back to the DOM element.

ng-ref-read is not a standalone directive. It only changes what ng-ref assigns.

<canvas ng-ref="$ctrl.boardEl" ng-ref-read="$element"></canvas>
<my-widget ng-ref="$ctrl.resizeHandle" ng-ref-read="resizeHandle"></my-widget>

Use ng-ref-read="$element" only when you specifically need the DOM element through an assignable expression. For the common DOM-only case, prefer ng-el.

function BoardController() {
  this.boardEl = null;
}

Event and communication directives

ng-channel

Subscribes to a named event channel (backed by $eventBus). When an event is published on the channel, the expression is evaluated.

  Latest: {{ lastNotification }}
</div>

ng-listener

Attaches a DOM event listener to the element using the native addEventListener API — without the overhead of Angular’s event directive wiring.

  Scroll-tracked content
</div>

ng-inject

Injects a named service directly into the scope, making it accessible in the template without a controller.

  <!-- $http is now available in this scope -->
</div>

Lazy loading and performance

ng-viewport

Uses the browser’s Intersection Observer API to defer content rendering until the element enters the viewport. Ideal for below-the-fold content.

  <!-- loadComments() is called once when this enters the viewport -->
  <div ng-repeat="comment in comments">{{ comment.text }}</div>
</div>

ng-viewport

  • Type: expression

Expression to evaluate when the element enters the viewport. Called once and not repeated.

ng-cloak

Prevents the browser from briefly displaying uncompiled template syntax ({{ }}) before AngularTS bootstraps. Add to the root element or any element with interpolation.


<div ng-cloak>
  <p>Hello {{ user.name }}</p>
</div>

Note: Always include the CSS rule [ng-cloak] { display: none; } in your stylesheet when using ng-cloak.

Web Workers and WebAssembly

ng-worker

Runs a JavaScript file in a Web Worker and binds the result back to scope. The worker communicates via postMessage.

     data-params="{ items: largeList }"
     data-on-result="sortedItems = $result">
  <div ng-repeat="item in sortedItems">{{ item.name }}</div>
</div>

ng-worker

  • Type: string
  • Required: yes

Path to the Web Worker JavaScript file.

data-params

  • Type: expression

Data to pass to the worker as the message payload.

data-on-result

  • Type: expression

Expression evaluated when the worker posts a result. $result contains the worker’s response.

interval

  • Type: number

Re-send the params to the worker on a millisecond interval.

throttle

  • Type: number

Throttle worker invocations to at most once per N milliseconds.

The worker file uses standard onmessage / postMessage:

  var sorted = e.data.items.slice().sort((a, b) => a.name.localeCompare(b.name));
  postMessage(sorted);
};

ng-wasm

Loads a WebAssembly module and makes its exports available on scope.

  <p>Result: {{ math.add(3, 4) }}</p>
</div>

ng-wasm

  • Type: string
  • Required: yes

Path to the .wasm file to load.

as

  • Type: string

Scope property name to assign the WASM exports object to. Defaults to wasm.

Transclusion

ng-transclude

Used inside custom directive templates to mark where transcluded content should be inserted.

  return {
    transclude: true,
    template: '<div class="panel"><ng-transclude></ng-transclude></div>'
  };
});
  <p>This content is transcluded into the panel.</p>
</my-panel>

Non-bindable sections

ng-non-bindable

Prevents AngularTS from compiling or interpolating a subtree. Use this for displaying raw Angular syntax as documentation or code examples.

  {{ this will not be interpolated }}
  ng-repeat="item in items"
</pre>

Aria directives

AngularTS automatically manages ARIA attributes for accessibility. These directives are applied alongside their functional counterparts:

DirectiveARIA attribute managed
ng-disabledaria-disabled
ng-checkedaria-checked
ng-readonlyaria-readonly
ng-requiredaria-required
ng-show / ng-hidearia-hidden
ng-modelaria-value*, role

The $aria service and $ariaProvider let you configure which ARIA attributes are automatically managed:

  $ariaProvider.config({
    ariaDisabled: true,
    ariaChecked: true,
    ariaReadonly: true,
    ariaRequired: true,
    ariaHidden: true,
    ariaValue: true,
    tabindex: true
  });
});

Event directives

AngularTS generates event directives for all common DOM events. They all follow the ng-<eventname>="expression" pattern:

DirectiveDOM event
ng-clickclick
ng-dblclickdblclick
ng-focusfocus
ng-blurblur
ng-keydownkeydown
ng-keyupkeyup
ng-keypresskeypress
ng-mouseentermouseenter
ng-mouseleavemouseleave
ng-mousemovemousemove
ng-mouseovermouseover
ng-mousedownmousedown
ng-mouseupmouseup
ng-submitsubmit (on forms)
ng-cutcut
ng-copycopy
ng-pastepaste
ng-loadload
ng-oncustom event name

The expression is evaluated in the current scope. $event refers to the native DOM event object:

<input ng-keydown="$event.key === 'Enter' && submit()">

Event policy can be declared once on the same element and applies to every ng-on-* or generated event directive on that element:

<div
  ng-on-pointerdown="$ctrl.startDrag($event)"
  data-event-prevent
  data-event-capture>
</div>

Supported policy attributes:

AttributeBehavior
data-event-preventCalls $event.preventDefault() first
data-event-stopCalls $event.stopPropagation() first
data-event-captureRegisters the listener with capture: true
data-event-onceRegisters the listener with once: true
data-event-passiveRegisters the listener with passive: true

data-event-passive cannot be combined with data-event-prevent, because passive listeners cannot cancel default browser behavior.

ng-pointer-capture can be combined with ng-on-pointer* handlers for game and board interactions that need reliable pointer streams:

<div
  ng-pointer-capture
  ng-on-pointerdown="$ctrl.startDrag($event)"
  ng-on-pointermove="$ctrl.drag($event)"
  ng-on-pointerup="$ctrl.drop($event)"
  data-event-prevent>
</div>