Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/thejohnfreeman/ng-temple
Template inheritance for Angular directives.
https://github.com/thejohnfreeman/ng-temple
Last synced: 21 days ago
JSON representation
Template inheritance for Angular directives.
- Host: GitHub
- URL: https://github.com/thejohnfreeman/ng-temple
- Owner: thejohnfreeman
- Created: 2014-08-23T17:07:57.000Z (over 10 years ago)
- Default Branch: master
- Last Pushed: 2015-03-16T17:51:41.000Z (almost 10 years ago)
- Last Synced: 2024-11-24T21:46:56.478Z (about 1 month ago)
- Language: JavaScript
- Size: 192 KB
- Stars: 1
- Watchers: 4
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# [ng-temple][]
[Template inheritance][inherit] for [Angular][] directives.
[ng-temple]: https://github.com/thejohnfreeman/ng-temple
[inherit]: https://docs.djangoproject.com/en/dev/topics/templates/#template-inheritance
[Angular]: https://angularjs.org/## Installation
ng-temple requires [jQuery][], and for some reason it must be included before Angular.
[jQuery]: http://jquery.com/
```sh
$ bower install ng-temple --save
``````html
```
```js
// app.js
angular.module('app', ['ng-temple'])
```## Quick Start
Skip to the [usage section](#usage).
## Motivation
Angular [directives][] provide a powerful feature for injecting custom content
into a "hole" reserved in a template: [transclusion][ng-transclude].
Fortunately, transclusion in Angular supports [parameterization][]: transcluded
content can use scope variables defined in the directive.
Unfortunately, Angular transclusion works only for a single, monolithic block.[directives]: https://docs.angularjs.org/guide/directive
[ng-transclude]: https://docs.angularjs.org/api/ng/directive/ngTransclude
[parameterization]: http://en.wikipedia.org/wiki/Transclusion#Technical_considerationsConsider a case where we want to write a reusable directive for a panel with a
heading. We might start with a template like this:```html
????
????
```The question marks represent two blocks, the heading and body, that need to be
replaced *separately* with transclusion: a feature unsupported by the existing
directive infrastructure.Some directives take an alternative approach, dividing the responsibility among
multiple directives. For example the [accordion][] in [AngularUI Bootstrap][]
uses a clever trick for the [accordion-heading][] directive: it has an empty
template and passes its transcluded content to an injected parent controller
that inserts it at the right place in the page. This approach divides your
directive into more pieces than is usually desirable, and it's not a convenient
technique to implement.[accordion]: https://github.com/angular-ui/bootstrap/blob/master/src/accordion/accordion.js
[AngularUI Bootstrap]: http://angular-ui.github.io/bootstrap/
[accordion-heading]: https://github.com/angular-ui/bootstrap/blob/master/src/accordion/accordion.js#L96ngTemple offers a solution to multiple transclustion that more closely mimics
the familiar pattern of [template inheritance in Django][inherit]. Named blocks
are defined in a parent template and optionally overridden in a child template.## Usage
In your directive template, elements whose contents should be replaced with
transcluded content are called **holes**. Mark them with the `ng-hole`
attribute, whose value should be a name for the hole.```html
```In your directive definition, let the `ngTemple` service handle compilation.
```js
angular.module('example', ['ngTemple'])
.directive('examplePanel', function(ngTemple) {
return {
restrict: 'E',
compile: ngTemple('example-panel.html'),
}
})
```To use the directive, put replacement blocks, called **pegs**, in the
transcluded content. Use the `ng-peg` attribute with a value matching the name
of the corresponding hole.```html
Heading
The body.
```
Your directive's template will *replace* the calling element, and the contents
of each peg will *replace* the contents of each hole. The result of our example
here looks like this ([on Plunker](http://plnkr.co/edit/84QjyIDI08jDgkmIhkZg)):```html
Heading
The body.
```### Note on element restrictions
We must keep in mind that the browser parses our directive elements as HTML
before Angular even gets a peek. Consequently, invalid HTML in our transcluded
content will produce unexpected results.Consider a directive template that defines a hole inside a table row:
```html
```
```js
angular.module('example', ['ngTemple'])
.directive('exampleTable', function(ngTemple) {
return {
restrict: 'E',
controller: function() {
this.items = [1, 2, 3]
},
controllerAs: 'ctrl',
compile: ngTemple('example-table.html'),
}
})
```One intuitive approach will not work
([on Plunker](http://plnkr.co/edit/pQignhGlb55XcvSyDRaB)):```html
Item
#{{ $item }}
```
If you inspect the page, you'll see that the `td` tags were stripped from the
transclusion, similar to what would be produced by this:```html
Item
#{{ $item }}
```
What happened? `td` elements are [only permitted][td-usage] to be children of
`tr` elements, which are [only permitted][tr-usage] to be children of `table`,
`thead`, `tbody`, or `tfoot` elements. When the browser encounters them outside
of their permitted context, it may choose to ignore them.[td-usage]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td#Usage_context
[tr-usage]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tr#Usage_contextThe fix is to use valid HTML in our transcluded content. Judicious use of the
`ng-peg` attribute lets us exclude extra elements from the final result
([on Plunker](http://plnkr.co/edit/sID8gR9HqSrBaPGnEY4E)):```html
Item
#{{ $item }}
```
### Default peg
Pegs are optional, and any content defined within a hole will serve as a default
peg. Modifying our earlier example...```html
Default Heading
A default body.
``````html
The body.
```
... will produce this result
([on Plunker](http://plnkr.co/edit/oRxkNE1K2IREe46Ew3gx)):```html
Default Heading
The body.
```