Aurelia for new developers
If you're new to Aurelia or perhaps development in general, we've got you.
Last updated
Was this helpful?
If you're new to Aurelia or perhaps development in general, we've got you.
Last updated
Was this helpful?
Aurelia stands out from other frameworks and libraries by allowing you to model your entire application using plain Javascript. It's one of those things that's best understood through experience, so let's dive in.
We'll start by replacing the App class that comes with the skeleton you created in the section.
Picture this: our todo application is essentially a list of tasks. Users can add new todos by typing a description and removing them. Once a todo is added, the input field clears automatically and is ready for the next entry. Simple, right?
Let's take these concepts and turn them into code. Aurelia's approach makes this process intuitive and straightforward.
Let's review the ideas we modelled:
Our application has a heading
of "Todos".
The todo list is modelled as an array of todo instances represented by the todos
property.
Todo instances can be added (addTodo
) or removed (removeTodo
).
When a new todo is added, it is given a description, and the done flag defaults to false.
After adding a new todo, the todoDescription
is cleared to enable the next addition.
Here's what's amazing. This is all the code for the app. But where is Aurelia? Well, the answer is that Aurelia tries as hard as possible to stay out of your code. That's why you don't see it above. It's not needed. Aurelia can render plain objects.
Let's recap what we've covered so far. You might be surprised to learn that most of our work isn't Aurelia-specific. The bulk of our code is just plain vanilla Javascript/TypeScript.
We've got our src/main.ts
file, which serves as the entry point for our app. By convention, it typically uses src/app.ts
as the root UI component. To dive deeper into this, check out our docs' App Configuration and Startup section.
Now, let's talk about rendering. To bring our app component to life, we need to create a view for it. This is where we introduce another Aurelia convention. Creating a view for any class is straightforward: create an HTML file with the same name as your TypeScript module, but swap out the file extension for .html.
Inside this view, you can set up an HTML template. This is where the magic happens - you can use data-binding expressions to specify how the view should render an instance of your class.
Let's start simple. We're going to create a basic view for our app. Open up the src/app.html
file the skeleton provided, and we'll overwrite it with our code.
There are a couple of things to notice here. First, all views are wrapped in an template
element. Second, did you notice the ${heading}
syntax? Well, inside a view, you have access to all the properties and methods of the class instance associated with that View, and you can access them inside the content of any element or attribute by using the TypeScript template string syntax as shown above. The above syntax creates a one-way data-binding to the heading
property. By "one-way", we mean that the dataflow is unidirectional, and only changes to the heading
property will affect the view. There is no "reverse" flow from the view back to the view-model.
Run au run --open
if you haven't done that. When you run the app, you should see the app render out the heading
property, something like this:
Rendering properties in HTML seems simple enough, but what about working with user input? Let's add some markup that enables us to take input from the user to create our todos:
Let's look at the form we've just added to our view. This form is designed to gather the todo name from the user. Notice the input element – we've used the .bind
syntax on its value attribute. This is Aurelia's way of creating a connection between the input's value and the todoDescription
property in our view-model. It's a neat trick that allows you to bind any HTML attribute to your view model using a simple property expression.
It's worth pointing out a clever convention Aurelia uses here. When you use .bind
, Aurelia automatically chooses the most appropriate "binding mode" based on the element and attribute you're working with. In this case, Aurelia sets up a two-way binding since we're dealing with an input's value. Any changes to todoDescription
in the view-model will update the input's value, and vice versa.
You'll also spot another binding: disabled.bind="!todoDescription"
. This one-way binding disables the button when todoDescription
is empty. Unlike the input's value, there's no need for user input to sync back here, hence the one-way nature.
But wait, there's more. Aurelia doesn't just let you bind properties – you can also hook into events. Check out the form element. By appending .trigger
to any DOM event, you're telling Aurelia to evaluate the associated expression when that event fires. In our case, the submit event triggers the addTodo()
method. This setup means users can add a todo by clicking the submit button or pressing enter while focused on the input. It's pretty handy, right?
If you run the app now, you should see something like this:
Try typing into the input box and adding the todo. You should notice that the input box gets cleared out each time you do that. The reason for this is that the value
of the input
has two-way binding, and our original code cleared out the todoDescription
after adding a new todo instance. Here's our addTodo()
implementation for reference:
We can now add todos, but we can't see them. Let's remedy that by looking at how Aurelia handles lists of data. Change your markup to match this new version:
When working with Arrays, Maps, or Sets in Aurelia, we use the repeat.for="local of collection"
syntax to generate HTML. This syntax is inspired by Javascript's for...of loop, making it intuitive for developers familiar with the language.
Let's break down the example above. We want to create an li
element for each item in our todos
array. To achieve this, we add a repeat.for
attribute to the li
element we want to replicate. We specify the todos
collection and choose a name for our local loop variable – in this case, todo
.
With this setup, we can easily bind to any property of the todo
instance. We're applying the same techniques we discussed earlier: binding the checked
attribute to the todo's done
property and injecting the description
property into the span
's content.
We've also added a click event trigger on the button to remove the todo. You'll notice that removeTodo
is still in scope. Like in Javascript, variables from the outer block remain accessible inside a loop. This allows us to call the removeTodo
method on the App class, passing in the specific todo instance we want to remove.
This approach gives us a powerful and flexible way to generate dynamic content based on our data collections while maintaining clean and readable code.
If you run the application again, you should now see something like this:
We're on the home stretch now, but we've overlooked one small detail. You might have noticed that checking and unchecking the boxes does not provide visual feedback. That's not ideal for user experience, is it?
How about we add a little flair by crossing out the todo item when it's checked? This way, users can easily see which tasks they've completed. Let's make one last tweak to our view to incorporate this feature:
This example demonstrates direct CSS binding on HTML elements, showcasing the versatility of Aurelia's ${}
syntax within attributes. We apply a line-through text decoration when a todo item is marked as done, otherwise leaving it undecorated. This simple technique allows for dynamic styling based on your data's state.
Run the application one more time and you should see the expected result:
Aurelia prioritizes developer experience, making application creation both powerful and enjoyable. Our simple conventions minimize configuration and boilerplate code, freeing you from framework constraints. Aurelia's pluggable and customizable design ensures flexibility, while its seamless integration lets you focus on writing plain Javascript and TypeScript without constant framework awareness.
We encourage you to explore our Contact Manager Tutorial next. It demonstrates how to set up a production-grade project using the Aurelia CLI and introduces advanced features like routing, publish/subscribe, and custom elements.
We're looking forward to seeing what you create!