Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

adding forloop.first, forloop.last, and forloop.key

  • Loading branch information...
commit f37fb3cffd2c93b8c2bf2b2c6acd54b272cd9df6 1 parent 941f966
@paularmstrong authored
Showing with 54 additions and 16 deletions.
  1. +11 −2 docs/tags.md
  2. +14 −7 lib/tags.js
  3. +29 −7 tests/tags.test.js
View
13 docs/tags.md
@@ -29,12 +29,21 @@ Includes a template in it's place. The template is rendered within the current c
### for
-You can iterate arrays and objects. Access the current iteration index through 'forloop.index' which is available inside the loop.
+You can iterate arrays and objects.
+
+For loops have 4 special context variables accessible inside of the loop:
{% for x in y %}
- <p>{% forloop.index %}</p>
+ {% if forloop.first %}<ul>{% endif %}
+ <li>{% forloop.index %} - {% forloop.key %}: {{ x }}</li>
+ {% if forloop.last %}</ul>{% endif %}
{% endfor %}
+* `forloop.index`: the zero-indexed spot in the iteration.
+* `forloop.key`: if the iterator is an object, this will be the key of the current item, otherwise it will be the same as the `forloop.index`.
+* `forloop.first`: `true` if the current object is the first in the object or array.
+* `forloop.last`: `true` if the current object is the last in the object or array.
+
You can also apply filters to the object that you are iterating over.
{% for x in y|reverse %}
View
21 lib/tags.js
@@ -204,18 +204,25 @@ exports['for'] = function (indent) {
, ' }'
, ' if (Array.isArray(__forloopIter)) {'
, ' var __forloopIndex = 0, __forloopLength = __forloopIter.length;'
- , ' for (; __forloopIndex < __forloopLength; ++__forloopIndex) {'
+ , ' for (; __forloopIndex < __forloopLength; __forloopIndex += 1) {'
, ' forloop.index = __forloopIndex;'
+ , ' forloop.key = __forloopIndex;'
+ , ' forloop.first = (__forloopIndex === 0);'
+ , ' forloop.last = (__forloopIndex === __forloopLength - 1);'
, ' ' + helpers.escape(operand1) + ' = __forloopIter[__forloopIndex];'
- , parser.compile.call(this, indent + ' ')
+ , ' ' + parser.compile.call(this, indent + ' ')
, ' }'
, ' } else if (typeof __forloopIter === "object") {'
- , ' var __forloopIndex;'
- , ' for (__forloopIndex in __forloopIter) {'
- , ' if (__forloopIter.hasOwnProperty(__forloopIndex)) {'
+ , ' var __forloopKey, __forloopLength = Object.keys(__forloopIter).length, __forloopIndex = 0;'
+ , ' for (__forloopKey in __forloopIter) {'
+ , ' if (__forloopIter.hasOwnProperty(__forloopKey)) {'
, ' forloop.index = __forloopIndex;'
- , ' ' + helpers.escape(operand1) + ' = __forloopIter[__forloopIndex];'
- , parser.compile.call(this, indent + ' ')
+ , ' forloop.key = __forloopKey;'
+ , ' forloop.first = (__forloopIndex === 0);'
+ , ' forloop.last = (__forloopIndex === __forloopLength - 1);'
+ , ' ' + helpers.escape(operand1) + ' = __forloopIter[__forloopKey];'
+ , ' ' + parser.compile.call(this, indent + ' ')
+ , ' __forloopIndex += 1;'
, ' }'
, ' }'
, ' }'
View
36 tests/tags.test.js
@@ -72,25 +72,47 @@ exports.if = testCase({
});
exports.for = testCase({
- basic: function (test) {
+ setUp: function (callback) {
swig.init({});
+ callback();
+ },
+ basic: function (test) {
var tmpl8 = swig.fromString('{% for foo in bar %}{{ foo }}, {% endfor %}');
- test.strictEqual(tmpl8.render({ bar: ['foo', 'bar', 'baz'] }), 'foo, bar, baz, ');
+ test.strictEqual(tmpl8.render({ bar: ['foo', 'bar', 'baz'] }), 'foo, bar, baz, ', 'array loop');
+ test.strictEqual(tmpl8.render({ bar: { baz: 'foo', pow: 'bar', foo: 'baz' }}), 'foo, bar, baz, ', 'object loop');
test.done();
},
- index: function (test) {
- swig.init({});
+ variables: function (test) {
+ var tmpl8 = swig.fromString('{% for foo in bar %}[{{ forloop.index }}, {{ forloop.key }}]{% endfor %}');
+ test.strictEqual(tmpl8.render({ bar: ['foo', 'bar', 'baz'] }), '[0, 0][1, 1][2, 2]', 'array loop');
+ test.strictEqual(tmpl8.render({ bar: { baz: 'foo', pow: 'bar', foo: 'baz' }}), '[0, baz][1, pow][2, foo]', 'object loop');
+ test.done();
+ },
+ index: function (test) {
var tmpl8 = swig.fromString('{% for foo in bar %}{{ forloop.index }}{% endfor %}');
- test.strictEqual(tmpl8.render({ bar: ['foo', 'bar', 'baz'] }), '012');
+ test.strictEqual(tmpl8.render({ bar: ['foo', 'bar', 'baz'] }), '012', 'index in object');
+ test.strictEqual(tmpl8.render({ bar: { baz: 'foo', pow: 'bar', foo: 'baz' }}), '012', 'index in object');
test.done();
},
- 'loop object allows filters': function (test) {
- swig.init({});
+ first: function (test) {
+ var tmpl8 = swig.fromString('{% for foo in bar %}{% if forloop.first %}{{ foo }}{% endif %}{% endfor %}');
+ test.strictEqual(tmpl8.render({ bar: ['foo', 'bar', 'baz'] }), 'foo', 'first in array');
+ test.strictEqual(tmpl8.render({ bar: { baz: 'foo', pow: 'bar', foo: 'baz' }}), 'foo', 'first in object');
+ test.done();
+ },
+ last: function (test) {
+ var tmpl8 = swig.fromString('{% for foo in bar %}{% if forloop.last %}{{ foo }}{% endif %}{% endfor %}');
+ test.strictEqual(tmpl8.render({ bar: ['foo', 'bar', 'baz'] }), 'baz', 'last in array');
+ test.strictEqual(tmpl8.render({ bar: { baz: 'foo', pow: 'bar', foo: 'baz' }}), 'baz', 'last in object');
+ test.done();
+ },
+
+ 'loop object allows filters': function (test) {
var tmpl8 = swig.fromString('{% for foo in bar|reverse %}{{ foo }}{% endfor %}');
test.strictEqual(tmpl8.render({ bar: ['baz', 'bar', 'foo'] }), 'foobarbaz');
test.done();
Please sign in to comment.
Something went wrong with that request. Please try again.