HTTP Directives: ng-get, ng-post, ng-put, ng-sse
AngularTS ships a family of declarative HTTP directives inspired by HTMX. Rather than wiring up $http calls in a controller, you attach ng-get, ng-post, ng-put, ng-delete, or ng-sse directly to HTML elements. The directives handle the request lifecycle, DOM insertion, loading states, error handling, and scope merging — all configured through HTML attributes.
How they differ from $http
When you use $http directly you write controller code: define the request, subscribe to the promise, update scope properties, handle errors, and trigger a digest. The HTTP directives do all of this declaratively:
<button ng-click="loadUser()">Load user</button>
<p>{{ user.name }}</p>
$http.get('/api/user/1').then(function(res) {
$scope.user = res.data;
});
};
<button ng-get="/api/user/1">Load user</button>
<p>{{ name }}</p>
When the server returns JSON, the directive merges it into scope automatically. When it returns HTML, the result is compiled and injected into the DOM using the configured swap strategy.
ng-get
ng-get fires a GET request when the configured event occurs (default: click for buttons, change for inputs, submit for forms).
<button ng-get="/api/weather?city=London">
Get weather
</button>
{{ temperature }}°C — {{ description }}
<button ng-get="/partials/user-card.html"
swap="outerHTML"
target="#user-area">
Show profile
</button>
<div id="user-area"></div>
Automatic trigger
Use trigger="load" to fire the request immediately when the element is linked (no user interaction required):
<div ng-get="/api/dashboard/stats" trigger="load">
<span ng-bind="stats.users"></span> users
</div>
Polling with interval
<div ng-get="/api/live-count"
trigger="load"
interval="5000">
{{ count }} online
</div>
ng-post
ng-post fires a POST request. On <form> elements, the default trigger is submit and the form data is collected via FormData. On buttons and other elements, the trigger defaults to click.
<form ng-post="/api/contact" name="contactForm">
<input name="email" type="email" ng-model="contact.email" required />
<textarea name="message" ng-model="contact.message" required></textarea>
<button type="submit" ng-disabled="contactForm.$invalid">Send</button>
</form>
<button ng-post="/api/cart/add"
success="cartMessage = $res.message"
error="cartError = $res.error">
Add to cart
</button>
When the form element has an enctype attribute, the request body is URL-encoded using Content-Type: application/x-www-form-urlencoded. Without enctype, form data is sent as a JSON object.
ng-put
ng-put fires a PUT request. Use it to update resources:
name="profileForm"
success="profileSaved = true"
state-success="dashboard">
<input name="name" ng-model="user.name" required />
<input name="email" type="email" ng-model="user.email" required />
<button type="submit">Save changes</button>
</form>
ng-delete
ng-delete fires a DELETE request. It shares all the same modifier attributes as ng-get:
<li>
<span>{{ item.name }}</span>
<button ng-delete="/api/items/{{ item.id }}"
swap="delete"
target="#item-{{ item.id }}">
Delete
</button>
</li>
ng-sse
ng-sse opens a persistent Server-Sent Events connection using the $sse service. Incoming messages are handled the same way as HTTP responses: JSON payloads are merged into scope, HTML strings are injected using the configured swap strategy.
<div ng-sse="/api/events/notifications"
swap="beforeend">
</div>
<div ng-sse="/api/events/market"
trigger="load">
<p>{{ price | currency }}</p>
<p>{{ change }}%</p>
</div>
The connection is torn down automatically when the scope is destroyed (e.g., when navigating away). Reconnect behaviour and error logging are provided by the $sse service.
app.get('/api/events/market', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
const interval = setInterval(() => {
res.write(`data: ${JSON.stringify({ price: 42.50, change: 0.3 })}\n\n`);
}, 2000);
req.on('close', () => clearInterval(interval));
});
Shared modifier attributes
All HTTP directives accept the same set of modifier attributes to control their behaviour:
swap
- Type:
string - Default:
innerHTML
Controls how the response HTML is inserted. Possible values:
innerHTML— replaces the element’s inner content (default)outerHTML— replaces the entire elementtextContent— inserts plain text without HTML parsingbeforebegin— inserts immediately before the elementafterbegin— inserts inside the element, before its first childbeforeend— inserts inside the element, after its last childafterend— inserts immediately after the elementdelete— removes the target element entirelynone— performs no DOM insertion (useful when only scope merging is needed)
target
- Type:
CSS selector
A querySelector selector for the element that receives the response. When omitted, the directive element itself is the target.
<button ng-get="/api/user" target="#profile-card">Load</button>
<div id="profile-card"></div>
trigger
- Type:
DOM event name
The DOM event that fires the request. Defaults to click for buttons and generic elements, change for inputs/selects/textareas, and submit for forms. Use "load" to trigger immediately on link.
latch
- Type:
interpolated expression
Re-fires the request every time the interpolated value changes.
<div ng-get="/api/search" latch="{{ query }}" swap="innerHTML">
{{ results.length }} results
</div>
interval
- Type:
number
Fires the request immediately and then repeats every N milliseconds. The interval is cleared when the scope is destroyed.
<div ng-get="/api/status" interval="10000">{{ status }}</div>
delay
- Type:
number
Wait N milliseconds before sending the request after the trigger event fires.
throttle
- Type:
number
Ignore subsequent trigger events for N milliseconds after the request fires.
loading
- Type:
none
When present, sets data-loading="true" on the element while the request is in flight and data-loading="false" when it completes. Useful as a CSS hook.
<button ng-get="/api/data" loading>Load</button>
button[data-loading="true"] {
opacity: 0.6;
cursor: wait;
}
loading-class
- Type:
string
A CSS class toggled on the element while the request is in flight.
<button ng-get="/api/data" loading-class="is-loading">Load</button>
success
- Type:
expression
Expression evaluated when the response has a 2xx status code. The response data is available as $res.
<button ng-get="/api/items" success="items = $res">Fetch</button>
error
- Type:
expression
Expression evaluated when the response has a 4xx or 5xx status code. The response data is available as $res.
<button ng-post="/api/login"
success="redirect('/dashboard')"
error="loginError = $res.message">
Log in
</button>
state-success
- Type:
string
Router state name to navigate to on success (calls $state.go).
state-error
- Type:
string
Router state name to navigate to on error (calls $state.go).
animate
- Type:
none
When present, enables $animate transitions for the swap operation. Requires the $animate CSS hooks to be defined.
enctype
- Type:
string
Sets the Content-Type request header and URL-encodes form data. Use "application/x-www-form-urlencoded" to replicate a native HTML form submission.
Practical examples
Loading a data table on mount
<thead>
<tr>
<th>Name</th>
<th>Status</th>
<th>Joined</th>
</tr>
</thead>
<tbody ng-get="/api/users"
trigger="load"
swap="innerHTML">
<!-- Populated with server-rendered rows -->
</tbody>
</table>
Infinite scroll
<li ng-repeat="post in posts">{{ post.title }}</li>
</ul>
<button ng-get="/api/posts?page={{ nextPage }}"
ng-viewport
on-enter="loadMore()"
swap="beforeend"
target="#post-list">
Load more
</button>
Real-time notifications via SSE
<span ng-bind="notifications.unread"></span>
</div>
<!-- SSE merges JSON payloads into scope automatically -->
<div ng-sse="/api/events/notifications" trigger="load">
</div>
Form submission with redirect on success
ng-post="/api/auth/login"
state-success="app.dashboard"
error="authError = $res.message">
<input type="email" name="email" ng-model="credentials.email" required />
<input type="password" name="password" ng-model="credentials.password" required />
<p ng-if="authError" ng-bind="authError"></p>
<button type="submit" ng-disabled="loginForm.$invalid">Log in</button>
</form>
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.