Fork me on GitHub

Keeping up with the standard lib

Mobl develops rapidly. Especially the mobl standard library is expanding (and fixing bugs) quickly. As a mobl developer, how do you keep up? There are two ways:

  • Upgrade with new releases. Every release comes packed with the latest version of the standard library.
  • Live on the bleeding edge. By cloning the standard library using git.

Releases are frequent, but not as frequent as fixes to the standard library. Therefore, real mobl developers live on the bleeding edge ;) . Here’s how. Basic knowledge of how to use git is assumed.

Step 1: Clone the mobl-lib repo

The first step is to clone the mobl-lib repository from GitHub as follows:

git clone git://github.com/mobl/mobl-lib.git

This copies the sources of the entire mobl standard library into the mobl-lib/ directory. This does not only set you up with the very latest version, it is also…

  • a great way to explore what is available already. Just look through the sources to see what controls, functions etc. are available.
  • puts you on the fast track to contributing back to mobl. Add your own functionality to the mobl library, commit them to your personal fork and send us a fork request!

Step 2: Set the stdlib option in your config.mobl

If you didn’t have one already, create a config.mobl file for your project (this is a special file that is used to configure various aspects of your application). Use the stdlib option to override the default (plug-in) path of the standard library to use. For instance:

configuration
stdlib /Users/zef/git/mobl-lib

You should use an absolute path here and only Unix-style paths are supported. Windows users, your mobl-lib clone should be on the same drive as your project, if it is located on c:\git\mobl-lib, using stdlib /git/mobl-lib should work.

Step 3: Go!

That’s it. Your application will now use the git-cloned version of the standard library. Just in case you can remove your project’s www/ directory (a refresh may be required first), make a little change in your application’s main .mobl file and save it. This will trigger a complete recompile.

Step 4: Keeping up

To pull updates to the standard library, simply cd into the repository directory and:

git pull origin master

to pull in the latest updates.

1 Comment more...

Version 0.3.2

Version 0.3.2 of mobl has been released. Mobl is a language for rapid development of mobile web applications using HTML5 technologies. Programs written in the mobl language are compiled to a combination of HTML, Javascript and CSS and can run on any webkit browser, specifically those on iOS and Android devices.

New in this version compared to 0.3.1:

  • itemArrow control has been removed, the arrow is rendered for when the item control has an onclick handler.
  • Bug fixes related to auto updating of UI related to search collections (Entity.searchPrefix())
  • Runtime fixes.

To install, follow these instructions. To upgrade, simply upgrade from the update site.

1 Comment more...

Styling User Interfaces

Moved to here.


Reducing the Pain: Synchronous Asynchronous Programming

Although non-mobile-web-developers may not realize, there is one “feature” of Javascript that causes a lot of pain to Javascript every day — although they may deny it, a case of Stockholm Syndrome, me thinks. That pain point is called asynchronous programming.

Here’s the problem.

Javascript in the browser does not support threads. All the rendering of the page and the Javascript logic that has to be executed shares a single thread. That is OK as long as you do simple things. Simple DOM manipulations, input field validation and so on.

But what if you need to do things that could take a while, say, talk to a database, send an HTTP request to the server — what happens then? In typical synchronous style programming such a HTTP request could look as follows:

var content = fetchURL('http://www.yahoo.com');
processContent(content);

However, fetching the URL could take seconds. Due to the unthreaded nature of this environment, the browser could not do anything during those few seconds because the thread is blocked, resulting in a browser freeze. Bad idea. What can we do about this?

AJAX: Asynchronous Javascript and XML

The idea is to, rather than a blocking, we make a call that returns immediately. When the request finishes, a callback function is called. The request itself is performed on a separate thread (yes, a browser does keep a thread pool for asynchronous actions, but it is not directly accessible for the developer). So, what does that look like?

fetchURLAsync('http://www.yahoo.com',
              function(content) {
  processContent(content);
});

In addition to the regular arguments, an asynchronous function is also passed a callback function, that takes the result of the computation as an argument. The function is called whenever the fetching of the URL has finished, and in the mean time continues executing other code.

Pretty nice solution, right?

It does lead to code that is harder to read, however. In synchronous style programming, we’re used to having code execute from top to bottom. For instance:

var content = fetchURL('http://www.yahoo.com');
processContent(content);
sayHello();

First we fetch the URL, then we process it, then we say hello. Now consider this asynchronous code:

fetchURLAsync('http://www.yahoo.com',
              function(content) {
  processContent(content);
});
sayHello();

Naively this could be read as (top to bottom): first we fetch the URL, then we process the content and then we say hello. However, this is almost certainly not the order in which these statements will be executed. The likely execution order will be: first the url fetch request is sent off, then we say hello and then we process the content.

It gets worse when you try to do loops with asynchronous calls. Let’s say you would like to fetch URLs contained in some array sequentially (one after the other) and then say hello. In the synchronous style you would write the following:

for(var i = 0; i < ar.length; i++) {
  var content = fetchURL(ar[i]);
  processContent(content);
}
sayHello()

Now, how do we do this in an asynchronous style? We may try to do this:

for(var i = 0; i < ar.length; i++) {
  fetchURL(ar[i], function(content) {
    processContent(content);
  });
}
sayHello();

But that’s not going to work. First of all, URLs would now be fetched in parallel (which is kind of cool actually, but not what we wanted) and second, the hello’ing happens too early, not after we’re done with the fetching. What we would need to do is something like this:

ar.reverse(); 
function done() {
   sayHello();
}
function fetchOne() {
  var url = ar.pop();
  fetchURL(ar[i], function(content) {
    processContent(content);
    if(ar.length === 0) {
      done();
    } else {
      fetchOne();
    }
  });
}
if(ar.length === 0) {
  done();
} else {
  fetchOne();
}

Ouch! The idea here is to use the array as a stack. We define a function that processes one URL. The function pops an element off the array, fetches the URL and when done processes it, it checks if the stack is empty, if so, it says hello (done function), if not, it recursively calls itself to process the next element (the new top) in the array.

Luckily, this type of code can be wrapped in a nicer looking API, which allows you to rewrite this code as:

asyncForEach(ar, function(url, callback) {
  fetchURL(ar[i], function(content) {
    processContent(content);
    callback();
  });
}, function() {
  sayHello();
});

But still, wouldn’t you prefer the synchronous version?

Enter mobl

Even though mobl compiles down to Javascript, you do not have to do this style of asynchronous programming. Why? Because the compiler is able to automatically transform synchronous style programs into asynchronous style programs. Yes. Automatically, the compiler does exactly what I just did by hand.

Mobl libraries wrap asynchronous Javascript APIs as synchronous APIs. A simple example. How do you sleep in a Javascript program for 1 second. There’s no sleep function, and even if there would be, it would block the thread and render the browser unusable. If you want something to happen in about 1 second, what you do is you use Javscript’s setTimeout, right?

setTimeout(function() {
  alert('1 second passed!');
}, 1000);

As you can tell, this is another example of an asynchronous call. Here’s what that code looks like in mobl:

sleep(1000);
alert("1 second passed!");

Let’s have a look at the signature of sleep in the mobl standard library:

external function sleep(ms : Num) : void

This signature tells us two things:

  1. There is a function named sleep that takes a single (numeric) argument and returns nothing (void).
  2. This function is asynchronous.

Every external function is assumed to be asynchronous unless stated otherwise (using the sync keyword, e.g. external sync function). Being asynchronous means that in addition to the arguments specified in the signature, a callback function is provided that is to be called when the function completes.

This signature by itself does not do anything, it just tells the mobl compiler that “there exists a function with this name in this module”. The compiler then assumes there’s a definition for it elsewhere, in this case in native Javascript:

<javascript>
__ns.sleep = function(ms, callback) {
  setTimeout(callback, ms);
};
</javascript>

Mobl enables you to include fragments of “native” Javascript in-between <javascript> tags. __ns is a reference to the module’s namespace object. If a function, control or screen is defined in a module it is not put in a global scope, but in a module object named after the module. For instance for the mobl module this object is named mobl, for mobl::ui::generic it’s mobl.ui.generic, a reference to the object can be obtained using the __ns shortcut.

The implementation of sleep takes, as predicted, two arguments: the number of milliseconds to wait, and what to do next (a callback function). It basically delegates this call directly to setTimeout, just switching the argument order.

Alright, so what happens when we call sleep from mobl? What is the Javascript code generated by the following mobl code?

sleep(1000);
alert("1 second passed!");

Cleaned-up a little bit, the resulting Javascript looks as follows:

mobl.sleep(1000, function() {
  mobl.alert("1 second passed!");
});

The transformation performed by the compiler here is called the continuation-passing style transformation, a pretty well-known transformation in academia, although not often applied outside languages like Scheme.

Thanks to the CPS transform, mobl code can be written in a synchronous style, while still maintaining the advantages of asynchronous code, i.e. being non-blocking. One drawback is that writing code that requires concurrent execution — for instance, fetching all the URLs at the same time — is more difficult to express. Mobl does have the async block for this purpose, which conceptually executes its body “on a different thread of execution”, i.e. the code after it can run in parallel with the code inside it:

async {
  sleep(1000);
  alert("I'm last");
}
alert("I'm first!");

Excited? Learn more about mobl.


Higher-Order Controls: Do More With Less

In the previous tutorial we built a todo list manager. In this tutorial we’ll continue improving that application by using a few higher-level controls.

A higher-level control is a control that takes other controls as arguments.

Say what?

We’re going to add new functionality to our task manager, while reducing the amount of lines of code. How does that sound? Here’s screenshots of the end result, both on iPhone and iPad:

The last screenshots shows the same screen as the first one. However, as you can see, it automatically adapts to the fact that the screen is wider. The iPad version shows the list of tasks to the left and details immediately at the right, whereas with the narrow (iPhone) version, details appear on a separate screen when the task is selected.

Tabs

The original version of our todo list application had a single screen of tasks, and a button to move to a separate “Search” screen. Kind of silly, isn’t it? Wouldn’t it be nicer to have a tabbed screen, one showing all tasks, and a second that had the search functionality? (One could argue it would be nice to have everything integrated, but for the purpose of this exercise, let’s not.)

In order to do that, we have to make a few changes. First, we’re going to rename our root screen, and turn it into a control. So, we change our root screen:

screen root() {
  ...
}

Into:

control tasks() {
  ...
}

Now we’ll do the same thing to the search screen, we’ll turn this screen into a control:

screen search() {
  header("Search") {
    backButton()
  }
  var phrase = ""
  ...
}

Becomes:

control search() {
  header("Search")
  var phrase = ""
  ...
}

We changed screen into control and removed the backButton, because we won’t use it anymore. The IDE will now complain about the missing root screen, so let’s define a new one:

screen root() {
  tabSet([("Tasks", "", tasks),
          ("Search", "", search)])
}

So, what does that do? It uses the tabSet control to build a tab set. The tabSet control takes a single argument: an array of tuples. A tuple could be described as an array with a fixed length. Mobl’s syntax to create arrays, as you can tell, is [item1, item2] and its syntax to create tuples is (item1, item2). Each tuple in this array represents a single tab:

  • The first element of the tuple is the tab’s title
  • The second an URL to an icon (not used, at the moment)
  • The third is the control to use as the body of the tab.

Yes, you can pass a control as an argument to another control. Controls that use this functionality are called higher-order controls. So, what happens after making these minor changes? Go look for yourself.

A nicely tabbed interface. That wasn’t so hard. Let’s see if we can use some more of these higher-order controls.

Task details

Let’s define a control that gives some details about a single task:

control taskDetail(t : Task) {
  group {
    item { label(t.name) }
    when(t.description) {
      item { label(t.description) }
    }
    item { label(t.date.toDateString()) } 
    item {
      label(t.done ? "This task has been performed"
                   : "This task hasn't been performed")
    }
  }
  button("Edit", onclick={ editTask(t); })
}

This control uses two mobl language features we haven’t seen before:

  • The when construct, which conditionally shows its body elements (somewhat like an if-statement). Yes, it does have an optional else clause.
  • The ternary e1 ? e2 : e3 operator, which is like an if-expression. If e1 is true, the return e2, else return e3.

In this particular application, such a detail control is not extremely useful, but typically applications do often have more information to display than fits a list view.

We’re going to use this taskDetail control in combination with the masterDetail control. Wikipedia defines the master-detail user interface pattern as follows:

In computer user interface design, a master-detail page is one where a master area and its related detail area are represented on the same page. The content of the detail area is displayed based on the current record selection in the master area.

This UI pattern works great on larger screens (say, tablets), but not so much on smaller screens (say, phones). Therefore, the mobl::ui::generic library contains two implementations of masterDetail:

  1. One for screen widths <= 500 pixels. This version initially only renders a list view. Then, when the user selects an item from the list, it shows its details view on a separate screen (with a “Back” button to return).
  2. One for screen widths > 500 pixels. This version shows the list of items along the left side of the screen, and the details of the currently selected item directly to the right.

The “right” version of the controls is picked at run-time, automatically. Let’s see how we use it. Replace the tasks control with the following implementation:

control tasks() {
  header("Tasks") {
    button("Add", onclick={ addTask(); })
  }
  masterDetail(Task.all() order by date desc,
               taskItem, taskDetail)
}

Compared to the previous version, we now removed the group control that was there before with the masterDetail control. As you can see, masterDetail takes three arguments:

  1. A collection of items to show the master-detail view for.
  2. A control taking a single argument (an item from the collection) to use in the list view.
  3. A control taking a single argument (again, an item from the collection) to use in the detail view.

The result looks as follows on phones:

And as follows on tablets:

Pretty nice huh, those higher-level controls? One more? Alright, because you insist.

Searching

Replace your current search control with the following:

control search() {
  header("Search")
  searchList(Task, taskItem, taskDetail,
                             resultLimit=10)
}

That’s right. There’s a searchList control — very similar to the masterDetail control — that automatically creates a standard search for you. It takes three required and one optional argument:

  1. An entity type
  2. A control taking a single argument (an item from the collection) to use in the list view.
  3. A control taking a single argument (again, an item from the collection) to use in the detail view.
  4. A maximum number of search results to show (defaults to 10)

And voila, the new search screen:

Conclusion

Higher-order controls are controls that take other controls as arguments. They enable the implementation of controls such as tab sets, master-detail and search lists (and more to come), greatly reducing the amount of code you need to write to build your applications.


Version 0.3.1

Version 0.3.1 of mobl has been released. Mobl is a language for rapid development of mobile web applications using HTML5 technologies. Programs written in the mobl language are compiled to a combination of HTML, Javascript and CSS and can run on any webkit browser, specifically those on iOS and Android devices.

New in this version compared to 0.3.0:

  • Bug fixes
  • Code completion and checks for styling
  • Fix of contextMenu control

To install, follow these instructions. To upgrade, simply upgrade from the update site.

1 Comment more...

Todo List

The previous tutorial taught the bare basics of creating user interfaces using mobl. This next tutorial will focus on two additional aspects of building mobl applications:

  • Data modeling (using a database)
  • Application logic (scripting)

To keep it simple, we’ll be constructing a todo list application. Here’s what the end result will look like:

Click here to see it in action (Webkit-based browser required, e.g. Safari, Chrome, iOS or Android browser).

So, let’s started, shall we?

Divide and conquer

In the previous tutorial we put our entire application in a single file. That clearly won’t scale. In a larger project we’d like to divide our applications into multiple modules. And luckily, mobl allows you to do so. In mobl there are three kinds of modules:

  • Application modules, which start with application <app-name>. These are required to have a root screen, and in addition to being compiled to Javascript, a HTML file is also generated for application modules. One mobl project can have multiple application modules, although typically, there’s only one.
  • Configuration module, named config.mobl and starts with configuration. This module defines some application configuration, such as the application’s title, database name and so on.
  • Regular modules, which start with module <module-name>. These are typically imported from an application module or from other modules. Just like application modules they can define new controls, screens, functions etc.

Data model

Create a new mobl project called “todo”. The todo.mobl application module is now automatically generated. We could define our data model directly in this file, but instead, we’re going to define it a dedicated data model module. Right-click your project, pick “New” and then “File”. Name the file model.mobl. Copy the following code into it:

module model
entity Task {
  name        : String (searchable)
  description : String (searchable)
  done        : Bool
  date        : DateTime
}

Every module starts with the keyword module, followed by the name of the module, which has to match its filename. This module contains a single definition, an entity definition. Entities are used to define your application’s data model — the types of objects that your application will deal with that need to be persisted to the mobile device’s local database. In mobl there are two kinds of types:

  • entity types, for which mobl handles persistency fully automatically: it creates tables in the database and it ensure that changes make to these objects are automatically saved.
  • regular types, which are volatile in-memory types, whose values are lost when the application is shut down.

The model module defines a single entity named Task. Task has four properties: name, description, done and date. name and description are textual properties (of type String). done keeps track of whether the task has been completed or not — a boolean (true or false) value. date is used to keep track of when the task was added. Entity properties can have annotations, which are enumerated in-between parentheses. The name and description properties have been annotated with a searchable annotation, which makes them full-text searchable. We’ll see how to use that ability later in this tutorial.

Save the module and switch back to your main application file (todo.mobl). Import the module there:

import model

Save the application. When running the application for the first in the browser, it will create a local database on the device. It is recommended to use a webkit-based desktop browser during development. For instance, Safari or Chrome. When your application is loaded you can see the database tables that have been created using your browser’s developer tools. In Chrome you can access these using the “Developer”, “Developer Tools” menu. In Safari using the “Develop” menu, “Show error console”. Chrome and Safari’s developer tools look similar and consist of a number of tabs:

The two most useful ones during mobl development are the “Storage” and “Console” tabs. “Storage” shows you your local databases, its tables and data. In this case you’ll see it contains two tables, one for Task objects and one table for keeping the full-text search index. The “Console” tab shows you all kinds of error messages and logging information if you enabled the debug setting in your config.mobl file as follows:

configuration
debug
title "Todo"

Remember to force a recompile of your main application after creating or changing your config.mobl file (by inserting a newline or space somewhere and saving the main application file), you’ll now see all the SQL statements that mobl executes to create the database schema when your application loads.

An initial root screen

Let’s get started with an initial root screen:

screen root() {
  header("Tasks")
  group {
    list(t in Task.all() order by date desc) {
      item { label(t.name) }
    }
  }
}

A lot of this you will have seen before. There’s the familiar header control, and the familiar group and item controls. What’s new is the list construct. What does that do? list is one of mobl’s control structures for user interfaces. It can be compared to a for-each loop, except that it adapts automatically to changes to the collection it iterates over. What that means will become clear later on. The syntax is:

list(<item> in <collection-exp>) {
  ...
}

or, if you want to be more explicit about types:

list(<item> : <Type> in <collection-exp>) {
  ...
}

This particular list iterates over the Task.all() order by date desc collection. So what’s that? The Task.all() collection is a virtual collection that contains all known instances of the Task entity. Task.all() is of type Collection<Task>. Collections represent (sometimes virtual) collections of objects that can be filtered, sorted and manipulated.

A collection’s order(prop, asc) method, for instance, sets the sort order for a collection: Task.all().order("date", false) is a collection of all instances of Task ordered in descending order by date.

A collection’s filter(prop, op, value) method filters a collection based on a property: Task.all().filter("done", "=", false) is a collection of all Task instances that have not yet been completed.

These can also be combined, of course: Task.all().filter("done", "=", false).order("date", false). However, this chained method call syntax does not look very pretty. Therefore, mobl has a syntactic abstraction over these methods that looks more SQL-like. The latter expression can therefore be rewritten as Task.all() where done == false order by date desc.

When we test our new root screen it will be a disappointing sight. Where are all the tasks? The database is still empty, so there’s not much to see.

We need a way to add new tasks.

Adding tasks

Add a new screen above or below the root screen:

screen addTask() {
  var newTask = Task()
  header("Add") {
    backButton()
    button("Add", onclick={
      newTask.date = now();
      add(newTask);
      screen return;
    })
  }
  group {
    item { textField(newTask.name, 
                     placeholder="Task name") }
  }
}

Woah! Some new stuff there. First of all, yes, you can create multiple screens. Here we created a new screen named addTask, again without any arguments. The screen has a local variable newTask that is initialized with a new Task instance. Instantiating a mobl type can be done simply by calling the type name as a function. Optionally, we can initialize properties directly while creating the object:

var newTask = Task(done=false, date=now())

Let’s skip the header for now and move on to the textField control. This control is bound to the name property of the newly created newTask object, meaning that whenever the value of the text field is changed by the user, it automatically changes newTask‘s name property as well. The placeholder argument sets the place holder text that is displayed within the text field when it has no value. It functions as a hint to the user as to what is supposed to be filled in there.

We now have a new Task object whose name property is bound to a text field. So when the user fills in the task name, it is assigned to the newTask.name property. Great. But what should the user do when he or she’s done filling in the task name? That’s what the “Done” button is for.

As you can see, a header control can have body elements as well. In fact, this one has two: a backButton and a button element. These controls will appear inside the header. By convention, a backButton always appears at the left, and regular buttons appear along the right of the header.

Let’s focus on the “Done” button. A button has two important arguments: the button text and the onclick handler. In this case, the button text is “Done”. The onclick arguments defines what should happen when the user clicks (or “taps”) the button. The onclick argument is of type Callback. A callback function is a snippet of application logic that is to be executed when a certain event occurs. Application logic is encoded using mobl’s scripting language.

Scripting

Mobl’s scripting language is syntactically similar to Javascript. It has many of Javascript’s constructs, such as var declarations, if, else, while and return statements. However, like the rest of mobl, it is a typed language. Callbacks are typically defined in-line by enclosing scripting code within curly braces. So, let’s see what happens when the “Done” button is clicked:

newTask.date = now();
add(newTask);
screen return;

The first line assigns a new value to newTask‘s date property. It calls the now() function, which returns a DateTime object representing, shockingly, the current time and date. The next line marks the newTask object for persistence. Newly instantiated entity objects are not immediately persisted, that would lead to a lot of garbage in the database. They have to be marked for persistence once in their lifetime using the add(obj) function. From then on, mobl manages the persistence of the objects. Whenever its properties are changed, it will make sure those changes are persisted to the database. The third line may seem the strangest. You may know about return statements, but what is a screen return?

Screens in mobl are called like functions. To invoke the addTask screen, you can simply call addTask() from script. When doing so, the currently visible screen will be hidden and replaced by the called screen. The question is, how does a screen signal it’s “done”? How does the user return to the previous screen? That’s what screen return does. screen return says: I’m done, return to whatever screen you were at before. Optionally, a value can be returned, if a return type is defined for a screen.

While we created an addTask screen, there’s no way to get to it yet. In order to invoke the screen, we will add an “Add” button to the header of our root screen. Adapt the header call in root to the following:

header("Tasks") {
  button("Add", onclick={ addTask(); })
}

When the user pushes the button, the addTask screen will appear, the user will fill in a task name and push the “Done” button. That will add the new task to the database, set the date property and then return the user to the root screen (using screen return).

Save your application and test it. You can now add new tasks!

Did you notice that newly added tasks automatically appear in the task list, without you having to do anything? Implicitly, when add()ing a new task, you modify the Task.all() collection, which triggers a re-render of the list in the root screen.

Marking tasks as done

Although we can now add tasks, and they appear in a list, we cannot yet mark them as done. To enable that, replace the item control within the list in the root screen with the following:

item { checkBox(t.done, label=t.name) }

This uses the checkBox control (which renders, well, a checkbox) and binds its value to t.done. Whenever the user taps the checkbox and changes its value, the t.done property is automatically changed as well (and the change is propagated to the database as well). The label argument adds a label to the checkbox. An alternative solution could have been:

item {
  checkBox(t.done)
  label(t.name)
}

The only difference is that in the former solution the label can be clicked to toggle the checkbox, in the latter solution the user has to aim a little bit better and click the checkbox itself.

Save your application and run it:

Editing and deleting tasks

We can now add, and mark tasks as done. Now let’s also enable the user to edit and delete tasks.

First define an editTask screen:

screen editTask(t : Task) {
  header("Edit") {
    button("Done", onclick={ screen return; })
  }
  group {
    item { textField(t.name, 
                     placeholder="Task name") }
    item { textField(t.description, 
                     placeholder="Task description") }
  }
}

Yep. The first screen with an argument — the task to be edited, to be precise. For the rest, there’s not much new. The screen defines two text fields, one for the task name, the other for its description. The “Done” button doesn’t do anything other than returning the user to the previous screen. Note an add(obj) call is not required, because the task is already in the database. There’s also no explicit save call, changes are persisted to the database as the user edits the text fields.

In order to expose the edit and remove features, we will create a context menu for every task in our root screen. Again, adapt the item control call in your root screen:

item {
  checkBox(t.done, label=t.name)
  contextMenu {
    button("Delete", onclick={
      remove(t);
    })
    button("Edit", onclick={
      editTask(t);
    })
  }
}

We now added a contextMenu control. In its body, we add two buttons that will become visible when we push the context menu’s icon. The first button is is for deleting tasks. It simply calls remove(t) when clicked. remove(obj) removes that object from the database, as expected. The “Edit” button invoked the editTask screen, as expected.

Save your application and run it, you can now remove and edit tasks!

Googling it up

If you’re a very busy person, the amount of tasks may overwhelm you. Wouldn’t it be nice to be able to search tasks as well? That would also make adding those searchable annotations in our data model more useful.

Before we start, we’ll first do some refactoring of our current code. In our search screen, we’ll also want to display task items, with the same checkbox and edit/delete buttons. Can’t we reuse that code somehow?

We can do that by creating our own control. We’ll call this control taskItem and we define it as follows:

control taskItem(t : Task) {
  checkBox(t.done, label=t.name)
  contextMenu {
    button("Delete", onclick={
      remove(t);
    })
    button("Edit", onclick={
      editTask(t);
    })
  }
}

As you can see, a control is defined very similar to screens. Easy huh? So, let’s use it. Let’s once again (last time, I promise) change the item control in our root screen, in fact, let’s replace it, turning the list construct there into:

list(t in Task.all() order by date desc) {
  item { taskItem(t) }
}

We replaced that whole item thing with a single taskItem control call. Cool huh? Cleaner code with exactly the same behavior.

Time to add search. Define the following new screen:

screen search() {
  var phrase = ""
  header("Search") { backButton() }
  searchBox(phrase, placeholder="Search term")
  group {
    list(t in Task.searchPrefix(phrase)) {
      item { taskItem(t) }
    }
  }
}

Once again, we use a local screen variable. It’s the variable that will keep the search phrase. We use the searchBox control to render a search input box. A searchBox is basically the same as a textField, except with different styling. It binds the control to the phrase variable.

The list construct iterates over the Task.searchPrefix(phrase) collection. This is a special collection that performs a full-text search on all properties that have been marked searchable. Because the collection depends on the value of the phrase variable, the list of updates automatically updates as the user types in his or her search query. We reuse our taskItem control here to render the task.

Add a button to the search screen at the bottom of the root screen:

button("Search", onclick={ search(); })

Save your application and run it. We’re done!

In barely 80 lines of code we built a pretty functional todo list applications that supports adding, editing, removing and searching tasks. We defined a simple data model, a custom control and a number of screens. We defined some event callbacks to navigate between screens and set properties.

What about MVC?

While mobl supports the Model-View-Controller pattern, it does not enforce it. The model (entities) of the application can be defined separately from the rest of the application. However, views (controls and screens) and controllers (script callbacks) are mixed. In the todo application we built, the amount of controller logic is so small that it would a waste to create a whole separate controller to implement it. However, if desired, it is possible to move more of the logic to functions. For instance, the following snippet of code:

button("Add", onclick={
  newTask.date = now();
  add(newTask);
  screen return;
})

Could be refactored to:

button("Add", onclick={
  createTask(newTask);
  screen return;
})
function createTask(t : Task) {
  t.date = now();
  add(t);
}

The function could even be moved to a separate module. But you don’t have to. Mobl lets you organize the code the way you like. It is good practice to move complex logic into functions in a separate module, but it is typically much more productive to write simple one or two-liners inline in the control or screen itself.


Version 0.3.0

Today version 0.3.0 of mobl was released. Mobl is a language for rapid development of mobile web applications using HTML5 technologies. Programs written in the mobl language are compiled to a combination of HTML, Javascript and CSS and can run on any webkit browser, specifically those on iOS and Android devices.

New in this version:

  • Styling support. Documentation is upcoming.
  • Configuration file support. Configuration settings are no longer put in the application file itself, but have instead been moved to the config.mobl file in the mobl project.
  • cond for conditionally showing content in user interfaces has been renamed to when, and also has an else clause. So, code like this:

    cond(show) {
      ...
    }
    cond(!show) {
      ...
    }
    

    can now be rewritten to:

    when(show) {
      ...
    } else {
      ...
    }
    

To install, follow these instructions. To upgrade, simply upgrade from the update site.

1 Comment more...

Your First Application

While researching other frameworks and languages for mobile web development, you may have been disappointed with their tutorial offerings. They build boring applications in them. Stuff you don’t really need. Therefore, in this first mobl tutorial we’re going to build something exciting and useful.

A tip calculator!

Yep, you heard that right. You may ask “are you sure I’m ready? I’m still so young”, but I say: yes. Yes, I think you are ready to enrich the wondrous world of tip calculators. If you weren’t aware, a tip calculator is an application that given the amount you have to pay in, for instance, a restaurant and a tip percentage, calculates the total amount due.

I predict you will only need at most 15 lines to do it. Does that sound exciting or what? This is what the end result will look like:

And here you can see it in action (use any webkit-based browser).

To speak the memorable words of Demetri Martin: “Crazy awesome!”

I’ll assume you will have installed the mobl plug-in, and created your first “Hello world!” application. If not, please follow the instructions in that link. I’ll wait until you’re done.

Done? Ok.

Create a new mobl project

Give it an imaginative name. Naming is everything. Suggestions: “tipcalculator”. That’s what I called mine.

Build the application

Replace the root screen with the following snippet of code:

screen root() {
  var amount     =  20
  var percentage =  10
  header("Tip calculator")
  group {
    item { numField(amount, label="amount") }
    item { numField(percentage, label="percentage") }
    item { "$" label(amount * (1 + percentage/100)) }
  }
}

What does it mean?

Woah! What does it mean? Let’s start at the top.

screen root() { ... }

This defines a screen named root with no arguments. A screen is exactly what you think it is. A screen can have zero or more arguments (this one has zero), and optionally a return type, which we will ignore for now. Within the curly braces is the body of the screen. A screen body defines the structure of the user interface and user interface state.

var amount     = 20
var percentage = 10

This code defines two screen state variables. These are variables that are only accessible from within the screen. While mobl is a typed language, it is often not required to explicitly define types of variables, because their types can be inferred. In fact, the above two lines are short hand for:

var amount     : Num = 20
var percentage : Num = 10

So, Num is the mobl type that allows numeric values (both integer and floating point, it maps directly to Javascript’s numeric type). Variables, as their names suggest can change (vary — get it?). There are two main ways that the value of a variable can change:

  1. it is explicitly assigned a new value; or
  2. it is bound to a control, which, through interaction with the user, implicitly changes the value

Don’t get what that last one? No problemo, we’ll get to that in a sec.

header("Tip calculator")

This line instantiates the header control. One of the controls that is part of the mobl::ui::generic library that we imported at the top of the application. Controls, like screens, can have arguments. In fact, they can have two kinds of arguments: regular arguments and body elements. Regular arguments are passed to the control within the parentheses ( and ). Some arguments may be optional, and arguments can be named. The first argument of the header control is called text, and therefore, the header control may also be called as follows:

header(text="Tip calculator")

Which style you choose depends on taste and/or clarity. So, how about the second type of arguments — body elements?

group {
  item { ... }
  item { ... }
  item { ... }
}

This is another instantiation of a control, in this case of the group control. Unlike the header control, it is not passed regular arguments, in fact, the parentheses were left out entirely (which is allowed). However, the group control does take body elements, which are a set of controls in the body of the control (between the curly braces). In this case the body elements argument of the group control consists of three item controls. The control can render its body elements if it wishes so, or ignore them altogether.

item { numField(amount, label="amount") }

Here we use two other controls. An item control, with a numField control in its body. item controls have to be embedded within a group, otherwise they will not work. The numField is an input control. It takes two arguments, one of which is named. The label argument defines a label that will appear to the left of the input control.

The other argument, amount is more interesting. amount, as you’ll recall is one of our screen variables. By passing amount to the numField control, we bind its value to the control. In the case of an input control, this data binding happens in two directions. When the user edits the text in the input field (using the phone’s keyboard, for instance), this changed value is also automatically assigned to the amount variable. Vice versa, if the amount variable’s value is changed, either by directly assigning to it, or by binding it to another control, the value that appears in the input control changes with it.

item { numField(percentage, label="percentage") }

This line does a similar thing as the previous one, except with a different label and binding to the percentage variable instead of amount.

item { "$" label(amount * (1 + percentage/100)) }

And then, the final line. The line where the magic happens. Again, the item control is instantiated. It contains two controls. The first is a literal string “$”, which, well renders a dollar sign on the screen. The second is a label control, which is passed an mathematical expression as argument. A label control simply displays its argument on the screen. However, like the numField control, it also binds its argument to the label control. In this case this is a one-way data binding. Whenever the value of the argument of label changes, the new label control reflects that change on the screen. When does the value of label‘s argument change? When either amount or percentage changes. When do those variables change? When their value is changed through the numField controls.

So, what is the result of all of this? The best way to find out is by trying it. You will see that the value of the label control recalculates whenever either the amount of tip percentage is modified — even as the user types. Cool huh?

Configuring your application

You will notice that your application’s title (as it appears in the browser’s title bar) is derived from your application’s file name. To change this, we have to create a configuration file for our project. Right-click on your project, pick “New” and then “File”. Name your file config.mobl and copy the following code into it:

configuration
title "Tip Calculator"

The config.mobl file is used to set various application configuration options, such as debug for debug mode, database to configure the name of the database to use. To see all configuration settings, use Ctrl+space on an empty line in the configuration file.

Save the configuration file. Go back to your application’s mobl file, make a little change (like, put a space somewhere) and save it to recompile it with the new configuration settings.

Conclusion

Let’s take a little step back and see what we did here.

We created a new application. Every application in mobl starts with application <application-name>, followed by zero or more imports, which define the libraries that the application will use. An application needs at least a single screen, named root without any arguments.

For this application we created root screen with two local variables. We bound those variables to two input controls. In addition, we created a label that performs a calculation based on the values of those variables that automatically recalculates whenever the input controls change. This may seem strange at first, but hopefully you’ll quickly appreciate its power. It is in fact very similar to the way spreadsheets like Excel work. Some cells are filled with data, others contain formulas and show derived values. Whenever one of the data cells change, all the cells that depend on that value change automatically. This is called reactive programming and is one of mobl’s core programming models.

Note that a screen definition is not like defining an imperative function. It does not contain a list of statements that are to be executed sequentially, but rather declares the structure of the user interface, that may be updated through state changes at any time.


Welcome

Welcome to the new mobl-lang.org. We’re working hard on it, so stay tuned!


mobl

Copyright © 2010-2020 mobl. All rights reserved.
iDream theme by Templates Next