# Looping through objects and arrays

Loop through and repeat content from an array or object in your personalized message content.


You can use the `#each` operator to loop through and repeat content from an array or object. For example, you can show a user all the items in their shopping cart, including quantity, description, and price.

Specify the key of the array or object that you want to start your loop from using `{{#each <property>}}`. You can access properties within the loop with the [Handlebars](https://www.airship.com/docs/reference/glossary/#handlebars) expressions on this page.

> **Note:** You cannot loop using Handlebars without an array or object data to loop through.


## Setting a loop limit {#each}

When you use `#each`, you can limit the number of loops to perform, making sure that your message is a reasonable length.

Set a limit using `#each (limit <property> <integer>)`.

```text
We think you might like:
{{#each (limit array_of_objects 2) as |obj|}}
{{obj.name}}: {{obj.desc}}
{{/each}}
```


## Setting context using #with {#with}

Use `{{#with}}` to set the context within your template. This can help you access nested keys without having to repeat the parent object's path.

For example, if your audience's shipping information is nested in an object called `shippingAddress`, your code might look like this:

```text
{{shippingAddress.street}}
{{shippingAddress.state}}, {{shippingAddress.zipCode}}
```


You then might use the `with` helper to limit context and simplify your template like this


```text
We'll ship your package to:
{{#with shippingAddress}}
   {{street}}
   {{state}}, {{zipCode}}
{{/with}}
```


## Creating and concatenating arrays

When constructing new arrays or concatenating existing arrays, the following operators are available:

  * `{{$array <object...>}}` — Creates a new array from the given items. Any number of items may be passed as parameters, e.g., `{{$array "a" "b" "c"}}` creates a new array containing `["a", "b", "c"]`.
  * `{{$concat <arrays...>}}` — Creates a new array from a given list of arrays.

The [`with`](#with) helper can be useful here to assign these created objects to new variables:

```text
{{#with ($array "a" "b" "c") as |arr|}}
{{#each arr}}{{.}}{{#unless @last}}, {{/unless}}{{/each}}
{{/with}}
```


...which will yield `a, b, c`.

## Checking for presence

The `$contains` operator can be used to check if a value is present in an array.

  * `{{$contains <array> <search_item>}}` — Returns a boolean value representing if `search_item` exists in `array`.

```text
{{#if ($contains favorite_movies "Brazil")}}
You must be a Terry Gilliam Fan.
{{/if}}
```


## Working with key/value objects

The `$merge` and `$pick` operators can help you construct new key/value objects from existing ones.

  * `{{$pick <object> <keys...>}}` — Constructs a new object from `keys` picked from `object`. If a key is not found in the object, it will be omitted. You may specify as many keys as you like, e.g., `{{$pick obj "key1" "key2"}}`.
  * `{{$merge <objects...>}}` — Constructs a new object by merging the given objects. They are merged only on their top-level keys, and the right-most object wins if the same key is present in multiple objects.

```text
{{#with ($pick ($merge obj1 obj2) "key1" "key2") as |newObj|}}
{{#each newObj}}
* {{@key}}: {{.}}
{{/each}}
{{/with}}
```


## Filtering empty values

You can use the `$filterEmpty` operator to filter any empty values from an array or key/value object. When filtering a key/value object, values are evaluated for emptiness:

```text
{{#with ($filterEmpty ($array "a" "b" "" "c")) as |arr|}}
{{#each arr}}{{.}}{{#unless @last}}, {{/unless}}{{/each}}
{{/with}}
```


...which will yield `a, b, c`.

## Getting the number of items in objects and arrays

Using the `length` property on an array, or the `size` property on a map or object, you can get the number of items or number of keys, respectively.

```text
{{#gt array.length 3}}
Array length was greater than 3!
{{/gt}}

{{#gt object.size 3}}
Object had more than 3 keys!
{{/gt}}
```


## Referencing properties in objects and arrays

Because your loop reference begins from the object or array specified by `#each`, you don't need to provide the full path of the property that you want to reference, just the path to the key within the current iteration of the loop.

For example, if looping through an array of objects called `suggestedProducts`, you could specify the keys within each object — `qty` and `productName`.
```text
{{#each suggestedProducts}}
{{qty}}x {{productName}}
{{/each}}
```



You can also reference properties of the array itself within the context of the loop.

* `{{.}}` — Accesses the current item in the array, generally for simple arrays of strings or integers.

* `{{@index}}` — References the current array index in the loop.

* `{{@key}}` — Provides the key name or index location of the current loop iteration.

* `{{@root}}` — Accesses the root element properties while you iterate in the context of any nested or child elements.

* `{{@first}}` — Returns true for the first element in the loop and can be used with If/Else statements. For example, `{{#each array}} {{#if @first}} Hello! {{/if}} {{/each}}` will include "Hello!" in front of the first object in your array.

* `{{@last}}` — Returns true for the last element in the loop and can be used with If/Else statements. For example, `{{#each array}} {{#if @last}} Goodbye! {{/if}} {{/each}}` will include "Goodbye!" in front of the last object in your array.

* `{{this}}` — Limits the context to the current object iteration of the loop. Use dot notation to reference a key in the object, i.e., `{{this.key}}`.

   In general, you don't need to use `this` unless you have a duplicate key outside the loop and the key in your loop is optional. In such a case, `this` prevents the template from finding and using a duplicate key outside the current iteration of the loop if the key in the loop is missing.


**Reference names in a simple array:**

```text
Everybody coming to the pizza party:
{{#each pizza_partiers}}
{{@index}}: {{.}}
{{/each}}
```


**Reference items in a user's shopping cart as an array of objects:**


```text
Are you still interested in the following items?
{{#each cart}}
* {{qty}}x {{product}} for {{price}}
{{/each}}
```


## Using a feed

An *External Data Feed* is a connection to an external API. When you send a message, Airship uses a response from that API to personalize messages. See: [External data feeds](https://www.airship.com/docs/guides/personalization/sources/external-data-feeds/).

You reference an external feed as a block, and you can use properties from your feed within the block — `{{#feed "feed_name" var_in_url="value" as |alias|}}`.

For example, imagine you have a feed at `https://www.example.com/[[region]]/featured-products` that returns an array of products that you want to display to your audience. You may want to set the region at send time (rather than using the default value from your feed), and you may want to provide an alias so that your feed properties don't collide with attributes or custom event properties.

Your message text and Handlebars might look something like this:

```text
{{#feed "featured_products" region="us" as |result|}}
  {{#each (limit result.products 2) as |product|}}
    {{product.name}}: {{product.price}}
    https://cool-store.tld/us/products/{{urlEncode product.slug}}/
  {{else}}
    Check back later for deals!
  {{/each}}
{{else}}
Couldn't fetch featured products!
{{/feed}}
```


> **Note:** While the feed block grants access to variables from the feed response, you can still reference variables (or [merge fields](https://www.airship.com/docs/reference/glossary/#merge_field)) that aren't a part of the feed — attributes, custom event properties, etc. If this is something you may do, set the feed namespace using `as |alias|` to differentiate between properties from the feed and other personalization variables.

