In part one of the Book information example we added our product information to a bag using virtual files. At the end of the article we show that you can also create html files using epsilon functions. However, this is not the most flexible way of creating a website-in-a-bag. Instead, let's look at how this can be done using Vue.js.

This article assumes minimal knowledge of Vue.js. Reading through the first page of their getting started guide will get you up-to-speed.

In Vue.js the templating language is fairly similar to what we did using plain JavaScript in part one. Our card now looks as follows:

<card>
 <img v-bind:src="content.thumbnail"/>
 <cardcaption>
    <h4>{{ content.name }}</h4>
    <h5>{{ content.subtitle }}</h5>
    <div class="quote">
      <p>{{ content.description }}</p>
    </div>
  </cardcaption>
</card>

Next, let's see how we can download our book data from the bag. This can be done using the Bridge and ZAZA SDK. We use Bridge.View.getId() to get the QID of the active page. Next, we use it to create a Zaza.View object. The View object lets us interact with the data in the bag. It has a method downloadJSON that helps us to download a json file from the bag and turn it into a JavaScript object, called bookInfo in this case.

let viewId = await Bridge.View.getId();
let view = new Zaza.View(viewId);

let bookInfo = await view.downloadJSON("book.json");
// Do something with bookInfo

Finally, let's bring these pieces together into a Vue.js app. One thing we have to take into account is the delay between opening the page and receiving the book information. Therefore, we add a loading step. Our final Vue.js app definition looks as follows:

let app = new Vue({ 
    el: '#app',
    data: {
        isLoading: true,
        content: undefined
    },
    async mounted() {
        let viewId = await Bridge.View.getId();
        let view = new Zaza.View(viewId);
        
        this.content = await view.downloadJSON("book.json");
        this.isLoading = false;
    }
});

The accompanying index.html page looks as follows:

<!DOCTYPE html>
<html lang="en">
<head>    
    <link rel="stylesheet" href="styles.css">
   
<script src="/sdk/v1/zaza-sdk/zaza.js"></script>
<script src="/sdk/v1/bridge/bridge.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <div v-if="isLoading">
            <h2>Loading...</h2>
        </div>
        <div v-if="!isLoading">
            <card>
                <img v-bind:src="content.thumbnail"/>
                <cardcaption>
                    <h4>{{ content.name }}</h4>
                    <h5>{{ content.subtitle }}</h5>
                    <div class="quote">
                        <p>{{ content.description }}</p>
                    </div>
                </cardcaption>
            </card>
        </div>
    </div>
    <script src="index.js"></script>
</body>
</html>

The content of styles.css is left as an exercise for the reader.
Finally, we put all the pieces in a bag, together with an autorun file:

If we open the download link we get the same result as in part one:

Now you may be thinking: Why go through all this trouble to get the same result as in part one? Dynamic websites, such as the one we just build, enable more then just displaying product information. For example we can let the user upload files or ask for their valuable for feedback. The template described above provides a good foundation for your solution to grow together with your business requirements.

In part 3 of this series we'll look at adding our own data using structured data.

Did this answer your question?