Book Image

Dart By Example

By : David Mitchell
Book Image

Dart By Example

By: David Mitchell

Overview of this book

Table of Contents (17 chapters)
Dart By Example
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Building your first application


Starting simple is a good idea, but we also want to start with something useful that can be expanded as we explore Dart.

In day-to-day software development, the text editor is where gigantic, world-changing software often starts. We are going to build a multi-purpose web-based text editor to use as a scratchpad for snippets of code, a to-do list, or stripping formatting from copied text—immensely handy. For added realism, there will be an imaginary customer along the way asking for new features.

In the next chapter, we will build on this foundation for some flashier features and graphical displays.

Tip

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

Exploring the Web project structure

Go to the WebStorm welcome page and click on Open. Select the folder where you extracted the sample code and choose the Chapter One folder, then the sub-folder named Start.

A good first step when opening any Dart project is to ensure all dependencies are present and up to date. To achieve this, select pubspec.yaml and right-click to show the context menu. Click on the Pub: Get Dependencies item. The dependencies will then be resolved and fetched if required.

File / Folder

Description

packages

A link to the packages (or libraries) that are being used by this project. In this case, you will see the 'browser' package.

pubspec.lock

Controls the specific version of the packages being used.

pubspec.yaml

Meta information on our project (name, description, and so on) and a list of packages being used.

web/styles/main.css

The standard cascading style sheet file.

web/index.html

The entry point for our web application.

main.dart

Last but not least, a Dart file!

Unwrapping packages

From the preceding list, there is clearly a lot of structure and meta files for packages in even a simple Dart project. The philosophy of the language is that libraries are small, focused, and likely to be from different sources. They are also numerous and update on different schedules, so version controls are important—dependencies are hungry and must be fed.

You want your team members to be able to build and use your new Uber package without dependency horrors! Likewise, you want the package you download off the Internet to "just work" and reduce the effort required to write your application.

To look after all these packages, Dart has a tool called pub. This is a Swiss Army knife tool that helps create, manage, and deploy your programs and packages. The main home for Dart packages is the website https://pub.dartlang.org, where numerous open source libraries are published.

Tip

If you are curious to know the origin of the name, "pub" is British slang for a bar where people drink and play a game of darts.

A look at Pubspec

The pubspec.yaml has a curious file extension—YAML stands for Yet Another Markup Language:.

name: 'TextEditor'
version: 0.0.1
description: A web based text editor.
environment:
  sdk: '>=1.0.0 <2.0.0'
dependencies:
  browser: any

From this, it is clear to see pubspec.yaml is Dart's equivalent of a project or solution file. This holds the typical dependency details and meta-information. The Pubspec file is fully detailed at https://www.dartlang.org/tools/pub/pubspec.html. Although it is an extensive and powerful file, the main interaction you will probably have with it is adding new dependencies.

Putting Dart into the web page

The file index.html is a regular web page. The rest of the file consists of a few simple <div> elements and, as you might expect, a <textarea> tag:

<!DOCTYPE html>
<html>
<head>
    <title>TextEditor</title>
    <link rel="stylesheet" href="styles/main.css">
</head>

<body>
<div id="output">

    <div id="toolbar">
    TextOnTheWeb
    </div>

    <textarea id="editor" cols="80" autofocus>
    </textarea>

</div>
<script type="application/dart" src="main.dart"></script>
<script data-pub-inline src="packages/browser/dart.js"></script>
</body>
</html>

The foot of this page is where the initial Dart file is specified. The main.dart file is loaded and the entry point, the first function to be run, is the main() function.

Tip

If you have programmed in C/C++, C#, or Java, main is a familiar starting or entry point to an application. The concept is identical in Dart.

Let's work through the main.dart file section one at a time and discover some Dart features along the way.

Importing packages

Dart features a keyword, import, to use other packages and classes in our current code context. In this case, both are prefixed with dart: to signify they are from the SDK:

import 'dart:html';
import 'dart:convert' show JSON;

The keyword show modifies the second import to only make the JSON property sections of the dart:convert package. This limits the classes in the current namespace and therefore helps avoid name clashes and developer confusion.

Variable declarations

The TextArea is central to our editor and will be referenced multiple times; therefore, we will use a specific type for it rather than var. In contrast, JavaScript declares variables with the all-encompassing var keyword.

TextAreaElement theEditor;

This declares a new variable called theEditor and declares it as the type TextAreaElement. The dart:HTML package contains classes to cover the DOM and the TextArea input element.

Dart has an optional type system, so it would be possible to declare var theEditor and the program would still run successfully. By being specific with the type, we gain clarity in the source code and we provide more detailed information to developer tools, such as code editors and documentation generators:

void main() {
  theEditor = querySelector("#editor");
  theEditor
      ..onKeyUp.listen(handleKeyPress)
      ..text = loadDocument();
}

In the main function, we use the querySelector method from dart:HTML to connect to the TextArea control (with the ID attribute set to editor) on the web page. Once we have a reference to the control, we want to a) connect an event handler so that we know when the user has typed something, and b) load any existing text and display it.

Because we are using the same object, we can use the cascade operator (..), which helps us write very readable and flowing code. The preceding can be written as:

      theEditor.onKeyUp.listen(handleKeyPress);
      theEditor.text = loadDocument();

The more properties we set, the more we have theEditor cluttering up the code. With the cascade operator, we can replace the object name with (..), and call the method/set a property as before. One important point with the cascade operator is that only the final use has a semi-colon at the end of the line.

Writing the event handler

The editor's TextArea KeyUp event has been connected to this short handler function:

void handleKeyPress(KeyboardEvent event) {
  saveDocument();
}

In contrast to JavaScript, there is no function keyword and we have void before the function. The void keyword just means that this function does not return anything when it is finished; it can be any class or type. As Dart is optionally typed, we could omit void altogether.

Just a minute! Where are we going to be storing this text? After all, we have only written a single HTML page and do not have a database connection or web service to take care of the persistence. Fortunately, HTML5 has a simple key/value based built-in storage feature called Local Storage that is well-supported by modern web browsers. This operates in a similar fashion to a dictionary (sometimes called a map) data structure.

In the next two functions, we will look at loading and saving from localStorage.

Note

The HTML5 feature window.localStorage persistently stores data with the client's browser. Unlike data stored in cookies, it does not expire based on a date. The data is not lost when the browser window is closed or the computer is switched off.

The amount of storage can vary per browser and according to user settings, but the typical default value is 5 MB. This is plenty for our text editor and many other types of applications.

Loading the saved text

The loadDocument function lets the world know it will be returning a String object:

String loadDocument() {
  String readings = "";
  String jsonString = window.localStorage["MyTextEditor"];
  if (jsonString != null && jsonString.length > 0)
    readings = JSON.decode(jsonString);
  return readings;
}

We will store the text under the key MyTextEditor. The first time the user loads up this page, there will be nothing in the local storage for our web page, so we will check if it is empty or null before putting the value into the readings string variable.

Note

JSON (JavaScript Object Notation) is an ECMA standard data format that is based on a subset of JavaScript and is an alternative to XML.

For example:

{
  "Name": "Davy Mitchell",
  "LuckyNumber": 123,
  "CarModel": null,
  "Language": "English"
}

Saving the text

The format we are using to save the text is JSON—JavaScript Object Notation—which is a common standard in web pages. The package dart:convert gives us both the encode and decode functions:

void saveDocument() {
  window.localStorage["MyTextEditor"] = JSON.encode(theEditor.value);
}

Finally, the saved document uses the local storage to keep our text safe. This time, we are encoding the data into the JSON format.

Running in the browser

We are now finally ready to actually run the text editor in the target environment. How is a browser going to execute a .dart file? Internet Explorer, Chrome, and Firefox don't speak Dart.

Dartium is a special build of the Chromium browser (the open source project behind Google's Chrome browser) that contains the Dart virtual machine. Though not recommended for day-to-day browsing, it is a full powerful modern browser to use while developing Dart applications. As shown in the screenshot, it looks just like (a very plain) Google Chrome.

Tip

If you are running on Ubuntu and receive a start up error mentioning libudev.so.0, run the following command in a terminal to resolve it:

sudo ln -s /lib/x86_64-linux-gnu/libudev.so.1 /lib/x86_64-linux-gnu/libudev.so.0

For more information, see https://github.com/dart-lang/sdk/issues/12325

In WebStorm, right-click on the index.html file to bring up the context menu and select the run index.html. This will start a local HTTP server for your application.

Once the application is running, type some text into the editor, and then close the browser window. Then, run the program again and you should see your text reappear once the page has loaded.

Editing and reloading

A new requirement has arrived from our customer. The title of the application, "TextOnTheWeb", is not to their liking, so we will have to change it.

By this point, Dart should be looking a lot more familiar to you if you have written JavaScript. The workflow is similar, too. Let's make a change to the executing code so that we can see the edit and reload cycle in effect.

This will be achieved in the main function so, while keeping Dartium open, open the main.dart file again in WebStorm, and locate the main function.

Add the following code snippet to start of the function:

  DivElement apptitle = querySelector("#toolbar");
  apptitle.text = "TextEditor";

Once you have made the change, save the file and switch back to Dartium. Refresh the page and the new version of the main function will run and the new title will be displayed.

Extending the interface

Our customer has asked for a button to clear the editing area. This is a reasonable request and should not take too long to code with the productivity of Dart.

Firstly, we will open the index.html and add an input button to the page underneath the TextArea control:

 <input type="button" id="btnClearText" value="Clear" />

Open main.dart and in the main function, connect up an event handler:

ButtonInputElement btnClear = querySelector("#btnClearText");
  btnClear.onClick.listen(clearEditor);

As with JavaScript, it is very easy to pass functions around as parameters. Move the cursor over the text clearEditor and a lightbulb will appear. This offers the keyboard shortcut of Alt and the Enter/Return key, or you can click on the lightbulb icon.

The implementation of the function is straightforward. Notice that we receive a properly typed MouseEvent object as part of the event:

void clearEditor(MouseEvent event) {
  theEditor.text = "";
  saveDocument();
}

Refresh the page and click the button to clear the existing text. One happy customer and we hardly broke a sweat!

The WebStorm Dart plugin has a number of quick fixes to aid your productivity and help avoid coding errors in the first place. They also encourage good design and keeping to Dart conventions.

Using the CSS editor

Keep the text editor running for the moment and switch back to WebStorm. Go to the Project tab and in the TextEditor folder, open the web/styles/main.css file.

This is going to be your editor, too, so it is important that it is your favorite color—perhaps you would like a thinner border or are not too fond of my chosen gray palette.

Make some changes to the color classes and save the file.

The WebStorm CSS editor is powerful and shows previews of colors. If you switch back to Dartium and click reload, the text editor should now reflect your chromatic preferences.