First Project: A simple web app

This article is a step by step guide to create a simple web app using Live Elements.

Basic Setup

To get up and running fast, we're going to use lvweb to generate a starting project template. lvweb is a tool found in live-elements-web-cli package, which can be installed using npm, either locally, in a new folder:

npm i live-elements-web-cli

Or globally:

npm i -g live-elements-web-cli

Note: The installation page offers more information if you have trouble installing lvweb or want other options.

In this guide we're going to use lvweb locally, so we will start by creating an empty folder for the project:

mkdir quickstart
cd quickstart

Then we install lvweb, and use it to initialize a new project:

npm i live-elements-web-cli
lvweb init

This will generate a package.json file with all of the dependencies, together with all the source files needed for the initial project. We will need to install the dependencies in the generated package.json:

npm i

And run the project:

lvweb serve

Now, navigating with a browser to http://localhost:8080, we should see the following message:

Welcome to Live Elements

To understand what's happening behind the scenes, we first need to look at the project structure.

Basic file structure

The following structure has been setup by lvweb:

 |-- live.package.json
 |-- package.json
 |-- app
 |   |-- Home.lv
 |-- bundle
 |   |-- bundle.lv
 |-- styles
 |   |-- style.css

Within the root, there are 2 files:

  • live.package.json describes a live elements package. It includes the name and version of this package.
  • package.jsonis the npm file that describes this package. It has been configured with the name of the folder, and initialized with all the required dependencies to run this project

And 4 folders:

  • app contains files for the front-end application run on the client side.
  • bundle contains the bundle file interpreted by the server in order to create routes, manage assets, styles, and other things.
  • styles contains the css files for the application.
  • buildis generated by the live elements compiler, and contains all the compiled .lv files.

app/Home.lv file

This is the file that renders the index page:

import live-web.dom
import live-elements-web-server.view

component Home < PageView{

    head: PageProperties{
        title: "Live Elements"
        StyleLink{ href: '/styles/style.css' }
    }

    H1`Welcome to Live Elements!`
}

The file defines the Home component, inheriting from PageView:

component Home < PageView{}

The head property manages the page <head> section. This is where we set the title of the page, and add a style link:

head: PageProperties{
    title: "Live Elements"
    StyleLink{ href: '/styles/style.css' }
}

The content is a simple heading, equivalent to the html code:

<h1>Welcome to Live Elements!</h1>

bundle/bundle.lv file

This is the file run by the server:

import live-elements-web-server.bundle
import live-elements-web-server.router
import live-elements-web-server.style
import .app

instance bundle Bundle{
    ViewRoute{ url: '/' c: Home }
    Stylesheet{ src: './styles/style.css' output: 'style.css' }
}

The file exports a bundle object, with the following 2 elements:

  • ViewRoute sets up the Home component at the index / route.Home is imported from the app folder, using the import: import .app. Imports in Live Elements from the same package start with the dot (.) notation.
  • Stylesheet defines a source style in ./styles/style.css. The path is relative from the root of the package. The output property sets the name of the style to be made available inside the styles route. Since the output is style.css, the style will be available at /styles/style.css.

For this guide, we won't need to configure anything on the server side, so we will go back to the Home file.

Modifying the application

Let's start by adding a paragraph to our homepage. In html, this would be the <p> tag, which is equivalent to P in Live Elements. The PageView allows only a single root element, so we will have to explicitly define Body this time:

import live-web.dom
import live-elements-web-server.view

component Home < PageView{

    head: PageProperties{
        title: "Live Elements"
        StyleLink{ href: '/styles/style.css' }
    }

    Body{
        H1`Welcome to Live Elements!`
        P`This is a paragraph.`
    }
}

If lvweb serve is running, the page should refresh automatically after saving the file. Otherwise, you will have to start lvweb again.

You might not see any changes when reloading the page, and that's because of the used stylesheet. Since we will be creating a new application, we can remove everything in the style/style.css file, and just leave a simple body:

body{
    font-family: Arial, Helvetica, sans-serif; 
    font-size: 20px; 
    color: black; 
    margin: 0px; 
    padding: 0px; 
}

The paragraph should now be visible.

To make things more interactive, let's add a button:

import live-web.dom
import live-elements-web-server.view

component Home < PageView{

    head: PageProperties{
        title: "Live Elements"
        StyleLink{ href: '/styles/style.css' }
    }

    Body{
        H1`Welcome to Live Elements!`
        P`This is a paragraph.`
        Button{ T`Clickable` }
    }
}

We can alert a message when the button is clicked using the on click event:

import live-web.dom
import live-elements-web-server.view

component Home < PageView{

    head: PageProperties{
        title: "Live Elements"
        StyleLink{ href: '/styles/style.css' }
    }

    Body{
        H1`Welcome to Live Elements!`
        P`This is a paragraph.`
        Button{ 
            on click: () => { alert('Button clicked.') }
            T`Clickable`
        }
    }
}

To interact with other elements, we can reference them using their id. In the example below, the paragraph has a background color, which will change once the button is clicked:

import live-web.dom
import live-elements-web-server.view

component Home < PageView{

    head: PageProperties{
        title: "Live Elements"
        StyleLink{ href: '/styles/style.css' }
    }

    Body{
        H1`Welcome to Live Elements!`
        P{ 
            id: paragraph
            style = { backgroundColor: 'green' }
            T`This is a paragraph.`
        }
        Button{ 
            on click: () => { paragraph.style = { backgroundColor: 'red' } }
            T`Clickable` 
        }
    }
}

Creating a simple To-Do list

From the changes we made so far, it's quite easy to go for something more practical, like the classical todo list:

import live-web.dom
import live-elements-web-server.view

component Home < PageView{

    head: PageProperties{
        title: "Live Elements"
        StyleLink{ href: '/styles/style.css' }
    }

    Body{
        Ul{
            id: todoList
            Li{ 
                T`Buy Groceries`
                Button{ 
                    on click: () => { todoList.children = todoList.children.filter(v => v != this.parent) }
                    T`x` 
                }
            }
            Li{ 
                T`Visit North Pole`
                Button{ 
                    on click: () => { todoList.children = todoList.children.filter(v => v != this.parent) }; 
                    T`x` 
                }
            }
        }
        P{
            Input{ id: newItem; type: 'text'; value: '' }
            Button{  
                on click: () => {
                    let li = Li{ 
                        T.(newItem.currentValue){}
                        Button{ 
                            on click: () => { todoList.children = todoList.children.filter(v => v != this.parent) }
                            T`x` 
                        }
                    }
                    todoList.children = todoList.children.concat([li])
                    newItem.value = ''
                }
                T`+` 
            }
        }
    }
}

We've used Ul and Li, which get converted into the html <ul> and <li> tags. For each Li, or list item, there's a delete button, that removes the item from the list when clicked.

Below the list, theres an input and a button, which will create create a new list item from the value inside Input.

Creating reusable components

The list items in the code can be wrapped by a component to not repeat the same structure throghout the list. The component will need a label property, which is the value to be displayed in the list.

import live-web
import live-web.dom

component TodoListItem < Li{
    id: todoListItem
    string label: ''

    T{ text: parent.label }
    Button{ 
        on click: () => { 
            todoListItem.parent.children = todoListItem.parent.children.filter(v => v != todoListItem) 
        }; 
        T`x` 
    }
}
 
instance app Application{
    render: Div{
        Ul{
            id: todoList
            TodoListItem{ label: 'Buy Groceries' }
            TodoListItem{ label: 'Visit North Pole' }
        }
        P{
            Input{ id: newItem; type: 'text'; value: '' }
            Button{  
                on click: () => {
                    let value = newItem.currentValue
                    let li = TodoListItem{ label: value } 
                    todoList.children = todoList.children.concat([li])
                }
                T`+` 
            }
        }
    }
}

TodoListItem is a new component that declares a label property. It inherits from Li, so everywhere it's created, it will create the Li tag. It has 2 children, a text (T) node, and a button (Button) node. When the Button is clicked, it will delete the current item from the Li parent.TodoListItem is then reused by creating the object, and assigning a label: TodoListItem{ label: 'Item Label' }.

Styling the Todolist

To wrap up, we're going to apply the following styles to our todolist:

body{ 
    font-family: Arial, Helvetica, sans-serif; 
    font-size: 20px; 
    color: black; 
    margin: 0px; 
    padding: 0px; 
}
ul{ 
    list-style-type: none;
    max-width: 400px;
    margin: 100px auto 10px auto;
    border: 1px solid #ccc;
    border-radius: 20px;
    padding: 0px;
}
ul li{ 
    border-bottom: 1px solid #ccc;
    margin: 20px;
    padding: 10px;
}
li button{ 
    float: right;
}
p{ 
    max-width: 400px; 
    height: 40px; 
    margin: 10px auto 10px auto; 
    border-radius: 10px; 
    border: 1px solid #ccc; 
    padding: 15px 0px; 
}
p input{ 
    margin-left: 15px; 
    width: 300px; 
    height: 25px; 
    font-family: Arial, Helvetica, sans-serif; 
    font-size: 20px;
}
p button{
    height: 25px;
    width: 25px;
    float: right;
    margin-right: 20px;
}

The style should apply once you save the file.

Wrapping up

We now have a simple Live Elements application up and running. For more lessons, and a deeper dive into the language there are more tutorials available in the tutorials section.