{ifchanged $customer} compares its value with the value it had the previous
time it ran in the same loop. The content renders when the value is different - and always on
the first row - so in a list sorted on that field it renders once at the start of every
group: the classic group heading. When the value is the same as before, the
@else@ part renders instead, if the tag has one.
With several values - {ifchanged $year, $month} - the content renders when any
of them changed. Sort the rows first (the sort option, or in the query): the tag
only looks one row back, so an unsorted list gets a heading every time the value flips.
The memory belongs to one run of the enclosing loop - the nearest level that is not an
{if}, a {case} or another {ifchanged} - so the tag may
stand inside an {if} in the loop, and a loop that runs again (an inner loop on the
next outer row) starts afresh. Several {ifchanged} tags in one row are kept apart
by position: the second one of a row is compared with the second one of the row before.
Under the strict syntax check an {ifchanged} without a value, or without its
closing tag, is an error. The {case} and {if} tags
compare with fixed values; {ifchanged} compares with the row before.