RealWorld App with OWL (Odoo Web Library) - Part 1
Tags: owl, javascript, odoo
Published: 2021-06-07 03:44:32

---
title: RealWorld App with OWL (Odoo Web Library) - Part 1
published: true
date: 2021-05-31 00:54:00 UTC
tags: OWL,JavaScript,Odoo
canonical_url: https://codingdodo.com/realworld-app-with-owl-odoo-web-library-part-1/
---

 ![RealWorld App with OWL (Odoo Web Library) - Part 1](https://codingdodo.com/content/images/2021/05/post-cover-owl.png)

In this series, we will create the famous "RealWorld App" from scratch. With OWL (Odoo Web Library) 🦉 as the FrontEnd of choice.

## What is the RealWorld App?

The RealWorld App is a Medium.com clone called Conduit built with several technologies on the FrontEnd and BackEnd.

The final result of this 4 parts tutorial [series can be seen here](https://owl-realworld.netlify.app/) it is hosted on Netlify.

The RealWorld App repository is a set of specs describing this "Conduit" app, how to create it on the front-end, and on the back-end:

{% github gothinkster/realworld %}

In our Tutorial, we will implement the front-end part. Following the [FRONTEND Instructions specs defined here](https://github.com/gothinkster/realworld-starter-kit/blob/master/FRONTEND_INSTRUCTIONS.md), we will use the brand new [OWL](https://github.com/odoo/owl) (Odoo Web Library) as the technology choice. This is a SPA with calls to an external API, so it will be a good starting point to see a lot of what the Framework has to offer in terms of state management, routing, and reactivity.

Styles and HTML templates are available in the repository and the routing structure of the client-side is described like that:


- Home page (URL: /#/ )
  - List of tags
  - List of articles pulled from either Feed, Global, or by Tag
  - Pagination for list of articles
- Sign in/Sign up pages (URL: /#/login, /#/register )
  - Uses JWT (store the token in localStorage)
  - Authentication can be easily switched to session/cookie-based
- Settings page (URL: /#/settings )
- Editor page to create/edit articles (URL: /#/editor, /#/editor/article-slug-here )
- Article page (URL: /#/article/article-slug-here )
  - Delete article button (only shown to article's author)
  - Render markdown from server client-side
  - The comments section at bottom of the page
  - Delete comment button (only shown to comment's author)
- Profile page (URL: /#/profile/:username, /#/profile/:username/favorites )
  - Show basic user info
  - List of articles populated from author's created articles or author's favorited articles


## Introducing OWL Framework(Odoo Web Library)

OWL is a new open-source Framework created internally at Odoo with the goal to be used as a replacement to the current old client-side technology used by Odoo. According to the repository description:

> The Odoo Web Library (OWL) is a relatively small UI framework intended to be the basis for the [Odoo](https://www.odoo.com/) Web Client in future versions (>15). Owl is a modern framework, written in Typescript, taking the best ideas from React and Vue in a simple and consistent way.

The Framework offers a declarative component system, reactivity with hooks (See React inspiration), a Store (mix between Vue and React implementation), and a front-end router.

The [documentation](https://github.com/odoo/owl/blob/master/doc/learning/overview.md) is not exhaustive for now, but we will try to make sense of everything via use-cases.

### Components

Components are JavaScript classes with properties, functions and the ability to render themselves (Insert or Update themselves into the HTML Dom). Each Component has a template that represents its final HTML structure, with composition, we can call other components with their tag name inside our Component.

```javascript
class MagicButton extends Component {
  static template = xml`
    <button t-on-click="changeText">
      Click Me! [<t t-esc="state.value"/>]
    </button>`;

  state = { value: 0 };

  changeText() {
    this.state.value = "This is Magic";
    this.render();
  }
}
```

The templating system is in XML QWeb, which should be familiar if you are an Odoo Developer. `t-on-click` allow us to listen to the click event on the button and trigger a function defined inside the Component called `changeText`.

Properties of the Component live inside the `state` property, it is an object that has all the keys/value we need. This state is isolated and only lives inside **that Component, it is not shared with other Components (even if they are copies of that one).**

Inside that `changeText` function we change the `state.value` to update the text, then we call `render` to force the update of the Component display: the Button shown in the Browser now has the text "Click Me! This is Magic".

### Hooks and reactivity

It is not very convenient to use `render` function all the time and to handle reactivity better, OWL uses a system its system of hooks, specifically the `useState` hook.

```javascript
const { useState } = owl.hooks;

class MagicButton extends Component {
  static template = xml`
    <button t-on-click="changeText">
      Click Me! [<t t-esc="state.value"/>]
    </button>`;

  state = useState({ value: 0 });

  changeText() {
    this.state.value = "This is Magic";
  }
}
```

As we can see, we don't have to call the `render` function anymore. Using the `useState` hook actually tells the OWL `Observer` to watch for change inside the state via the native `Proxy` Object.

### Passing data from Parent to Child via props

We saw that a Component can have multiple Components inside itself. With this Parent/Child hierarchy, data can be passed via **props.** For example, if we wanted the initial text "Click me" of our MagicButton to be dynamic and chosen from the Parent we can modify it like that

```javascript
const { useState } = owl.hooks;

class MagicButton extends Component {
  static template = xml`
    <button t-on-click="changeText">
      <t t-esc="props.initialText"/> [<t t-esc="state.value"/>]
    </button>`;

  state = useState({ value: 0 });

  changeText() {
    this.state.value = "This is Magic";
  }
}

// And then inside a parent Component
class Parent extends Component {
  static template = xml`
<div>
    <MagicButton initialText="Dont click me!"/>
</div>`;
  static components = { MagicButton };
```

And that's it for a quick overview of the Framework, we will dive into other features via examples. From now on it's better if you follow along with your own repository so we create the RealWorld App together!

## Starting our project

### Prerequisites

Make sure that you have NodeJS installed. I use [NVM (Node Version Manager)](https://github.com/nvm-sh/nvm) to handle different NodeJS versions on my system.

Follow the NVM [install instructions here](https://github.com/nvm-sh/nvm#installing-and-updating) or install directly the following NodeJS version on your system.

For this tutorial, I'm using NodeJS v14.15.1

```shell
▶ nvm list
       v10.22.0
       v10.24.0
        v14.7.0
-> v14.15.1
default -> 10 (-> v10.24.0)
node -> stable (-> v14.15.1) (default)
stable -> 14.15 (-> v14.15.1) (default)
```

### Using the OWL starter template

To make things a little easier, I've created a template project with Rollup as the bundling system to help us begin with modern JavaScript convention and bundling systems.

{% github Coding-Dodo/OWL-JavaScript-Project-Starter %}

This is a template repo, so click on " **Use this template"** to create your own repo based on this one (You can also clone it like other repositories).

After pulling the repository we have this file structure:

```shell
├── README.md
├── package-lock.json
├── package.json
├── public
│   └── index.html
├── rollup.config.js
├── src
│   ├── App.js
│   ├── components
│   │   └── MyComponent.js
│   └── main.js
└── tests
    ├── components
    │   └── App.test.js
    └── helpers.js
```

Index.html is a basic HTML file containing minimum info, we will use the `<head>` tag to insert the Stylesheet given by the RealWorld app later.

The core of our app lives in the `src` folder, for now, it only contains 2 files. `main.js` is the **entry point** :

```javascript
import { App } from "./app";
import { utils } from "@odoo/owl";

(async () => {
  const app = new App();
  await utils.whenReady();
  await app.mount(document.body);
})();
```

In this file, we import our main **App Component** , that we mount on the `<body>`tag of our index.html file.

Owl components are defined with [ES6 (JavaScript - EcmaScript 20015)](https://www.w3schools.com/js/js_es6.asp) classes, they use QWeb templates, a virtual DOM to handle reactivity, and asynchronous rendering. Knowing that we simply instantiate our App object.

As its name may suggest `utils` package contains various utilities, here we use `whenReady` that tells us when the DOM is totally loaded so we can attach our component to the body.

#### App Component

The App Class Component represents our application, it will inject all other Components.

```javascript
import { Component, tags } from "@odoo/owl";
import { MyComponent } from "./components/MyComponent";

const APP_TEMPLATE = tags.xml/*xml*/ `
<main t-name="App" class="" t-on-click="update">
  <MyComponent/>
</main>
`;

export class App extends Component {
  static template = APP_TEMPLATE;
  static components = { MyComponent };
}
```

MyComponent is a basic Component representing a span, when you click on it the text change. It's only here as an example and we will delete it later.

### Installing dependencies and running the dev server.

First, we need to install the dependencies

```shell
cd OWL-JavaScript-Project-Starter
npm install
```

Then, to run the tests

```shell
npm run test
```

And finally, to run the development server

```shell
npm run dev
```

The output should be:

```shell
rollup v2.48.0
bundles src/main.js → dist/bundle.js...
http://localhost:8080 -> /Users/codingdodo/Code/owl-realworld-app/dist
http://localhost:8080 -> /Users/codingdodo/Code/owl-realworld-app/public
LiveReload enabled
created dist/bundle.js in 608ms

[2021-05-20 14:33:10] waiting for changes...
```

![RealWorld App with OWL (Odoo Web Library) - Part 1](https://codingdodo.com/content/images/2021/05/OWL-Hello-world-app.png)<figcaption>OWL Hello World App is running on localhost:8080</figcaption>

If you would prefer to run the server on a different port you have to edit `rollup.config.js` and search for the `serve` section

```javascript
serve({
    open: false,
    verbose: true,
    contentBase: ["dist", "public"],
    host: "localhost",
    port: 8080, // Change Port here
}),
```

### Importing styles from RealWorld App resources kit.

We will update  `public/index.html` to include `<link>` to assets given by RealWorld App repository instructions. These assets include the **font, the icons, and the CSS:**

```html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>RealWorld App in OWL</title>
    <!-- Import Ionicon icons & Google Fonts our Bootstrap theme relies on -->
    <link
      href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://fonts.googleapis.com/css?family=Titillium+Web:700|Source+Serif+Pro:400,700|Merriweather+Sans:400,700|Source+Sans+Pro:400,300,600,700,300italic,400italic,600italic,700italic"
      rel="stylesheet"
      type="text/css"
    />
    <!-- Import the custom Bootstrap 4 theme from our hosted CDN -->
    <link rel="stylesheet" href="https://demo.productionready.io/main.css" />
    <script type="module" src="bundle.js"></script>
  </head>
  <body></body>
</html>
```

Navigating to [http://localhost:8080/](http://localhost:8080/) should already show you the change of fonts.

## Implementing the elements of the layout as Components.

The **Conduit** App has a classic design layout, composed of **a Navbar Header, Content, and Footer.**

For now, we will implement the Homepage and the different elements of the Layout as simple HTML content ("dumb" Components, with no logic).

### Creating the Navbar Component

Inside `src/components/` we will create a new file named `Navbar.js`

```javascript
import { Component, tags } from "@odoo/owl";

const NAVBAR_TEMPLATE = tags.xml/*xml*/ `
<nav class="navbar navbar-light">
    <div class="container">
        <a class="navbar-brand" href="index.html">conduit</a>
        <ul class="nav navbar-nav pull-xs-right">
            <li class="nav-item">
                <!-- Add "active" class when you're on that page" -->
                <a class="nav-link active" href="">Home</a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="">
                    <i class="ion-compose"></i> New Post
                </a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="">
                    <i class="ion-gear-a"></i> Settings
                </a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="">Sign in</a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="">Sign up</a>
            </li>
        </ul>
    </div>
</nav>
`;
export class Navbar extends Component {
  static template = NAVBAR_TEMPLATE;
}
```

The **template** is defined as a `const NAVBAR_TEMPLATE` then added as a **static property** to our `Navbar` Component declaration.

The content of the template is surrounded by _`tags.xml/*xml*/`._ These `xml`comments are used so TextEditor extensions that handle **Comment tagged templates** can be used to have syntax highlight inside our components. For [VisualStudio Code the plugin is here](https://marketplace.visualstudio.com/items?itemName=bierner.comment-tagged-templates).

For the XML content itself, it is just copy-pasted from the **instructions on** the RealWorld Repo. We will not implement Navigation just yet.

### Creating the Footer Component

Inside `src/components/` we will create a new file named `Footer.js`

```javascript
import { Component, tags } from "@odoo/owl";

const FOOTER_TEMPLATE = tags.xml/*xml*/ `
<footer>
    <div class="container">
        <a href="/" class="logo-font">conduit</a>
        <span class="attribution">
            An interactive learning project from <a href="https://thinkster.io">Thinkster</a>. Code &amp; design licensed under MIT.
        </span>
    </div>
</footer>
`;
export class Footer extends Component {
  static template = FOOTER_TEMPLATE;
}

```

### Creating the Home Page Component

This component will hold the content of the Home page.

In this tutorial, we will create a new folder `src/pages/` that will hold our "pages" Components. This is an architecture decision that you don't have to follow, but as the number of components will start to grow we would ultimately want to do some cleaning to keep things organized.

With the folder created, inside `src/pages/`, we will create a new file named `Home.js`, (full structure):

```javascript
import { Component, tags, useState } from "@odoo/owl";

const HOME_TEMPLATE = tags.xml/*xml*/ `
<div class="home-page">

    <div class="banner" t-on-click="update">
        <div class="container">
            <h1 class="logo-font">conduit</h1>
            <p><t t-esc="state.text"/></p>
        </div>
    </div>

    <div class="container page">
        <div class="row">
            <div class="col-md-9">
                <div class="feed-toggle">
                    <ul class="nav nav-pills outline-active">
                        <li class="nav-item">
                            <a class="nav-link disabled" href="">Your Feed</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link active" href="">Global Feed</a>
                        </li>
                    </ul>
                </div>

                <div class="article-preview">
                    <div class="article-meta">
                        <a href="profile.html"><img src="http://i.imgur.com/Qr71crq.jpg" /></a>
                        <div class="info">
                            <a href="" class="author">Eric Simons</a>
                            <span class="date">January 20th</span>
                        </div>
                        <button class="btn btn-outline-primary btn-sm pull-xs-right">
                            <i class="ion-heart"></i> 29
                        </button>
                    </div>
                    <a href="" class="preview-link">
                        <h1>How to build webapps that scale</h1>
                        <p>This is the description for the post.</p>
                        <span>Read more...</span>
                    </a>
                </div>
                <div class="article-preview">
                    <div class="article-meta">
                    <a href="profile.html"><img src="http://i.imgur.com/N4VcUeJ.jpg" /></a>
                    <div class="info">
                        <a href="" class="author">Albert Pai</a>
                        <span class="date">January 20th</span>
                    </div>
                    <button class="btn btn-outline-primary btn-sm pull-xs-right">
                        <i class="ion-heart"></i> 32
                    </button>
                    </div>
                    <a href="" class="preview-link">
                    <h1>The song you won't ever stop singing. No matter how hard you try.</h1>
                    <p>This is the description for the post.</p>
                    <span>Read more...</span>
                    </a>
                </div>
            </div>

            <div class="col-md-3">
                <div class="sidebar">
                    <p>Popular Tags</p>

                    <div class="tag-list">
                        <a href="" class="tag-pill tag-default">programming</a>
                        <a href="" class="tag-pill tag-default">javascript</a>
                        <a href="" class="tag-pill tag-default">emberjs</a>
                        <a href="" class="tag-pill tag-default">angularjs</a>
                        <a href="" class="tag-pill tag-default">react</a>
                        <a href="" class="tag-pill tag-default">mean</a>
                        <a href="" class="tag-pill tag-default">node</a>
                        <a href="" class="tag-pill tag-default">rails</a>
                    </div>
                </div>
            </div>
        </div>
    </div>

</div>

`;
export class Home extends Component {
  static template = HOME_TEMPLATE;
  state = useState({ text: "A place to share your knowledge." });
  updateBanner() {
    this.state.text =
      this.state.text === "A place to share your knowledge."
        ? "An OWL (Odoo Web Library) RealWorld App"
        : "A place to share your knowledge.";
  }
}

```

Since we will delete `./components/MyComponent` we will inject some logic inside this Home Component to test if the framework reactivity is working.

We registered a click event on the banner to fire the `updateBanner` function:

```xml
<div class="banner" t-on-click="update">
    <div class="container">
        <h1 class="logo-font">conduit</h1>
        <p><t t-esc="state.text"/></p>
    </div>
</div>
```

Inside the Component definition, we created the `updateBanner` function:

```javascript
  updateBanner() {
    this.state.text =
      this.state.text === "A place to share your knowledge."
        ? "An OWL (Odoo Web Library) RealWorld App"
        : "A place to share your knowledge.";
  }
```

**So every time the user clicks on the banner, the message will change.**

### Injecting our components into the main App Component

Now we need to make use of these fine Components. To do so, open the `src/components/App.js` file and use these Components.

```javascript
import { Component, tags } from "@odoo/owl";
import { Navbar } from "./components/Navbar";
import { Footer } from "./components/Footer";
import { Home } from "./pages/Home";

const APP_TEMPLATE = tags.xml/*xml*/ `
<main>
  <Navbar/>
  <Home/>
  <Footer/>
</main>
`;

export class App extends Component {
  static components = { Navbar, Footer, Home };
  static template = APP_TEMPLATE;
}

```

First, we **imported** the different components/pages like `import { Navbar } from "./Navbar";`, etc... We use destructuring to get Navbar as a class from the file it is exported and the path of the file is relative (same folder) with the use of `./`.

Inside the **class App,** we filled the **static property** `components` to "register" what components `App` will need to render itself.

Finally, in the XML template, we called these Components as if they were HTML elements with the same name as the ones defined in the `static components` property.

Our App template now reflects what the basic layout of the website is:

```xml
<main>
  <Navbar/>
  <Home/>
  <Footer/>
</main>
```

### Update the tests to check that everything is working correctly.

Inside the `./tests/components/App.test.js` we will update the logic to test the reactivity of our Home Component and the presence of Navbar and Footer.

```javascript
describe("App", () => {
  test("Works as expected...", async () => {
    await mount(App, { target: fixture });
    expect(fixture.innerHTML).toContain("nav");
    expect(fixture.innerHTML).toContain("footer");
    expect(fixture.innerHTML).toContain("A place to share your knowledge.");
    click(fixture, "div.banner");
    await nextTick();
    expect(fixture.innerHTML).toContain(
      "An OWL (Odoo Web Library) RealWorld App"
    );
  });
});
```

Run the tests with the command:

```shell
npm run test
```

The tests should pass

```shell
> jest
 PASS tests/components/App.test.js

Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.628 s
Ran all test suites.
```

## Implementing the different Pages Components of the App.

We will create each of the pages corresponding to the specs as components. There is the HomePage, Settings, LogIn, Register, Editor (New article), and Profile pages.

### Settings Page

```javascript
import { Component, tags, hooks } from "@odoo/owl";
const { xml } = tags;

const SETTINGS_TEMPLATE = xml/* xml */ `
<div class="settings-page">
  <div class="container page">
    <div class="row">

      <div class="col-md-6 offset-md-3 col-xs-12">
        <h1 class="text-xs-center">Your Settings</h1>
        <form>
          <fieldset>
              <fieldset class="form-group">
                <input class="form-control" type="text" placeholder="URL of profile picture"/>
              </fieldset>
              <fieldset class="form-group">
                <input class="form-control form-control-lg" type="text" placeholder="Your Name"/>
              </fieldset>
              <fieldset class="form-group">
                <textarea class="form-control form-control-lg" rows="8" placeholder="Short bio about you"></textarea>
              </fieldset>
              <fieldset class="form-group">
                <input class="form-control form-control-lg" type="text" placeholder="Email"/>
              </fieldset>
              <fieldset class="form-group">
                <input class="form-control form-control-lg" type="password" placeholder="Password"/>
              </fieldset>
              <button class="btn btn-lg btn-primary pull-xs-right">
                Update Settings
              </button>
          </fieldset>
        </form>
        <hr/>
        <button class="btn btn-outline-danger">Or click here to logout.</button>
      </div>

    </div>
  </div>
</div>
`;

export class Settings extends Component {
  static template = SETTINGS_TEMPLATE;
}

```
<figcaption>./src/pages/Settings.js</figcaption>

### LogIn Page

```javascript
import { Component, tags } from "@odoo/owl";
const { xml } = tags;

const LOG_IN_TEMPLATE = xml/* xml */ `
<div class="auth-page">
  <div class="container page">
    <div class="row">

      <div class="col-md-6 offset-md-3 col-xs-12">
        <h1 class="text-xs-center">Sign in</h1>
        <p class="text-xs-center">
          <a href="#register">Need an account?</a>
        </p>

        <ul class="error-messages">
          <li>Invalid credentials</li>
        </ul>

        <form>
          <fieldset class="form-group">
            <input class="form-control form-control-lg" type="text" placeholder="Email"/>
          </fieldset>
          <fieldset class="form-group">
            <input class="form-control form-control-lg" type="password" placeholder="Password"/>
          </fieldset>
          <button class="btn btn-lg btn-primary pull-xs-right">
            Sign In
          </button>
        </form>
      </div>

    </div>
  </div>
</div>
`;
export class LogIn extends Component {
  static template = LOG_IN_TEMPLATE;
}

```
<figcaption>./src/pages/LogIn.js</figcaption>

### Register Page

```javascript
import { Component, tags } from "@odoo/owl";
const { xml } = tags;

const REGISTER_TEMPLATE = xml/* xml */ `
<div class="auth-page">
  <div class="container page">
    <div class="row">

      <div class="col-md-6 offset-md-3 col-xs-12">
        <h1 class="text-xs-center">Sign up</h1>
        <p class="text-xs-center">
          <a href="#login">Have an account?</a>
        </p>

        <ul class="error-messages">
          <li>That email is already taken</li>
        </ul>

        <form>
          <fieldset class="form-group">
            <input class="form-control form-control-lg" type="text" placeholder="Your Name"/>
          </fieldset>
          <fieldset class="form-group">
            <input class="form-control form-control-lg" type="text" placeholder="Email"/>
          </fieldset>
          <fieldset class="form-group">
            <input class="form-control form-control-lg" type="password" placeholder="Password"/>
          </fieldset>
          <button class="btn btn-lg btn-primary pull-xs-right">
            Sign up
          </button>
        </form>
      </div>

    </div>
  </div>
</div>
`;
export class Register extends Component {
  static template = REGISTER_TEMPLATE;
}

```
<figcaption>./src/pages/Register.js</figcaption>

### Profile Page

```javascript
import { Component, tags } from "@odoo/owl";
const { xml } = tags;

const PROFILE_TEMPLATE = xml/* xml */ `
<div class="profile-page">
    <div class="user-info">
        <div class="container">
            <div class="row">

            <div class="col-xs-12 col-md-10 offset-md-1">
                <img src="http://i.imgur.com/Qr71crq.jpg" class="user-img" />
                <h4>Eric Simons</h4>
                <p>
                Cofounder @GoThinkster, lived in Aol's HQ for a few months, kinda looks like Peeta from the Hunger Games
                </p>
                <button class="btn btn-sm btn-outline-secondary action-btn">
                <i class="ion-plus-round"></i> Follow Eric Simons 
                </button>
            </div>

            </div>
        </div>
    </div>

    <div class="container">
    <div class="row">

        <div class="col-xs-12 col-md-10 offset-md-1">
        <div class="articles-toggle">
            <ul class="nav nav-pills outline-active">
            <li class="nav-item">
                <a class="nav-link active" href="">My Articles</a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="">Favorited Articles</a>
            </li>
            </ul>
        </div>

        <div class="article-preview">
            <div class="article-meta">
            <a href=""><img src="http://i.imgur.com/Qr71crq.jpg" /></a>
            <div class="info">
                <a href="" class="author">Eric Simons</a>
                <span class="date">January 20th</span>
            </div>
            <button class="btn btn-outline-primary btn-sm pull-xs-right">
                <i class="ion-heart"></i> 29
            </button>
            </div>
            <a href="" class="preview-link">
            <h1>How to build webapps that scale</h1>
            <p>This is the description for the post.</p>
            <span>Read more...</span>
            </a>
        </div>

        <div class="article-preview">
            <div class="article-meta">
            <a href=""><img src="http://i.imgur.com/N4VcUeJ.jpg" /></a>
            <div class="info">
                <a href="" class="author">Albert Pai</a>
                <span class="date">January 20th</span>
            </div>
            <button class="btn btn-outline-primary btn-sm pull-xs-right">
                <i class="ion-heart"></i> 32
            </button>
            </div>
            <a href="" class="preview-link">
            <h1>The song you won't ever stop singing. No matter how hard you try.</h1>
            <p>This is the description for the post.</p>
            <span>Read more...</span>
            <ul class="tag-list">
                <li class="tag-default tag-pill tag-outline">Music</li>
                <li class="tag-default tag-pill tag-outline">Song</li>
            </ul>
            </a>
        </div>
        </div>
    </div>
    </div>
</div>
`;

export class Profile extends Component {
  static template = PROFILE_TEMPLATE;
}

```
<figcaption>./src/pages/Profile.js</figcaption>

### Editor Page

```javascript
import { Component, tags } from "@odoo/owl";
const { xml } = tags;

const EDITOR_TEMPLATE = xml/* xml */ `
<div class="editor-page">
  <div class="container page">
    <div class="row">

      <div class="col-md-10 offset-md-1 col-xs-12">
        <form>
          <fieldset>
            <fieldset class="form-group">
                <input type="text" class="form-control form-control-lg" placeholder="Article Title"/>
            </fieldset>
            <fieldset class="form-group">
                <input type="text" class="form-control" placeholder="What's this article about?"/>
            </fieldset>
            <fieldset class="form-group">
                <textarea class="form-control" rows="8" placeholder="Write your article (in markdown)"></textarea>
            </fieldset>
            <fieldset class="form-group">
                <input type="text" class="form-control" placeholder="Enter tags"/><div class="tag-list"></div>
            </fieldset>
            <button class="btn btn-lg pull-xs-right btn-primary" type="button">
                Publish Article
            </button>
          </fieldset>
        </form>
      </div>

    </div>
  </div>
</div>
`;
export class Editor extends Component {
  static template = EDITOR_TEMPLATE;
}

```
<figcaption>./src/pages/Editor.js</figcaption>

Now that all our pages are created we will now handle the routing and navigation between them.

## OWL Router to the rescue

To handle Single Page Applications most of the modern frameworks have a router. OWL is no different.

### Creating the routes and adding the router to the env

The router in OWL is an object that has to be instantiated and "attached" to the **`env`** of our main App.

Env is an environment is an object which contains a QWeb instance. Whenever a root component is created, it is assigned an environment. This environment is then automatically given to all child components (and accessible in the this.env property).

A router can run in **hash** or **history\_mode**. Here we will use the **hash** mode because the expected result for RealWorld App is URLs like `/#/profile` `/#/settings`, etc. The router will also handle direct, programmatically **navigation/redirection** , navigation guards, to protect some routes behind conditions, and routes also accept parameters. [_Official documentation of OWL router_](https://github.com/odoo/owl/blob/master/doc/reference/router.md)_._

To instantiate an OWL router we need an environment and a list of routes.

Inside `./src/main.js` we will create our Router. We will have to import `router, QWeb` from the `@odoo/owl`.

```javascript
import { App } from "./App";
import { utils, router, QWeb } from "@odoo/owl";
```

Before we import each of our pages Components we will create a new file  `./pages/index.js` that will handle all the import/export of the classes so we can import every Component needed in one line later.

```javascript
import { LogIn } from "./LogIn";
import { Register } from "./Register";
import { Home } from "./Home";
import { Settings } from "./Settings";
import { Editor } from "./Editor";
import { Profile } from "./Profile";

export { LogIn, Register, Home, Settings, Editor, Profile };

```


Then back inside our `./src/main.js` we can import all the pages and declare the routes that adhere to the specifications of the RealWorld App. These routes have an internal name, a path (without the #), and an associated Component.

```javascript
import { LogIn, Register, Home, Settings, Editor, Profile } from "./pages";

export const ROUTES = [
  { name: "HOME", path: "/", component: Home },
  { name: "LOG_IN", path: "/login", component: LogIn },
  { name: "REGISTER", path: "/register", component: Register },
  { name: "SETTINGS", path: "/settings", component: Settings },
  { name: "EDITOR", path: "/editor", component: Editor },
  { name: "PROFILE", path: "/profile/@{{username}}", component: Profile },
];
```

Then we will create our environment and attach the router to it inside a function called `makeEnvironement`

```javascript
async function makeEnvironment() {
  const env = { qweb: new QWeb() };
  env.router = new router.Router(env, ROUTES, { mode: "hash" });
  await env.router.start();
  return env;
}
```

**This is our final `App.js` Component**

```javascript
import { App } from "./App";
import { utils, router, mount, QWeb } from "@odoo/owl";
import { LogIn, Register, Home, Settings, Editor, Profile } from "./pages";

export const ROUTES = [
  { name: "HOME", path: "/", component: Home },
  { name: "LOG_IN", path: "/login", component: LogIn },
  { name: "REGISTER", path: "/register", component: Register },
  { name: "SETTINGS", path: "/settings", component: Settings },
  { name: "EDITOR", path: "/editor", component: Editor },
  { name: "PROFILE", path: "/profile", component: Profile },
];

async function makeEnvironment() {
  const env = { qweb: new QWeb() };
  env.router = new router.Router(env, ROUTES, { mode: "hash" });
  await env.router.start();
  return env;
}

async function setup() {
  App.env = await makeEnvironment();
  mount(App, { target: document.body });
}

utils.whenReady(setup);

```

### Using `<RouteComponent/>`.

Now that our routes are registered we will update our App Component to make use of the OWL `<RouteComponent/>`. Inside "./src/App.js":

```javascript
import { Component, tags, router } from "@odoo/owl";
import { Navbar } from "./components/Navbar";
import { Footer } from "./components/Footer";
import { Home } from "./pages/Home";
const RouteComponent = router.RouteComponent;

const APP_TEMPLATE = tags.xml/*xml*/ `
<main>
  <Navbar/>
  <RouteComponent/>
  <Footer/>
</main>
`;

export class App extends Component {
  static components = { Navbar, Footer, Home, RouteComponent };
  static template = APP_TEMPLATE;
}

```

What we did here is import the RouteComponent from the router package in `@odoo/owl`. Then register the RouteComponent inside the `static components` property and then add it **inside the template.**

Directly trying [http://localhost:8080/#/settings](http://localhost:8080/#/settings) in your browser will show you the setting page!

### Adding the `<Link>` Components to handle navigation.

`<Link>` is an OWL Component that has a prop, (Attribute that you can pass directly to the Component from the Template and the value is scoped to inside that Component), named `to` that navigate to the route name.

Inside `./src/components/Navbar.js` let's import `Link` Component and transform our `<a href></a>` to `<Link to="">` Components

```javascript
import { Component, tags, router } from "@odoo/owl";
const Link = router.Link;

const NAVBAR_TEMPLATE = tags.xml/*xml*/ `
<nav class="navbar navbar-light">
    <div class="container">
        <!-- <a class="navbar-brand" href="index.html">conduit</a> -->
        <Link to="'HOME'" class="navbar-brand">conduit</Link>
        <ul class="nav navbar-nav pull-xs-right">
            <li class="nav-item">
                <!-- Add "active" class when you're on that page" -->
                <Link to="'HOME'" class="nav-link">Home</Link>
            </li>
            <li class="nav-item">
                <Link to="'EDITOR'" class="nav-link"><i class="ion-compose"></i> New Post</Link>
            </li>
            <li class="nav-item">
                <Link to="'SETTINGS'" class="nav-link"><i class="ion-gear-a"></i> Settings</Link>
            </li>
            <li class="nav-item">
                <Link to="'LOG_IN'" class="nav-link">Sign in</Link>
            </li>
            <li class="nav-item">
                <Link to="'REGISTER'" class="nav-link">Sign up</Link>
            </li>
            <li class="nav-item">
                <Link to="'PROFILE'" class="nav-link">Coding Dodo</Link>
            </li>
        </ul>
    </div>
</nav>
`;
export class Navbar extends Component {
  static template = NAVBAR_TEMPLATE;
  static components = { Link };
}

```

We can see that `class` is also passed to the `<Link/>` Component as a prop, the end result is an "href" with the class that was given to the prop.

Going to [http://localhost:8080/#/](http://localhost:8080/#/) we can see that our **navigation is working!**

But there is a little problem with the styles, the original `<Link/>` Component applies a class of `router-active` to the "href" if the route corresponds to that link. But our style guide uses the `active` class directly.

### Creating our custom NavbarLink component via inheritance.

To handle that problem will create our own Custom NavbarLink component in `./src/components/NavbarLink.js`

```javascript
import { tags, router } from "@odoo/owl";
const Link = router.Link;
const { xml } = tags;

const LINK_TEMPLATE = xml/* xml */ `
<a t-att-class="{'active': isActive }"
    t-att-href="href"
    t-on-click="navigate">
    <t t-slot="default"/>
</a>
`;
export class NavbarLink extends Link {
  static template = LINK_TEMPLATE;
}

```

As you can see we inherit the base Link Component class and just define another Template that is slightly different.

Then inside our **Navbar.js component** we update our imports, components and replace the `<Link>` with our own `<NavbarLink>`:

```javascript
import { Component, tags, router } from "@odoo/owl";
const Link = router.Link;
import { NavbarLink } from "./NavbarLink";

const NAVBAR_TEMPLATE = tags.xml/*xml*/ `
<nav class="navbar navbar-light">
    <div class="container">
        <!-- <a class="navbar-brand" href="index.html">conduit</a> -->
        <Link to="'HOME'" class="navbar-brand">conduit</Link>
        <ul class="nav navbar-nav pull-xs-right">
            <li class="nav-item">
                <!-- Add "active" class when you're on that page" -->
                <NavbarLink to="'HOME'" class="nav-link">Home</NavbarLink>
            </li>
            <li class="nav-item">
                <NavbarLink to="'EDITOR'" class="nav-link"><i class="ion-compose"></i> New Post</NavbarLink>
            </li>
            <li class="nav-item">
                <NavbarLink to="'SETTINGS'" class="nav-link"><i class="ion-gear-a"></i> Settings</NavbarLink>
            </li>
            <li class="nav-item">
                <NavbarLink to="'LOG_IN'" class="nav-link">Sign in</NavbarLink>
            </li>
            <li class="nav-item">
                <NavbarLink to="'REGISTER'" class="nav-link">Sign up</NavbarLink>
            </li>
            <li class="nav-item">
                <NavbarLink to="'PROFILE'" class="nav-link">Coding Dodo</NavbarLink>
            </li>
        </ul>
    </div>
</nav>
`;
export class Navbar extends Component {
  static template = NAVBAR_TEMPLATE;
  static components = { Link, NavbarLink };
}

```

## Conclusion

Ending this first part of the tutorial, we have a functional, albeit basic, routing system. Each of the pages has been created statically (no dynamic data inside) for now.

The source code for [this part of the tutorial is available here.](https://github.com/Coding-Dodo/owl-realworld-app/tree/feature/basic-pages-structure-routing) To directly clone that branch (that part of the tutorial):

```
git clone -b feature/basic-pages-structure-routing https://github.com/Coding-Dodo/owl-realworld-app.git
```

In the next part, we will tackle:

- authentication/registration 
- Using the **OWL Store** to get info of the currently logged-in user. 
- With that, we will add conditionals to our template to show the correct links if the user is logged in or not.

Thanks for reading and consider [becoming a member](https://codingdodo.com/signup/) to stay updated when the next part comes out!

[Part 2 of this tutorial is available here.](https://codingdodo.com/realworld-app-with-owl-odoo-web-library-part-2/)

[![RealWorld App with OWL (Odoo Web Library) - Part 1](https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png)](https://www.buymeacoffee.com/CodingDodo)