Armin Ronacher | 2b22874 | 2008-05-18 20:29:32 +0200 | [diff] [blame] | 1 | Tips and Tricks |
| 2 | =============== |
Armin Ronacher | fdf9530 | 2008-05-11 22:20:51 +0200 | [diff] [blame] | 3 | |
| 4 | .. highlight:: html+jinja |
| 5 | |
Armin Ronacher | 2b22874 | 2008-05-18 20:29:32 +0200 | [diff] [blame] | 6 | This part of the documentation shows some tips and tricks for Jinja2 |
Armin Ronacher | fdf9530 | 2008-05-11 22:20:51 +0200 | [diff] [blame] | 7 | templates. |
| 8 | |
| 9 | |
| 10 | .. _null-master-fallback: |
| 11 | |
| 12 | Null-Master Fallback |
| 13 | -------------------- |
| 14 | |
| 15 | Jinja2 supports dynamic inheritance and does not distinguish between parent |
| 16 | and child template as long as no `extends` tag is visited. While this leads |
| 17 | to the surprising behavior that everything before the first `extends` tag |
Vivek Agarwal | 972feb4 | 2014-03-12 20:26:03 +0530 | [diff] [blame] | 18 | including whitespace is printed out instead of being ignored, it can be used |
Armin Ronacher | fdf9530 | 2008-05-11 22:20:51 +0200 | [diff] [blame] | 19 | for a neat trick. |
| 20 | |
| 21 | Usually child templates extend from one template that adds a basic HTML |
Vivek Agarwal | 972feb4 | 2014-03-12 20:26:03 +0530 | [diff] [blame] | 22 | skeleton. However it's possible to put the `extends` tag into an `if` tag to |
Armin Ronacher | fdf9530 | 2008-05-11 22:20:51 +0200 | [diff] [blame] | 23 | only extend from the layout template if the `standalone` variable evaluates |
| 24 | to false which it does per default if it's not defined. Additionally a very |
| 25 | basic skeleton is added to the file so that if it's indeed rendered with |
| 26 | `standalone` set to `True` a very basic HTML skeleton is added:: |
| 27 | |
| 28 | {% if not standalone %}{% extends 'master.html' %}{% endif -%} |
| 29 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
| 30 | <title>{% block title %}The Page Title{% endblock %}</title> |
| 31 | <link rel="stylesheet" href="style.css" type="text/css"> |
| 32 | {% block body %} |
| 33 | <p>This is the page body.</p> |
| 34 | {% endblock %} |
| 35 | |
| 36 | |
| 37 | Alternating Rows |
| 38 | ---------------- |
| 39 | |
| 40 | If you want to have different styles for each row of a table or |
| 41 | list you can use the `cycle` method on the `loop` object:: |
| 42 | |
| 43 | <ul> |
| 44 | {% for row in rows %} |
| 45 | <li class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li> |
| 46 | {% endfor %} |
| 47 | </ul> |
| 48 | |
| 49 | `cycle` can take an unlimited amount of strings. Each time this |
| 50 | tag is encountered the next item from the list is rendered. |
| 51 | |
| 52 | |
| 53 | Highlighting Active Menu Items |
| 54 | ------------------------------ |
| 55 | |
| 56 | Often you want to have a navigation bar with an active navigation |
| 57 | item. This is really simple to achieve. Because assignments outside |
| 58 | of `block`\s in child templates are global and executed before the layout |
| 59 | template is evaluated it's possible to define the active menu item in the |
| 60 | child template:: |
| 61 | |
| 62 | {% extends "layout.html" %} |
| 63 | {% set active_page = "index" %} |
| 64 | |
| 65 | The layout template can then access `active_page`. Additionally it makes |
William Wenge-Murphy | de08e05 | 2014-09-20 18:11:28 -0700 | [diff] [blame] | 66 | sense to define a default for that variable:: |
Armin Ronacher | fdf9530 | 2008-05-11 22:20:51 +0200 | [diff] [blame] | 67 | |
Armin Ronacher | 69e12db | 2008-05-12 09:00:03 +0200 | [diff] [blame] | 68 | {% set navigation_bar = [ |
Armin Ronacher | fdf9530 | 2008-05-11 22:20:51 +0200 | [diff] [blame] | 69 | ('/', 'index', 'Index'), |
| 70 | ('/downloads/', 'downloads', 'Downloads'), |
| 71 | ('/about/', 'about', 'About') |
| 72 | ] -%} |
Armin Ronacher | 69e12db | 2008-05-12 09:00:03 +0200 | [diff] [blame] | 73 | {% set active_page = active_page|default('index') -%} |
Armin Ronacher | fdf9530 | 2008-05-11 22:20:51 +0200 | [diff] [blame] | 74 | ... |
| 75 | <ul id="navigation"> |
| 76 | {% for href, id, caption in navigation_bar %} |
| 77 | <li{% if id == active_page %} class="active"{% endif |
Eugene Kalinin | 9501718 | 2013-05-14 06:59:53 +0400 | [diff] [blame] | 78 | %}><a href="{{ href|e }}">{{ caption|e }}</a></li> |
Armin Ronacher | fdf9530 | 2008-05-11 22:20:51 +0200 | [diff] [blame] | 79 | {% endfor %} |
| 80 | </ul> |
| 81 | ... |
Armin Ronacher | e224488 | 2008-05-19 09:25:57 +0200 | [diff] [blame] | 82 | |
| 83 | .. _accessing-the-parent-loop: |
| 84 | |
| 85 | Accessing the parent Loop |
| 86 | ------------------------- |
| 87 | |
| 88 | The special `loop` variable always points to the innermost loop. If it's |
| 89 | desired to have access to an outer loop it's possible to alias it:: |
| 90 | |
| 91 | <table> |
| 92 | {% for row in table %} |
| 93 | <tr> |
| 94 | {% set rowloop = loop %} |
| 95 | {% for cell in row %} |
Yuval Greenfield | a002727 | 2014-11-06 09:31:32 -0800 | [diff] [blame] | 96 | <td id="cell-{{ rowloop.index }}-{{ loop.index }}">{{ cell }}</td> |
Armin Ronacher | e224488 | 2008-05-19 09:25:57 +0200 | [diff] [blame] | 97 | {% endfor %} |
| 98 | </tr> |
| 99 | {% endfor %} |
| 100 | </table> |