Giter Site home page Giter Site logo

ng-temple's Introduction

Template inheritance for Angular directives.

Installation

ng-temple requires jQuery, and for some reason it must be included before Angular.

$ bower install ng-template --save
<!-- index.html -->
<script src="bower_components/jquery/dist/jquery.js"></script>
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/ng-temple/ng-temple.js"></script>
// app.js
angular.module('app', ['ng-temple'])

Quick Start

Skip to the usage section.

Motivation

Angular directives provide a powerful feature for injecting custom content into a "hole" reserved in a template: transclusion. 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.

Consider a case where we want to write a reusable directive for a panel with a heading. We might start with a template like this:

<div>
  <h1>
    ????
  </h1>
  <p>
    ????
  </p>
</div>

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.

ngTemple offers a solution to multiple transclustion that more closely mimics the familiar pattern of template inheritance in Django. 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.

<!-- example-panel.html -->
<div>
  <h1 ng-hole="heading">
  </h1>
  <p ng-hole="body">
  </p>
</div>

In your directive definition, let the ngTemple service handle compilation.

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.

<!-- index.html -->
<example-panel>
  <div ng-peg="heading">
    Heading
  </div>
  <div ng-peg="body">
    The body.
  </div>
</example-panel>

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):

<div>
  <h1 ng-hole="heading">
    Heading
  </h1>
  <p ng-hole="body">
    The body.
  </p>
</div>

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:

<!-- example-table.html -->
<table class="table">
  <tr ng-repeat="$item in ctrl.items" ng-hole="row">
  </tr>
</table>
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):

<!-- index.html -->
<example-table>
  <div ng-peg="row">
    <td>Item</td>
    <td>#{{ $item }}</td>
  </div>
</example-table>

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:

<table class="table">
  <tr ng-repeat="$item in ctrl.items" ng-hole="row">
    Item
    #{{ $item }}
  </tr>
</table>

What happened? td elements are only permitted to be children of tr elements, which are only permitted 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.

The 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):

<!-- index.html -->
<example-table>
  <table>
    <tr ng-peg="row">
      <td>Item</td>
      <td>#{{ $item }}</td>
    </tr>
  </table>
</example-table>

Default peg

Pegs are optional, and any content defined within a hole will serve as a default peg. Modifying our earlier example...

<!-- example-panel.html -->
<div>
  <h1 ng-hole="heading">
    Default Heading
  </h1>
  <p ng-hole="body">
    A default body.
  </p>
</div>
<!-- index.html -->
<example-panel>
  <div ng-peg="body">
    The body.
  </div>
</example-panel>

... will produce this result (on Plunker):

<div>
  <h1 ng-hole="heading">
    Default Heading
  </h1>
  <p ng-hole="body">
    The body.
  </p>
</div>

ng-temple's People

Contributors

thejohnfreeman avatar

Watchers

João Figueiredo avatar James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.