Learning Dart - Second Edition - Sample Chapter
Learning Dart - Second Edition - Sample Chapter
Second Edition
Learning Dart, Second Edition provides you with a
project-based approach to everything you need to start
or enhance your career in future web development work
with Dart. It follows the spiral approach: each project
builds up in successive spirals, adding new features at
each step.
Stop solving new challenges with the same old tools let
Learning Dart, Second Edition show you a whole new way.
$ 44.99 US
28.99 UK
P U B L I S H I N G
Ivo Balbaert
Dzenan Ridjanovic
Second Edition
Learning Dart
Learning Dart
ee
pl
C o m m u n i t y
E x p e r i e n c e
D i s t i l l e d
Learning Dart
Second Edition
Learn to develop high-performance applications with Dart 1.12
Sa
m
Ivo Balbaert
Dzenan Ridjanovic
retirement to focus on the development of web applications with Dart, HTML5, web
components, and NoSQL databases. For more than 10 years, he was a director of
research and development in the Silverrun team (http://www.silverrun.com/),
which created several commercial tools to analyze, design, and develop data-driven
applications. He was the principal developer of Modelibra (http://www.modelibra.
org/) tools and frameworks for model-driven development in Java. Currently, he
is developing the dartling framework for the design and code generation of Dart
models. His projects are on GitHub (https://github.com/dzenanr), where he
is considered a Dart expert (http://osrc.dfm.io/dzenanr). He writes about his
projects on the On Dart blog (http://dzenanr.github.io/). His courses
are available on On Dart Education (http://ondart.me/). He markets his Dart
efforts on the On Dart G+ page (https://plus.google.com/+OndartMe). Dzenan
Ridjanovic wrote a book in 2009, under the Creative Commons License, entitled
Spiral Development of Dynamic Web Applications: Using Modelibra and Wicket
(http://www.modelibra.org/).
Preface
Developing a web application (or software in general) is still a challenging task.
There is a client- or browser-side and a server-side with databases. There are many
different technologies to master in order to feel comfortable with a full client-server
stack. There are different frameworks with different objectives. There are different
programming languages as well that a developer must learn, each one more suitable
either for the server-side or for the client-side.
Learning Dart will make a developer become more productive by using Dart
both for clients and servers. Using the same language, a developer will lose
neither performance nor flexibility. Dart can be used within its virtual machine
or its code may be compiled to JavaScript. In both the cases, the performance
benchmarks show promising scores (https://www.dartlang.org/performance/).
Dart is both an object-oriented and a functional language. A mix of both the
approaches is possible with Dart, providing great professional freedom and
programming background flexibility. In addition, Dart provides many libraries and
tools (http://pub.dartlang.org/) to allow a developer focus on the tasks at hand
and not be concerned with all the aspects of software development.
With Polymer.dart (https://www.dartlang.org/polymer-dart/), a new approach
of developing web applications with web components will allow a developer to
divide a web page in sections and reuse an already developed and tested web
component for each section. In the near future, different catalogs of web components
will appear, enabling, after waiting for many years, an engineering approach
to software development. A web component may be derived from other web
components. It may pass data to its components. A web component may inherit
its behavior from another web component. It may access an already instantiated
web component.
Preface
Simple solutions are provided first. Later on, these solutions may be replaced
by more advanced solutions.
All three points are important to teach and learn these technologies.
Learning new software concepts and technologies is a challenging task. Learning
in spirals, from simple to more advanced concepts but with concrete software
applications, helps readers get a reasonable confidence level early on, and motivates
them to learn by providing more useful applications. With each new spiral, the
project grows and new concepts are introduced. A new spiral is explained with
respect to the previous one. The difference between the two consecutive spirals is
that the next spiral introduces the new code and modifies or deletes the old. This
is called learning by anchoring to what we already understand. With a new spiral,
we can go back to what we did previously and improve it. In this way, learning in
spirals can touch the same topic several times, but each time, with more details in a
better version.
Preface
Chapter 4, Modeling Web Applications with Model Concepts and Dartlero, will let you
design graphically a small model in the Model Concepts tool, which is developed
in Dart. A model is then represented in Dart as several classes that inherit some
data and operations from the classes of the Dartlero model framework; this is
also done in Dart.
Chapter 5, Handling DOM in a New Way, covers how to access HTML elements
in Dart. Some elements will be even created in Dart and placed properly in the
Document Object Model (DOM) of a web page. Dart will also handle user events,
such as a click on a button. Finally, you will be able to create a simple game in Dart.
Chapter 6, Combining HTML5 Forms with Dart, will let you enter some data in a form.
The data will be validated by HTML5 and Dart. Then, the valid data will be saved in
the local storage of a browser.
Chapter 7, Building Games with HTML5 and Dart, will let you create a well-known
memory game step by step, based on what you have learned already. Each step
will be a new spiral represented as a complete project in Dart Editor. The first spiral
will draw only a rectangle, while the last spiral will be a game that you may show to
your friends.
Chapter 8, Developing Business Applications with Polymer Web Components, will help you
create several web components using Polymer.dart. These web components will be
used in the different sections of a single-page application. Three different projects
with web components will be presented in this chapter.
Chapter 9, Modeling More Complex Applications with dartling, will let you discover
how a graphical model can be transformed into a JSON document and then used to
generate a complete model in Dart by using the dartling domain model framework
together with its tools. The dartling follows the Model View Controller (MVC)
pattern to separate a model from its views.
Chapter 10, Local Data and Client-Server Communication, will let you store application
data in a local database called IndexedDB. The data will then be sent as a JSON
document to a Dart server. Asynchronous programming with futures will be covered
in this chapter.
Chapter 11, Data-Driven Web Applications with MySQL and MongoDB, will help you
learn how to use database drivers to save (and load) data to (and from) a relational
database and a NoSQL database. Data sent from a browser as a JSON document will
be easily saved in MongoDB in the same JSON form. Two clients will exchange data
with the server so that both of them will be up-to-date.
We will get started with the Dart platform and have a look at its tools. Before this, we
will be programming and taking a dive into a simple functional to-do list program so
that you realize how familiar it all is.
What is Dart?
Dart is a new general and open source programming language with a vibrant
community developed by Google Inc. and its official website is http://www.
dartlang.org. It was first announced as a public preview on October 10, 2011;
it has now reached version 1.10. World class language designers and developers
are involved in this project, namely, Lars Bak and Kasper Lund (known for their
V8 JavaScript engine embedded in the Chrome browser, which revolutionized
performance in the JavaScript world), and Gilad Bracha (a language theorist known
for the development of the Strongtalk and Newspeak languages and for the Java
specification). Judging by the huge amount of resources and the number of teams
working on it, it is clear that Google is very serious about making Dart a success.
[1]
Dart looks instantly familiar to the majority of today's programmers coming from
a Java, C#, or JavaScript (JS) (ActionScript) background; you will feel at ease with
Dart. However, this does not mean that it is only a copy of what already exists; it
takes the best features of the statically typed "Java-C#" world and combines these
with features more commonly found in dynamic languages such as JS, Python, and
Ruby. On the nimble, dynamic side Dart allows rapid prototyping, evolving into a
more structured development familiar to business app developers when application
requirements become more complex.
Its main emphasis lies on building complex (if necessary), high performance, and
scalable-rich client apps for the modern web. By modern web, we mean that it
can execute in any browser on any kind of (client) device, including tablets and
smartphones, taking advantage of all the features of HTML5, and it is ported to the
ARM-architecture and the Android platform. Dart is designed with performance in
mind by the people who developed V8. Because the Dart team at Google believes
web components will be the foundation for the next evolution of web development,
there is strong Dart support for the Polymer framework (web components are pieces
of the web code containing HTML and Dart or JavaScript that you can reuse in
different pages and projects. In other words, it is a reliable infrastructure of widgets).
However, Dart can also run independently on servers. Because Dart clients and
servers can communicate through web sockets (a persistent connection that allows
both parties to start sending data at any time), it is, in fact, an end-to-end solution.
It is perfect on the frontend to develop web components with all the necessary
application logic, nicely integrated with HTML5 and the browser document model
(DOM). On the backend server side, it can be used to develop web services, for
example, to access databases, or cloud solutions in Google App Engine or other
cloud infrastructures.
Moreover, it is ready to be used in the multicore world (remember, even your cell
phone is multicore nowadays), because a Dart program can divide its work among
any number of separate processes called isolates, an actor-based concurrency model
as in Erlang.
[2]
Chapter 1
Because of this sometimes undefined nature of JS, its performance is often very
unpredictable, so building high performance web apps in it is tricky.
[4]
Chapter 1
Advantages of Dart
This way, Dart can get a better performance profile than JS (remember that the
same experts who developed the V8 JS VM are forging Dart, see http://www.
dartlang.org/performance/) and, at the same time, maintain the simple and rapid
development process of JS in the browser: the edit code, save, and refresh browser
cycle to view the latest version, rather than having to stop, recompile, and run for
every little change. Dart delivers high performance on all the modern web browsers
and environments ranging from small handheld devices to server-side execution.
When it runs on its own VM, Dart is faster than JS (currently, around 1.5 times the
performance of JS). Moreover, through snapshotting (a mechanism inherited from
Smalltalk), a Dart app has a fast application startup time in contrast to JS, where all
the source code has to be interpreted or compiled from the source.
Dart executes in the browser after having been compiled to JS, so Dart runs
everywhere JS does. The Dart VM can also run standalone on a client or server.
[5]
Another big advantage compared with GWT is that Dart is much better integrated
with the web page and like JS can directly manipulate the page elements and the
document structure, that is, the Document Object Model (DOM). Like JS, it has
intimate access to the new HTML5 APIs, for example, drawing with the canvas,
playing audio and video clips, or using the new local storage possibilities. Following
the RIA model explained earlier, Dart executes the full application code in the
browser, requesting data from the server and rebuilding the page user interface
when needed. Because Dart wants to be a part of the web, not just sit on the top, the
team has also built a Dart to JavaScript interop layer to call JavaScript from Dart and
the other way around. Together with its out-of-browser and server capabilities, Dart
is also conceived to build complex, large-scale web applications. This can be clearly
seen from its object-oriented nature, and Dart code is built with code clarity and
structure (using libraries and packages) in mind. To summarize it:
Dart is faster than JavaScript while running in its VM (as a server standalone
application, or in Dartium, which is a special build of the Chromium browser)
client(browser)
DART VM
server
building
the view
[6]
Chapter 1
https://dartpad.dartlang.org/.
[8]
Chapter 1
This is probably the shortest app possible, but it can be even shorter! The void
keyword indicates (as in Java or C#) that the method does not explicitly return an
object (indeed print only produces output to the console), but the return types can
be left out. Furthermore, when a function has only one single expression, we can
shorten this further to the following elegant shorthand syntax:
main() => print("Hello, World!");
Now, change the printed string to "Becoming a Dart Ninja!" and click on
the green arrow button (or press Ctrl + R) to run the application. You should see
something like the following screenshot (where the Files, Apps, and Outline items
from the Tools menu were selected):
[9]
The Files and Apps tabs are useful for browsing through your applications and for
creating, copying, moving, renaming, and deleting files. The Outline tab now only
shows main(), but this tool will quickly become very useful because it provides an
overview of the code in the active file.
Because this was a command-line application, we could just as easily have opened a
console in our dart1 folder and executed the dart main.dart command to produce
the same output as shown in the following screenshot:
To let this work, you must first let the OS know where to find
the Dart V. For example, in Windows, you change the path
environment variable to include C:\dart\dart-sdk\bin if
your Dart installation lives in C:\dart.
Auto completion for class members (by typing . after a class name you get a
list of available properties and methods of the current class)
Tools to navigate the code (a handy overview of the code with the outline,
find callers of a method, and so on)
Chapter 1
Refactoring capabilities
The code you make is analyzed while you type, indicating warning (yellow triangles)
or errors (red underscores or stop signs). To get more acquainted and experiment
with these possibilities, go and read the documentation at http://www.dartlang.
org/docs/editor/ and play with one of the samples such as Sunflower or Solar
(you can find the samples by navigating to Tools | Welcome Page). From now on,
use the editor in conjunction with the code examples of the book so that you can try
them out and test the changes.
executed in browser
(Dartium or Chrome)
or on Server
Dart VM
Dart
source
code
(B)
LINUX
OS X
WINDOWS
executed as Javascript
in all modern browsers
dart2js
The Dart code produced in the Dart Editor (or in a plugin for Eclipse or IntelliJ) can:
Be compiled to JS with the dart2js compiler so that it can run in all the
recent browsers
Code libraries in Dart are called packages and the Dart SDK core contains the basic
types and functionalities to work with collection, math, html, uri, json, and so on.
They can be recognized by the dart:prefix syntax, for example, dart:html. If you
want to use a functionality from a library in a code file, you must import it by using the
following as the first statement(s) in your code (dart:core is imported by default):
import 'dart:html';
[ 11 ]
The Dart code can be tested with the unit test package and, for documentation, you
can use the dartdoc tool, which generates a local website structured like the official
API documentation on the Web. The pub tool is the Dart package manager: if your
app needs other packages besides the SDK, pub can install them for you (from
the Tools menu item in Dart Editor, select Pub Get or Pub Update). You can also
publish your apps with it in the http://pub.dartlang.org/ web repository.
We will see all of these tools in action in Chapter 2, Getting to Work with Dart.
(1)
void main() {
var n = 0; // number of rabbits
(2)
(3)
(4)
(5)
Chapter 1
print("After $years years:\t $n animals");
(6)
}
}
0 years:
1 years:
2 years:
3 years:
4 years:
5 years:
6 years:
7 years:
8 years:
9 years:
10 years:
2 animals
30 animals
450 animals
6750 animals
101250 animals
1518750 animals
22781250 animals
341718750 animals
5125781250 animals
76886718750 animals
1153300781250 animals
So, if developing programs doesn't make you rich, breeding rabbits will. Because we
need some mathematical formulas such as natural logarithms log and power pow,
we imported dart:math in line (1). Our number of livestock n is declared in line
(2); you can see that we precede its name with var. Here, we don't have to indicate
the type of n as int or num (so called type annotations), as Dart uses optional typing.
Local variables are commonly declared untyped as var.
[ 13 ]
In the lines (3) and (6), we see that within a quoted string, we can use escape
characters such as \n and \t to format our output. Line (4) uses the well-known
for loop that is also present in Dart. In order to have the count of animals as a whole
number, we needed to apply the round() function. The pow function produces
double and because 6750.0 animals doesn't look so good, we have to convert double
into int with the toInt() function. In the line (6), the elegant string substitution
mechanism (also called string interpolation) is used: print takes a string as
argument (a string variable: any expression enclosed within " " or ' ') and, in any
such quoted string expression, you can substitute the value of variable n by writing
$n. If you want the value of an expression within a string, such as a + b, you have to
enclose the expression with braces, for example, ${a + b}.
You don't have to write ${n} while displaying a variable n,
just use $n; you can also simply use print(n).
It is important to realize that we did not have to make any class in our program.
Dart is no class junkie like Java or C#. A lot can be done only with functions; but if
you want to represent real objects in your programs, classes is the way to go (see the
Example 2 banking section).
Extracting a function
This version of our program is not yet very modular, we would like to extract the
calculation in a separate calculateRabbits(years) method that takes the number
of years as a parameter. This is shown in the following code (version 2 line (4) of
prorabbits_v2.dart) with exactly the same output as version 1:
import 'dart:math';
int rabbitCount = 0;
const int NO_YEARS = 10;
const int GROWTH_FACTOR = 15;
(1)
(2)
(3)
void main() {
print("The number of rabbits increases as:\n");
for (int years = 0; years <= NO_YEARS; years++) {
rabbitCount = calculateRabbits(years);
(4)
print("After $years years:\t $rabbitCount animals");
}
}
int calculateRabbits(int years) {
return (2 * pow(E, log(GROWTH_FACTOR) *
years)).round().toInt();
}
[ 14 ]
(5)
Chapter 1
We could have written this new function ourselves, but Dart has a
built-in refactoring called Extract Method. Highlight the line:
n = (2 * pow(E, log(15) * years)).round().toInt();
[ 15 ]
3. Run the program and learn how to use the features of the Debugger tool
(press F5 to step line by line, F6 or F7 to step over or out of a function,
and F8 to resume execution until the next breakpoint is hit).
4. Watch the values of the years and rabbitCount variables.
The output should resemble the following screenshot:
Debugging prorabbits_v2.dart
A web version
As a final version, for now, let us build an app that uses an HTML screen, where we
can input the number of years of rabbit elevation and output the resulting number
of animals. Go to File | New Project, but this time select Web application. Now,
a lot more code is generated, which needs explaining. The app now contains a web
subfolder; this will be the home for all of the app's resources. However, for now, it
contains a stylesheet (.css file), a hosting web page (.html), and a startup code file
(normally main.dart, in our case, prorabbits_v3.dart). The first line in this file
makes the HTML functionality available to our code:
import 'dart:html';
[ 16 ]
Chapter 1
We remove the rest of the example code, so only an empty main() function remains.
Look at the source of the HTML page right before the </body> tag, it contains the
following code:
<script type="application/dart" src="prorabbits_v3.dart"></script>
<script src="packages/browser/dart.js"></script>
We see that our app depends on the browser package; any version of it is ok. The
package is added to your app when you right-click on the selected pubspec.yaml
file and select Pub Get: a packages folder is added to your app and, per package,
a subfolder is added containing the downloaded code, in our case, dart.js
(In Chapter 2, Getting to Work with Dart, we will explore pub in greater depth
and see that it can also be performed from the command-line).
For this program, we replace the HTML <p id="sample_text_id"></p> code as
shown in the following code:
<input type="number" id="years" value="5" min="1" max="30">
<input type="button" id="submit" value="Calculate"/>
<br/>Number of rabbits: <label id="output"></label>
The input field with type number (new in HTML5) gives us a NumericUpDown
control with a default value 5 limited to the range of 1 to 30. In our Dart code, we
now have to handle the click-event at the button with id as submit. We do this in
our main() function with the following line of code:
querySelector("#submit").onClick.listen( (e) => calcRabbits() );
[ 17 ]
(1)
(2)
Here, in the lines (1) and (2), the input field and the output label are bound to
the yearsInput and output variables. This is always done in the same way: the
querySelector() function takes as its argument a CSS selector; in this case, the
ID of the input field (an ID is preceded by a # sign). We typed yearsInput as
InputElement (because it is bound to an input field). This way, we can access its
value, which is always string. We then convert this string into an int type with
the int.parse()function, because calculateRabbits needs an int parameter.
The result is shown as HTML in the output label via string substitution, see the
following screenshot:
[ 18 ]
Chapter 1
All the objects in the Dart code that are bound to the HTML elements are instances
of the Element class. Notice how you can change the Dart and HTML code, and save
and hit refresh in Dartium (Chrome) to get the latest version of your app.
Example 2: banking
All the variables (strings, numbers, and also functions) in Dart are objects, so
they are also instances of a class. The class concept is very important in modeling
entities in real-world applications, making our code modular and reusable. We will
now demonstrate how to make and use a simple class in Dart by modeling a bank
account. The most obvious properties of such an object are the owner of the account,
the bank account number, and the balance (the amount of money it contains). We
want to be able to deposit or withdraw an amount of money so as to increase or
decrease the balance, respectively. This can be coded in a familiar and compact way
in Dart, as shown in the following code:
class BankAccount {
String owner, number;
double balance;
// constructor:
BankAccount(this.owner, this.number, this.balance);
// methods:
deposit(double amount) => balance += amount;
withdraw(double amount) => balance -= amount;
}
(1)
(2)
Notice the elegant constructor syntax in line (1), where the incoming parameter
values are automatically assigned to the object fields via this. The methods (line (2))
can also use the shorthand => function syntax, because the body contains only one
expression. If you prefer the {} syntax, they will be written as follows:
deposit(double amount) {
balance += amount;
return balance;
}
The code in main() makes a BankAccount object ba and exercises its methods (see
the banking_v1.dart program):
main() {
var ba = new BankAccount("John Gates",
"075-0623456-72", 1000.0);
print("Initial balance:\t\t ${ba.balance} \$");
ba.deposit(250.0);
[ 19 ]
1000.0 $
1250.0 $
1150.0 $
Notice how when you type ba. in the editor, the list of the BankAccount class
members appears to autocomplete your code. By convention, variables (objects)
and functions (or methods) start with a lower case letter and follow the CamelCase
notation (http://en.wikipedia.org/wiki/CamelCase), while class names start with
a capital letter as well as the word parts in the name. Remember Dart is case sensitive!
The HTML5 placeholder attribute lets you specify a default text that appears in
the field.
We specify a list tag (UListElement), which we will fill up in our code:
<ul id="list"/>
(1)
(2)
(3)
Chapter 1
var newTask = new LIElement();
newTask.text = task.value;
task.value = '';
list.children.add(newTask);
(4)
(5)
(6)
(7)
We bind our HTML elements to the Dart objects task and list in the lines (1) and
(2). In line (3), we attach an addItem event handler to the onChange event of the
textfield task: this fires, when the user enters something in the field and leaves it
(either by pressing Tab or Enter). UListElement is, in fact, a collection of LIElements
(these are its children). So, for each new task, we will make LIElement in (4),
assign the task's value to it in (5), clear the input field in (6), and add the new
LIElement to the list in (7). In the following screenshot, you can see some tasks to
be performed:
Of course, this version isn't very useful (unless you want to make a print of your
screen); our tasks aren't recorded and we can't indicate the tasks are finished. Don't
worry, we will enhance this app in the future versions.
[ 21 ]
Summary
We covered a lot of ground in this introductory chapter but, by now, you know the
reasons for using Dart in the context of web applications. We also saw where Dart
apps can live, how they are executed, and the various tools to work with Dart, in
particular, the Dart Editor.
You also got acquainted with some simple command-line and web Dart apps and
got a feeling for the Dart syntax. In the next chapter, we will explore the various code
and data structures of Dart more systematically. Any obscurities that are still there in
your mind will surely disappear. More coming soon to a Dart center near you...
[ 22 ]
www.PacktPub.com
Stay Connected: