Many of the Jinja functionalities reside as code blocks. These blocks are usually declared as: `{% blocktype %} ... {% endblocktype %}`. Code blocks not only enable you to organize your code better visually, but they also allow you to semantically divide your code into coherent blocks that provide one certain function. There are eight block types supported by Jinja. However, template importing is not supported in our implementation of Jinja. Therefore, the basic block type `block` does not have any practical use and will not be covered.

# Scope of a variable

By introducing blocks to your code, you will need to keep in mind one important new thing called variable scope. To make efficient use of memory resources, variables should only exist as long as they are needed. Some variables might be important for the whole of your template, such as the name of your customer, but often you will find yourself working with a variable only inside the block where it was defined. Hence, Jinja includes a property of variables called _variable scope_. Some variables have their scope defined as `Global`, which denotes that they are defined and accessible in all of your template code. However, generally, the variables defined in your templates will have a defined scope only inside a certain block, such as inside a for loop, macro, or a custom-defined block. They will have the so-called `Local` variable scope. It is considered to be good practice to stay away from Global variables unless they are truly necessary. However, with local variables, you need to keep track of the scope they are defined for.

For a list of Global Jinja variables in Bloomreach Engagement see [Personalization using Jinja](🔗).

# Block types

## Set

The set block is used to assign values to variables. See [using your variables](🔗) in our Jinja Basics article.

Set blocks and filters

Unlike in Jinja documentation, applying filter directly to {% set %} block, as illustrated below, is **NOT** supported,

## Control flow

Your templates are generally being evaluated line by line from the first line to the last line. But often, you might want to repeat certain statements in your template or you might want to perform certain statements only if a certain condition was met. Jinja provides this functionality through the control flow blocks.

### If blocks

The simplest control flow block to understand is the if block. If blocks are used to include conditional statements to your templates. The syntax of block statements is quite simple. Firstly, you have a line with a boolean expression that represents your condition `{% if myCondition %}`, then you have a bunch of lines that will get rendered only if your condition was indeed true. Optionally, you can include the elif statement `{% elif mySecondCondition %}`. Elif is an abbreviation of else if and as the name suggests, the elif statement gets evaluated if the first condition was false. Once again, elif statement is followed by a bunch of lines that will get rendered if the second condition is true ( hence the lines after elif will get evaluated if and only if the first condition was false and the second true. You can include the else statement `{% else %}` and again a bunch of lines that will get evaluated if neither of the conditions was met. Finally, the if block has to end with a `{%endif%}` line.

To sum up, in a single if block, the first if/elif whose statement evaluates to true is rendered, the other one is skipped. If all if/elif statements evaluate to false the else block is rendered.

The simple examples below illustrate the use of if blocks.

#### Inline expressions

You can also use if statements outside of if blocks by using inline expressions. They are very similar to python conditional expressions, see the reference in [Conditional expressions - python docs](🔗). You use the inline expressions to quickly assign conditional values to variables inside the set blocks. The syntax is `valueIfTrue if myCondition else valueIfFalse`. See the code below for an example

### Jinja Tests

To help you create common conditions that include more than just simple boolean evaluation, Jinja includes functionality called testing. You can test your variables using the `is` or `in` keyword to evaluate the common properties of your variables. The tests with the `is` operator are used to test whether the variable being tested has a certain property, while the `in` operator is being used to test whether a value can be found in the variable being tested. The result is a boolean True or False in both cases and as any boolean value, it can be printed, included in a conditional statement, or even saved in a variable for later use.

**Test categories are:**

  • Tests that check type

  • Tests that check object characteristics

  • Tests that check Strings

  • Tests that check Numbers

  • Tests that check Equality and Identity

  • Tests that check ownership

##### List of all tests
###### Tests that check types
defined(value)Returns true if the variable is defined.
none(value)Returns true if the variable is of type none.
number(value)Returns true if the variable is a number.
string(value)Returns true if the object is a string.
undefined(value)Returns true if the variable is undefined. Opposite of defined().
###### Tests check object characteristics
callable(object)Returns true if the object is callable (i.e., some kind of function, e.g. macro, filter or test). Note that classes are callable, as are instances with a **call**() method.
iterable(value)Returns true if the object is iterable (List, Tuple, String, Dictionary). Same as sequence().
mapping(value)Returns true if the object is a mapping (dictionary).
sequence(value)Returns true if the variable is a sequence. Sequences are variables that are iterable (List, Tuple, String, Dictionary). Same as iterable().
###### Tests that check Strings
escaped(value)Returns true if the value is escaped (does NOT contain any of the following: '&', '>', '\<', single-quote ( ' )).
lower(value)Returns true if the variable is lowercased (All alphabetical characters are lowercase, and there is at least 1 alphabetical character).
upper(value)Returns true if the variable is uppercased (All alphabetical characters are uppercase, and there is at least 1 alphabetical character).
###### Tests that check Numbers
odd(value)Returns true if the value in the variable is odd.
even(value)Returns true if the value in the variable is even.
divisibleby(value, num)Returns true if the variable is divisible by a number.
###### Tests that check ownership
in(value, seq)Returns true if the iterable sequence contains value as one of its items.

The in test syntax

Note the slightly different syntax for in operator (as well as the different position of the _not_ keyword). '{% set x = {'a': 1, 'b': 2} %}' '{{ 'a' in x }}' // prints true, 'a' is one of keys '{{ 2 not in x }}' // prints true, 2 is not one of keys

### For blocks

For blocks are used to go through the elements of iterables while performing some actions on each element.

Firstly, you will need to initiate the for block using `{% for myItem in myIterable%}`, where `myIterable` stands for the given iterable. Then, the following lines will be the actions to be run on the item that is currently being accessed from the iterable. You can also include the `{% else %}` block, which will be run if no items were passed through in the for loop, i.e. the supplied iterable was empty. Finally, you need to end the for block by using `{% endfor %}`.

For block on a dictionary

If a dictionary is provided, the for loop will iterate over its keys.

#### Recursive for loop

Jinja supports recursive loop with 'recursive' flag at the end of for loop statement. Such for loops can use `loop(List)` function, which repeats the for loop with the recursive flag for each item in List. This allows you to effectively work with nested data structures.

#### For loop filtering

If iterable contains items that you would like to exclude from the for loop, these can be filtered out at the end of the for loop statement.

If used on for loop with the recursive flag, the recursive flag is at the end of the statement.

#### For blocks loop variables

When inside for loop, a special variable 'loop' is available with the properties listed in the following table.

Property nameTypeReturns
loop.first**Integer**True if it is the first iteration, else false
loop.last**Integer**True if it is the last iteration, else false
loop.length**Integer**Number of total iterations
loop.depth**Integer**Current depth in a loop with 'recursive' tag. Starts at level 1. See Recursive for loop.
loop.depth0**Integer**Current depth in a loop with 'recursive' tag. Starts at level 0. See Recursive for loop.
loop.index**Integer**Current index starting from 1
loop.index0**Integer**Current index starting from 0
loop.revindex**Integer**Current index from end starting from 1. (On first iteration: loop.revindex == loop.length, on last iteration: loop.revindex == 1).
loop.revindex0**Integer**Current index from end starting from 0. (On first iteration: loop.revindex0 == loop.length - 1, on iteration loop: loop.revindex0 == 0)
loop.cycle(arg1, arg2, ...)**Function**For each iteration n in current loop, returns n-th item in the sequence of arguments. See [**loop.cycle()**](🔗).
##### loop.cycle()

The loop.cycle() is a helper function that for each iteration n in current loop, returns n-th item in the provided sequence of arguments. Loops over the given sequence if reached the end.

loop.cycle() and recursive for loop

loop.cycle() also resets for recursive loops.

## Macros

Macros are Jinja equivalent of functions, a callable block to which arguments can be passed. They allow you to write clearer code or save up space by replacing the same commands repeated in multiple places with one macro.

The syntax of macro blocks is simple. As with the other block types, you begin by `{% macro macroName(args) %} ` and end the block with `{% endmacro $}`. To enable macros to really behave like functions, they too have parameters, that are referred to as arguments.

Nested macros

Macros can call other macros as well as themselves recursively inside the macro block.

Macros' arguments can have default values, defined by arg=value in the parenthesis in the macro statement

Default values in macros

If defining default values for arguments, arguments without default value must be declared first.

### Call

The last Jinja block is directly connected to macros. Instead of calling a macro only by its name, you can use the call block to call a specified macro with the block's content appended as its last argument. When the call block is passed to the macro, its content is wrapped in a macro and assigned to the 'caller' argument. Since the passed call block is passed as a macro, it must be called `caller()`.

## Raw

The raw block's content is evaluated as a string. Any Jinja syntax within raw block is left as is and is **not** evaluated. The raw blocks are useful when you want to print out Jinja syntax. However, you will only rarely need them while using Bloomreach Engagement.