Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/longshotlabs/meteor-template-extension

A Meteor package: Replace already defined templates, inherit helpers and events from other templates
https://github.com/longshotlabs/meteor-template-extension

Last synced: 3 months ago
JSON representation

A Meteor package: Replace already defined templates, inherit helpers and events from other templates

Awesome Lists containing this project

README

        

[![Build Status](https://travis-ci.org/aldeed/meteor-template-extension.svg)](https://travis-ci.org/aldeed/meteor-template-extension)

template-extension
=========================

A smart package for Meteor that allows you to:

* iterate over all defined templates easily.
* attach multiple created/rendered/destroyed hooks to a template.
* attach a created/rendered/destroyed hook to all templates.
* override a template but keep its helpers and events.
* inherit the helpers from another template.
* inherit the events from another template.
* extend abstract templates and overwrite their events/helpers.
* use `template.parent(numLevels, includeBlockHelpers)` to access a parent template instance.
* use `template.get(propName)` to get the value of the first property named `propName` on the current or an ancestor template instance.
* use `template.set(propName, value)` to set the value of the first property named `propName` on the current or an ancestor template instance.
* pass a function to `Template.parentData(fun)` to get the first data context which passes the test.

**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*

- [Installation](#installation)
- [Compatibility](#compatibility)
- [Template.forEach(callback)](#templateforeachcallback)
- [Template.forEachCurrentlyRenderedInstance(callback)](#templateforeachcurrentlyrenderedinstancecallback)
- [Template.onCreated / Template.onRendered / Template.onDestroyed](#templateoncreated--templateonrendered--templateondestroyed)
- [hooks(options)](#hooksoptions)
- [replaces(templateName)](#replacestemplatename)
- [inheritsHelpersFrom(templateName), inheritsEventsFrom(templateName), and inheritsHooksFrom(templateName)](#inheritshelpersfromtemplatename-inheritseventsfromtemplatename-and-inheritshooksfromtemplatename)
- [clearEventMaps()](#cleareventmaps)
- [copyAs(newTemplateName)](#copyasnewtemplatename)
- [templateInstance.parent(numLevels, includeBlockHelpers)](#templateinstanceparentnumlevels-includeblockhelpers)
- [templateInstance.parent(selector, includeBlockHelpers)](#templateinstanceparentselector-includeblockhelpers)
- [templateInstance.get(fieldName)](#templateinstancegetfieldname)
- [Template.parentData(fun)](#templateparentdatafun)
- [Contributors](#contributors)

## Installation

```bash
$ meteor add aldeed:template-extension
```

## Compatibility

- Use a 3.x.x release with Meteor 1.0.x or Meteor 1.1.x
- Use a 4.x.x release with Meteor 1.2+

## Template.forEach(callback)

Call `callback` once for each defined template. Generally, you'll want to call this in a `Meteor.startup` function or sometime after all templates have been loaded.

## Template.forEachCurrentlyRenderedInstance(callback)

Call `callback` once for each template instance that is currently rendered.

## Template.onCreated / Template.onRendered / Template.onDestroyed

Run a function whenever *any* template is created/rendered/destroyed.

```js
Template.onRendered(function () {
// Initialize all datepicker inputs whenever any template is rendered
this.$('.datepicker').datepicker();
});
```

## hooks(options)

An alternative syntax to `onCreated`, `onRendered`, and `onDestroyed`.

```js
Template.foo.hooks({
created() {
console.log("foo created");
},
rendered() {
console.log("foo rendered");
},
destroyed() {
console.log("foo destroyed");
},
});
```

## replaces(templateName)

*html*

```html

{{> foo}}

{{bar}}
Click

{{bar}} 2
Click 2

```

*client.js*

```js
Template.foo.helpers({
bar() {
return "TEST";
},
});

Template.foo.events({
'click button'(event, template) {
console.log("foo button clicked");
},
});

Template.foo2.replaces("foo");
```

Whenever `{{> foo}}` is used, the contents of the `foo2` template will be shown instead. The `bar` helper defined on "foo" will be used to resolve `{{bar}}`. Clicking the button will still fire the event defined on "foo".

This is useful when a package you are using defines a template for something and you'd like to adjust some things in that template for your app.

NOTE: This simply swaps the render function. Helpers, callbacks, and events assigned to `foo2` will not fire when `{{> foo}}` is used. Only the `foo` helpers, callbacks, and events are used.

## inheritsHelpersFrom(templateName), inheritsEventsFrom(templateName), and inheritsHooksFrom(templateName)

*html*

```html

{{> foo}}
{{> foo2}}

{{bar}}
Click

{{bar}} 2
Click 2

```

*client.js*

```js
Template.foo.helpers({
bar() {
return 'TEST';
},
});

Template.foo.events({
'click button'(event, template) {
console.log('foo button clicked');
},
});

Template.foo.onCreated(function onCreated() {
console.log('foo created');
});

Template.foo2.inheritsHelpersFrom('foo');
Template.foo2.inheritsEventsFrom('foo');
Template.foo2.inheritsHooksFrom('foo');
```

In this example, both templates are rendered. Both use the `bar` helper defined on "foo" to resolve `{{bar}}`. Both fire the click event defined on "foo". The "foo2" template will inherit the `foo.created` callback and log 'foo' to the console upon creation.

Additionally, these methods can be called with an array of template names: `Template.foo2.inheritsHooksFrom(['foo', 'bar', 'baz']);`

Because of the different ways in which helpers, events, and hooks are stored, the ability to override them is different. Helpers are stored internally as a hash, which means that if you inherit a "name" helper and then call `myTemplate.helpers({ name: ... })`, the new "name" helper will overwrite the old helper. By contrast, events and hooks are stored in arrays, which means that you cannot override them easily. You may be able to achieve what you want with `clearEventMaps()` or looping through the events or hooks to somehow remove those you don't want.

## clearEventMaps()

After `Template.foo.events({...})` has been called one or more times, you can remove all the added event handlers by calling `Template.foo.clearEventMaps()`

## copyAs(newTemplateName)

*html*

```html

{{> foo}}
{{> bar}}

{{#each images}}
{{title}}
{{/each}}

```

*client.js*

```js
Template.abstract_foo.helpers({
images() {
return [];
}
});

Template.abstract_foo.copyAs(['foo', 'bar']);

Template.foo.helpers({
images() {
return Meteor.call('getFooImages');
}
});

Template.bar.helpers({
images() {
return Meteor.call('getBarImages');
}
});
```

In this example, we defined "foo" and "bar" templates that get their HTML markup, events, and helpers from a base template, `abstract_foo`. We then override the `images` helper for "foo" and "bar" to provide template-specific images provided by different Meteor methods. Template.template.copyAs can accept either single template name (in string form), or an array of template names as shown in the above example.

Calling `copyAs` is the same as calling `inheritsHelpersFrom`, `inheritsEventsFrom`, and `inheritsHooksFrom` and also copying the render function.

If copyAs is invoked with a string, it returns the newly created template.

If copyAs is invoked with an array, it returns an array of newly created templates.

## templateInstance.parent(numLevels, includeBlockHelpers)

On template instances you can now use `parent(numLevels)` method to access a parent template instance.
`numLevels` is the number of levels beyond the current template instance to look. Defaults to 1.
By default block helper template instances are skipped, but if `includeBlockHelpers` is set to true,
they are not.

## templateInstance.parent(selector, includeBlockHelpers)

You can also call `templateInstance.parent` with function as first argument. The function, known as selector, will be
passed the current template being traversed. If it returns true, we return the template that is currently being traversed,
otherwise, we traverse further up. We traverse up until there are no more templates, in which case, we return null.

## templateInstance.get(fieldName)

To not have to hard-code the number of levels when accessing parent template instances you can use
`get(fieldName)` method which returns the value of the first property named `fieldName` on the current
or ancestor template instances, traversed in the hierarchical order. It traverses block helper template
instances as well. This pattern makes it easier to refactor templates without having to worry about
changes to number of levels.

## Template.parentData(fun)

`Template.parentData` now accepts a function which will be used to test each data context when traversing
them in the hierarchical order, returning the first data context for which the test function returns `true`.
This is useful so that you do not have to hard-code the number of levels when accessing parent data contexts,
but you can use a more logic-oriented approach. For example, search for the first data context which contains
a given field. Or:

```js
var data = Template.parentData(function (data) {return data instanceof MyDocument;});
```

## Contributing

When submitting a pull request, please add tests for any new features and make sure that all existing tests still pass.

```bash
$ meteor test-packages ./
```

### Contributors

* @aldeed
* @grabbou
* @mitar
* @jgladch
* @merlinpatt
* @JoeyAndres