---
title: Injecting Data into the DOM | Shopware Community Hub
description: >-
  Extracting data from the App Server is an important part of App development.
  In this learning unit, you will take a response from the App Server and render
  it…
canonical_url: 'https://hub.shopware.com/learn/unit/app-injecting-data-into-the-dom'
---

# Injecting Data into the DOM

<LearningObjectives>

- **Understand** the capabilities and purpose of storefront plugins.
- **Learn** how to use **content templating** within storefront plugins.
- Use **`this.el`** to access and **manipulate the DOM**.
- **Render** entity data **dynamically** in the storefront using JavaScript.

</LearningObjectives>

# Injecting Data into the DOM

In the previous learning unit, we successfully fetched data from the App Server using the `AppClient`. Now we want to **display this data in the storefront**. To achieve this, we will work with [DOM manipulation](https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/DOM_scripting), so selecting and updating elements on the page via JavaScript. By injecting the App Server data directly into the DOM, we can make it visible to customers in the storefront.

<Callout title="Note on JavaScript Details" type="warning">

This learning unit does not aim to explain DOM APIs in full detail. If you are new to JavaScript or want to dive deeper, we recommend the [Mozilla Foundation](https://developer.mozilla.org/en-US/), which provides excellent references and tutorials on DOM manipulation.

</Callout>

## Code-Along

To follow along, use this command within the ShopwareStoreTracker directory:

```bash
git checkout tags/plugin_rendering--start
```

## Composing a Template for the Storefront Plugin

In the previous step we fetched data, but it only appears in the browser console. Now let's display this data in the storefront.

The common way to achieve this is that we define a [Content Template](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/template). A `template` element is a special HTML Element that stores content in the background. By default, it doesn't show up in the browser. JavaScript can later copy its content and display it dynamically into the page. In other words: if the template contains content, it can be displayed when needed, if it's empty, nothing will show up.

You might wonder why not just use a `p` or `div` element. The difference is that the `template` element is **inactive by default**. The browser ignores its content until JavaScript explicitly uses it. The `template` element is a great way to define a placeholder for content that will be displayed later.

Let's display the stock data in the buy widget of the product detail page. To do this, we will create a new template override in the `[app_root]/Resources/views/storefront/component/buy-widget/buy-widget.html.twig` file.

```twig
{# [app_root]/Resources/views/storefront/component/buy-widget/buy-widget.html.twig #}
{% sw_extends '@Storefront/storefront/component/buy-widget/buy-widget.html.twig' %}

{% block buy_widget %}
	{{ parent() }}
	{% if context.customer %}
		<template data-stock-check>
			<h3>Available Stock</h3>
			<!-- An empty list ready for Stock Items to be injected -->
			<ul class="product-stock__list">
				<!-- stock items will be rendered via JavaScript here! -->
				<li class="product-stock__item"></li>
			</ul>
		</template>
	{% endif %}
{% endblock %}
```

You can see that the template has the attribute `data-stock-check`. To make use of this `<template>` element, we turn back to the `main.js` file we created in the previous learning unit.

The `PluginManager.register()` method accepts a third parameter, which is expected to be a CSS selector. This tells Shopware where in the DOM the plugin should attach. In our case, we use the attribute selector `[data-stock-check]`.

```js
// <plugin root>/src/Resources/app/storefront/src/main.js
// Import all necessary Storefront plugins
import StockCheck from './stock-check/stock-check.plugin.js';

// Register your plugin via the existing PluginManager
const PluginManager = window.PluginManager;
PluginManager.register('StockCheck', StockCheck, '[data-stock-check]');
```

By specifying this third parameter in the registration of our plugin, we achieved two things:

- The plugin will only be loaded when an element with the attribute `[data-stock-check]` exists on the current page (lazy-loading).
- The plugin will automatically have access to that element via the special property **`this.el`**. This lets you work directly with the corresponding `template` element.

## Accessing the DOM via `this.el`

By adding the `[data-stock-check]` selector in our `main.js`, the `StockCheck` plugin gets a new ability! It automatically knows which element it should attach to. This element is available inside the plugin through the special property `this.el`. We can confirm this by using the browsers DevTools (either [Google Chrome](https://developer.chrome.com/docs/devtools) or [Mozilla Firefox](https://firefox-source-docs.mozilla.org/devtools-user/) are recommended). On a [Product Detail Page](https://developer.shopware.com/frontends/getting-started/e-commerce/product-detail-page.html), the element `template data-stock-check` should appear right below the Product Number.

![Product Number element](assets/product-number-highlight.png)

To check this:

1. Open a Product Detail Page.
2. Right-click the Product Number and select 'Inspect' to open DevTools.

Within DevTools, you should now see the `<template data-stock-check>` element below the `.product-detail-ordernumber` element.

![Devtools Inspector template element](assets/devtools-inspect-template.png)

Finally, let's verify that the plugin is really attached to this element. Open the browser console and run the following command:

```js
window.PluginManager.getPlugin('StockCheck');
```

If everything works, you will see that the `StockCheck` plugin is loaded and has a property called `el`, which refers to the `template` element we added.

![Javascript Console Plugin data](assets/inspector-plugin-el.png)

As you can see from the screenshot above, the `StockCheck` plugin is loaded on the page, and has a property called `el`, which refers to the `<template>` element we defined in our override.

### Troubleshooting

#### The Twig Template Is Not Showing Up

**1. Ensure, you ran App Update after all template changes**: After creating or changing a Template Override, you need to update the App System by run the following command

```bash
bin/console app:refresh
```

<Callout title="Memory Leaks?" type="info">

For additional guidance, refer back to the [course introduction](/learn/unit/the-manifest-file#versioningyourapp).

</Callout>

**2. The storefront override path is incorrect**: In our example, the override starts with:

```twig
{% sw_extends '@Storefront/storefront/component/buy-widget/buy-widget.html.twig' %}
```

If this path is incorrect, the page will throw an error when loading.

![Rendering error](assets/twig-template-error.png)

#### Loading the Storefront Plugin

**Double-Check the CSS selector**: The plugin only loads if the matching element exists on the page. Make sure the template is defined correctly:

```html
<template data-stock-check>
```

And make sure that in your `main.js` file the third parameter is set correctly (remember the square brackets):

```js
'[data-stock-check]'
```

## Populating Template Content

The next step is to render this data in the storefront. Since your plugin is attached to the `template` element, we can use `this.el.content` to access and clone its contents.

Let's add a new method called `displayStockData()` to handle this:

```js
const { PluginBaseClass } = window;
import AppClient from 'src/service/app-client.service.ts';

export default class StockCheck extends PluginBaseClass {
    ...
    displayStockData() {
      if (!this.stockData) {
        return;
      }
  
      // Check for the parent node which will hold the elements we want to create
      const buyBox = document.querySelector('.cms-element-buy-box');
      if (!buyBox) {
        return;
      }
  
      // Get the template node contents and make a copy
      const contentClone = this.el.content.cloneNode(true);
  
      // Set up any nodes and variables we will want to use when iterating the stock data
      const stockList = contentClone.querySelector('.product-stock__list');
      const stockItem = contentClone.querySelector('.product-stock__item');
      stockItem.classList.add('product-stock__item');
  
      // Loop through the stock data and input relevant information into the appropriate node
      for (const stockInfo of this.stockData) {
        const newStockItem = this.generateStockCheckRow(
          stockItem.cloneNode(),
          stockInfo.name,
          stockInfo.country,
          stockInfo.stockQuantity
        );
        stockList.appendChild(newStockItem);
      }
  
      // remove initial template li
      stockItem.remove();
      // Inject the final result into the buy-box
      buyBox.appendChild(stockList);
    }
  
    generateStockCheckRow(target, left = 'Name', middle = 'Country', right = 'Quantity') {
      const rowLeft = document.createElement('strong');
      const rowMiddle = document.createElement('p');
      const rowRight = document.createElement('span');
  
      rowLeft.textContent   = left;
      rowMiddle.textContent = "Country: " + middle;
      rowRight.textContent  = "Quantity: " + right;
  
      target.appendChild(rowLeft);
      target.appendChild(rowMiddle);
      target.appendChild(rowRight);
  
      return target;
    }
}
```

### Code Explanation

Let's see what happens step by step:

1. **Check for data**: If there is no stock data, the method exits early. Note that this approach is a good practical usage.
2. **Find the injection point**: We locate the `.cms-element-buy-box` node, which will hold the stock list.
3. **Clone the template**: We make a copy of the `template` content so we can safely modify it.
4. **Populate items**: For each stock entry, we create:
	1. A heading with the shop name.
	2. A paragraph with the shop address.
	3. A span with the available quantity.
5. **Finalize and inject**: We remove the initial placeholder and append the finished list to the buy box.

### Running the Plugin

Now, rebuild the storefront. Go to your Shopware Root directory and run the following command:

```bash
bin/build-storefront.sh
```

Reload the Product Detail Page and you should see the following result:

![Product Detail stock list](assets/rendered-app-server-data.png)

## Code-Along (end)

To see what the final result of this learning unit should look like, run the following command:

```bash
git checkout tags/plugin_rendering--end
```

<Callout title="Removing Working Changes" type="warning">

If you have local changes, you will need to run `git reset --hard HEAD` in the App directory. Be mindful that this command will destroy any local changes!

</Callout>

## Summary

In the final learning unit, you learned how to inject App Server data into the DOM using storefront plugins. Specifically, you now know how to:

- Use a **`template` element** as a placeholder for dynamic content
- **Attach** a **storefront plugin** to a **DOM** element using a **CSS selector**
- **Access** the injection point via **`this.el`**
- Populate and **render** the content of the **`template`** element with the data from the App Server

**Well done** on completing **App Development Essentials** learning path! You now have the foundation to build secure and interactive Apps with Shopware.
