Chromium Code Reviews| Index: src/site/articles/trydart/index.markdown |
| diff --git a/src/site/articles/trydart/index.markdown b/src/site/articles/trydart/index.markdown |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..630b90f03d88e526d2ab814b5d4c15f6d26538fd |
| --- /dev/null |
| +++ b/src/site/articles/trydart/index.markdown |
| @@ -0,0 +1,1393 @@ |
| +--- |
| +layout: default |
| +title: "Try Dart" |
| +description: "Write some Dart code. Learn some stuff." |
| +has-permalinks: true |
| +tutorial: |
| + id: trydart |
| +js: |
| +- url: /js/os-switcher.js |
| + defer: true |
| +- url: /js/editor-downloads-analytics.js |
| + defer: true |
| +- url: /js/editor-version.js |
| + defer: true |
| +header: |
| + css: ["/articles/trydart/trydart.css"] |
| +--- |
| + |
| +# {{ page.title }} |
| + |
| +## Got an hour? Write a Dart app. |
| + |
| +In this code lab, |
| +you build a pirate badge generator from a skeleton app. |
| + |
| +<strong>Build this app!</strong> |
| + |
| +<iframe class="running-app-frame" |
| + style="height:220px;width:530px;" |
| + src="examples/6-piratebadge_json/piratebadge.html"> |
| +</iframe> |
| + |
| +<hr> |
| + |
| +## The Map |
| + |
| +* [Step 0: Set up](#set-up) |
| +* [Step 1: Run the skeleton app](#step-one) |
| +* [Step 2: Add an input field](#step-two) |
| +* [Step 3: Add a button](#step-three) |
| +* [Step 4: Create a class](#step-four) |
| +* [Step 5: Save to local storage](#step-five) |
| +* [Step 6: Read names from JSON file using HttpRequest](#step-six) |
| +* [Step 7: What next?](#step-seven) |
| + |
| + |
| +<hr> |
| + |
| +## Step 0: Set up {#set-up} |
| + |
| +In this step, you download Dart and get the sample code. |
| + |
| +#### <i class="icon-anchor"> </i> Get Dart. |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +If you haven't already done so, |
| +get the Dart download. |
| + |
| +{% include downloads/_dart-editor.html %} |
| + |
| +<p markdown="1"> |
| + The Dart tools |
| + work in recent versions of |
| + {% include os-choices.html %} |
| +Having trouble? Go to the |
| +[Troubleshooting Dart Editor](/tools/editor/troubleshoot.html) page. |
| +</p> |
| +</div> |
| + |
| +#### <i class="icon-anchor"> </i> Start the Editor. |
| + |
| +<div class="trydart-step-details"> |
| +Start Dart Editor by double clicking its icon |
| +<img src="/imgs/Dart_Logo_21.png" |
| + width="21" height="21" alt="Dart Editor icon">. |
| +</div> |
| + |
| +#### <i class="icon-anchor"> </i> Get the sample code. |
| + |
| +<div class="trydart-step-details"> |
| +<a href="https://github.com/dart-lang/dart-tutorials-samples/archive/master.zip"> |
| + Download |
| +</a> |
| +the sample code. |
| +Unzip the ZIP file. |
| +</div> |
| + |
| +#### <i class="icon-anchor"> </i> Open the directory. |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +In Dart Editor, |
| +open the `piratebadge` directory from the ZIP file |
| +with **File>Open Existing Folder...**. |
| +</div> |
| + |
| +<div class="row"> <div class="span7" markdown="1"> |
| + |
| + |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +<i class="icon-key"> </i> <strong> Key Information </strong> |
| + |
| +* Dart web apps use the public `browser` package to run on a web page. |
| +This project has all of the package dependencies set up for you |
| +and the packages installed. |
| +The packages directory, the `pubspec.yaml`, and `pubspec.lock` files are |
| +all related to library dependencies. |
| + |
| +* Several numbered directories contain the completed code for each step. |
| +`1-blankbadge` contains the skeletal version of the app that you begin with. |
| +`6-piratebadge_json` contains the final version of the app. |
| + |
| +* The `piratebadge.css` file |
| +provides the CSS styles for all steps of the app. |
| +You don't change this file during this code lab. |
| + |
| + {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} |
| + |
| +</div> </div> |
| + |
| +<hr> |
| + |
| +##Step 1: Run the skeleton app {#step-one} |
| + |
| +In this step, you open the source files for the skeleton app, |
| +familiarize yourself with the Dart and HTML code, |
| +and run the app. |
| + |
| +#### <i class="icon-anchor"> </i> Expand the 1-blankbadge directory. |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +In Dart Editor, expand the `1-blankbadge` directory, |
| +which contains two files, `piratebadge.html` and `piratebadge.dart`. |
| +</div> |
| + |
| +#### <i class="icon-anchor"> </i> Open the files. |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +Open both files by double-clicking each filename in Dart Editor. |
| +</div> |
| + |
| +#### <i class="icon-anchor"> </i> Review the code |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +Get familiar with the HTML and the Dart code for the skeleton version of the app. |
| +The interesting bits are highlighted below. |
| +</div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +##### piratebadge.html |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +{% prettify html%} |
| +<html> |
| + <head> |
| + <meta charset="utf-8"> |
| + <title>Pirate badge</title> |
| + <link rel="stylesheet" href="../piratebadge.css"> |
| + </head> |
| + <body> |
| + <h1>Pirate badge</h1> |
| + |
| + <div class="widgets"> |
| + [[highlight]]<span>TO DO: Put the UI widgets here.</span>[[/highlight]] |
| + </div> |
| + <div class="outer"> |
| + <div class="boilerplate"> |
| + Arrr! Me name is |
| + </div> |
| + <div class="name"> |
| + [[highlight]]<span id="badgeName"> </span>[[/highlight]] |
| + </div> |
| + </div> |
| + |
| + [[highlight]]<script type="application/dart" src="piratebadge.dart"></script>[[/highlight]] |
| + [[highlight]]<script src="packages/browser/dart.js"></script>[[/highlight]] |
| + </body> |
| +</html> |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +<i class="icon-key"> </i> <strong> Key Information </strong> |
| + |
| +* During the code lab, |
| +all the changes you make to `piratebadge.html` are within |
| +the <div> element identified with the class `widgets`. |
| + |
| +* The <span> element with the ID `badgeName` |
| +is programmatically updated by the Dart code |
|
sethladd
2013/10/23 21:15:06
you don't show the updating here. How about "is us
|
| +based on user input. |
| + |
| +* The `piratebadge.dart` script provides the main program for the app. |
| + |
| +* The `packages/browser/dart.js` script is a bootstrap script |
| +that takes care of turning on the Dart VM, |
| +as well as compatibility with non-Dart browsers. |
| + |
| +</div> </div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +##### piratebadge.dart |
| +</div> |
| + |
| +<div class="row"> <div class="span7" markdown="1"> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +{% prettify dart %} |
| +[[highlight]]void main() { |
| + // Your app starts here. |
| +} |
| +[[/highlight]] |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* This file is included in the HTML file |
|
sethladd
2013/10/23 21:15:06
it's not included, it's referenced by the main HTM
|
| +with the <script> tag. |
| + |
| +* The `main()` function is a top-level function. |
| + Dart calls this function when your app starts. |
| + |
| + {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} |
| +</div> </div> |
| + |
| +#### <i class="icon-anchor"> </i> Run the app. |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +To run the app in Dart Editor, select `piratebadge.html` |
| +and click the Run button |
| +<img src="images/run.png" width="16" height="16" |
| + alt="Run button">. |
| + |
| +You should see a TO DO comment on the left |
| +and a red and white name badge on the right. |
| +</div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +<iframe class="running-app-frame" |
| + style="height:220px;width:530px;" |
| + src="examples/1-blankbadge/piratebadge.html"> |
| +</iframe> |
| +</div> |
| + |
| +<hr> |
| + |
| +##Step 2: Add an input field {#step-two} |
| + |
| +In this step, you add an input field to the app. |
| +As you type into the text field, |
| +the Dart code updates the badge from the value of the text field. |
| + |
| +#### <i class="icon-anchor"> </i> Try it! |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +Type in the input field. |
| + |
| +<iframe class="running-app-frame" |
| + style="height:220px;width:530px;" |
| + src="examples/2-inputnamebadge/piratebadge.html"> |
| +</iframe> |
| +</div> |
| + |
| +#### <i class="icon-anchor"> </i> Edit piratebadge.html. |
| + |
| +<div class="row"> <div class="span7" markdown="1"> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +Add the <input> tag to the HTML code |
| +within the `widgets` <div>. |
| + |
| +{% prettify html %} |
| +... |
| +<div class="widgets"> |
| +[[highlight]] <div> |
| + <input type="text" id="inputName"> |
| + </div>[[/highlight]] |
| +</div> |
| +... |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +<i class="icon-key"> </i> <strong> Key Information </strong> |
| + |
| +* The ID for the input element is `inputName`. |
| +Dart uses CSS selectors, like this ID, |
| +to get elements from the DOM. |
| + |
| + {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} |
| + |
| +</div> </div> |
| + |
| +#### <i class="icon-anchor"> </i> Edit piratebadge.dart. |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +Import the |
| +<a href="https://api.dartlang.org/dart_html.html" target="_blank">dart:html</a> |
| +library at the top of the file: |
| + |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +{% prettify dart %} |
| +[[highlight]]import 'dart:html';[[/highlight]] |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* This imports all classes and other resources from dart:html, |
| +which provides HTML elements and access to the DOM. |
| + |
| +</div> </div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| + |
| +Register a function to handle input events on the input field. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +{% prettify dart %} |
| +void main() { |
| +[[highlight]] query('#inputName').onInput.listen(updateBadge);[[/highlight]] |
| +} |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* The `query()` function, defined in |
| +dart:html, gets an element from the DOM. |
| +Here, the code uses the ID `#inputName` |
| +to specify the input field. |
| + |
| +* `onInput` registers an event handler for input events. |
| + |
| +* An input event occurs when the user presses a key. |
| + |
| +* You can use either single or double quotes to create a string. |
| + |
| +</div> </div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| + |
| +Implement the event handler as a top-level function. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +{% prettify dart %} |
| +[[highlight]]void updateBadge(Event e) { |
| + query('#badgeName').text = (e.target as InputElement).value; |
| +}[[/highlight]] |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* This function sets the text of the `badgeName` element from the value of the input field. |
| + |
| +* The `updateBadge()` function is an event handler based on its signature. |
| + |
| +* The element that generated the event, the input field, is `e.target`. |
| + |
| +* The `as` keyword typecasts `e.target` to an |
| +<a href="https://api.dartlang.org/dart_html/InputElement.html" target="_blank">InputElement</a> |
| +to reference its value field. |
| + |
| + {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} |
| + |
| +</div> </div> |
| + |
| +<hr> |
| + |
| +##Step 3: Add a button {#step-three} |
| + |
| +In this step, you add a button to the app. |
| +The button is enabled when the text field contains no text. |
| +When the user clicks the button, |
| +the app puts the name `Anne Bonney` on the badge. |
| + |
| +#### Try it! |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +Type in the input field. |
| +Remove the text from the input field. |
| +Click the button. |
| +</div> |
| + |
| +<div class="trydart-step-details"> |
| +<iframe class="running-app-frame" |
| + style="height:220px;width:530px;" |
| + src="examples/3-buttonbadge/piratebadge.html"> |
| +</iframe> |
| +</div> |
| + |
| +#### <i class="icon-anchor"> </i> Edit piratebadge.html. |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +Add the <button> tag below the input field. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify html %} |
| +... |
| +<div class="widgets"> |
| + <div> |
| + <input type="text" id="inputName"> |
| + </div> |
| +[[highlight]] <div> |
| + <button id="generateButton">Generate badge</button> |
| + </div>[[/highlight]] |
| +</div> |
| +... |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +<i class="icon-key"> </i> <strong> Key Information </strong> |
| + |
| +* The button has the ID `generateButton` so |
| +the Dart code can get the element. |
| + |
| +* The Dart code changes the button dynamically based on user input. |
| + |
| +</div> </div> |
| + |
| +#### <i class="icon-anchor"> </i> Edit piragebadge.dart. |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +Below the import, declare a top-level variable to hold the |
| +<a href="https://api.dartlang.org/dart_html/ButtonElement.html" target="_blank">ButtonElement</a>. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +import `dart:html`; |
| + |
| +[[highlight]]ButtonElement genButton;[[/highlight]] |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* Top-level variables are names at the library level. |
| + |
| + {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} |
| + |
| +</div> </div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| + |
| +Wire up the button with an event handler. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +void main() {} |
| + query('#inputName').onInput.listen(updateBadge); |
| + [[highlight]]genButton = query('#generateButton') |
| + ..onClick.listen(generateBadge)[[/highlight]] |
| +} |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* `onClick` registers a mouse click handler. |
| + |
| +* The cascade operator (`..`) allows you to perform multiple |
| +operations on the members of a single object. |
| + |
| + {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} |
| + |
| +</div> </div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| + |
| +Add a top-level setter that changes the name on the badge. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +[[highlight]]set badgeName(String newName) { |
| + query('#badgeName').text = newName; |
| +} [[/highlight]] |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* Setters are special methods that provide write access to an object’s properties. |
| + |
| +* Here the setter updates the HTML page with a new name. |
| + |
| + {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} |
| + |
| +</div> </div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| + |
| +Implement the click handler for the button. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +[[highlight]]void generateBadge(Event e) { |
| + badgeName = 'Anne Bonney'; |
| +}[[/highlight]] |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* This function calls the setter to set the badge name to `Anne Bonney`. |
| +Note that the call to a setter looks like a field assignment. |
| + |
| + {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} |
| + |
| +</div> </div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| + |
| +Replace the contents of the `updateBadge()` function |
| +with this code. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +void updateBadge(Event e) { |
| +[[highlight]] String inputName = (e.target as InputElement).value; |
| + |
| + badgeName = inputName; |
| + if (inputName.trim().isEmpty) { |
| + genButton..disabled = false |
| + ..text = 'Generate badge'; |
| + } else { |
| + genButton..disabled = true |
| + ..text = 'Arrr! Remove the text!'; |
| + }[[/highlight]] |
| +} |
| +{% endprettify %} |
| +</div> |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* The |
| +<a href="https://api.dartlang.org/dart_core/String.html" target="_blank">String</a> |
| +class has useful functions and properties for dealing with strings, |
| +such as `trim()` and `isEmpty`. |
| + |
| +* String comes from the |
| +<a href="https://api.dartlang.org/dart_core.html" target="_blank">dart:core</a> |
| +library, which is automatically imported into every Dart program. |
| + |
| +* Here, you see the cascade operator in action again. |
| + |
| +* This code calls the setter to set the badge name. |
| + |
| +* Dart has common programming language constructs like `if`-`else`. |
| + |
| +</div></div> |
| + |
| +<hr> |
| + |
| +##Step 4: Create a PirateName class {#step-four} |
| + |
| +In this step, you change only the Dart code. |
| +You create a class to represent a pirate name. |
| +When created, an instance of this class |
| +randomly selects a name and appellation from a list, |
| +or optionally you can provide a name |
| +and an appellation to the constructor. |
| + |
| +#### Try it! |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +Type in the input field. |
| +Remove the text from the input field. |
| +Click the button. |
| +</div> |
| + |
| +<div class="trydart-step-details"> |
| +<iframe class="running-app-frame" |
| + style="height:220px;width:530px;" |
| + src="examples/4-classbadge/piratebadge.html"> |
| +</iframe> |
| +</div> |
| + |
| +#### <i class="icon-anchor"> </i> Edit piratebadge.dart. |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +Add an import to the top of the file. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +import 'dart:html'; |
| +import 'dart:math' show Random; |
| +{% endprettify %} |
| +</div> |
| +</div> <div class="span5" markdown="1"> |
| + |
| +<i class="icon-key"> </i> <strong> Key Information </strong> |
| + |
| +* Using the `show` keyword, |
| +you can import just the classes you need. |
| + |
| +* <a href="https://api.dartlang.org/dart_math/Random.html" target="_blank">Random</a> |
| +provides a random number generator. |
| + |
| +</div></div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| + |
| +Add a class declaration to the bottom of the file. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +class PirateName { |
| + ... |
| +} |
| +{% endprettify %} |
| +</div> |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* The class declaration provides the class name. |
| + |
| +</div></div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| + |
| +Create a class-level Random object. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +class PirateName { |
| + [[highlight]]static final Random indexGen = new Random();[[/highlight]] |
| +} |
| +{% endprettify %} |
| +</div> |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* `static` defines a class-level field. That is, |
| +the random number generator is shared with all |
| +instances of this class. |
| + |
| +* Use `new` to call a constructor. |
| + |
| +</div></div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| + |
| +Add two instance variables to class, |
| +one for the first name and one for the appellation. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +class PirateName { |
| + ... |
| +[[highlight]] String _firstName; |
| + String _appellation;[[/highlight]] |
| +} |
| +{% endprettify %} |
| +</div> |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* Private variables start with underscore (`_`). |
| + |
| +</div></div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| + |
| +Create two static lists within the class |
| +that provide a small collection of names and appellations to choose from. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +class PirateName { |
| + ... |
| +[[highlight]] static final List names = [ |
| + 'Anne', 'Mary', 'Jack', 'Morgan', 'Roger', |
| + 'Bill', 'Ragnar', 'Ed', 'John', 'Jane' ]; |
| + static final List appellations = [ |
| + 'Black','Damned', 'Jackal', 'Red', 'Stalwart', 'Axe', |
| + 'Young', 'Old', 'Angry', 'Brave', 'Crazy', 'Noble'];[[/highlight]] |
| +} |
| +{% endprettify %} |
| +</div> |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* `final` variables cannot change. |
| + |
| +* Lists are built into the language. |
| +These lists are created using list literals. |
| + |
| +* The |
| +<a href="https://api.dartlang.org/dart_core/List.html" target="_blank">List</a> |
| +class provides the API for lists. |
| + |
| +</div></div> |
| + |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| + |
| +Provide a constructor for the class. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +class PirateName { |
| + ... |
| +[[highlight]] PirateName({String firstName, String appellation}) { |
| + if (firstName == null) { |
| + _firstName = names[indexGen.nextInt(names.length)]; |
| + } else { |
| + _firstName = firstName; |
| + } |
| + if (appellation == null) { |
| + _appellation = appellations[indexGen.nextInt(appellations.length)]; |
| + } else { |
| + _appellation = appellation; |
| + } |
| + }[[/highlight]] |
| +} |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* Constructors have the same name as the class. |
| + |
| +* Optional parameters are enclosed in curly brackets (`{` and `}`). |
| + |
| +* The `nextInt()` function gets a new random integer |
| +from the random number generator. |
| + |
| +* Square brackets (`[` and `]`) are operators to index into a list. |
| + |
| +* The `length` property returns the length of a list. |
| + |
| +* The code uses a random number as an index into the list. |
| + |
| +</div> </div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| + |
| +Provide a getter for the pirate name. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +class PirateName { |
| + ... |
| +[[highlight]] String get pirateName => '$_firstName the $_appellation';[[/highlight]] |
| +} |
| +{% endprettify %} |
| +</div> |
| + |
| +</div><div class="span5" markdown="1"> |
| + |
| +* Getters are special methods that provide read access to an object’s properties. |
| + |
| +</div></div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| + |
| +Modify the setter `badgeName()` to use a PirateName instead of a String: |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +set badgeName([[highlight]]PirateName newName[[/highlight]]) { |
| + query('#badgeName').text = [[highlight]]newName.pirateName[[/highlight]]; |
| +} |
| +{% endprettify %} |
| +</div> |
| + |
| +</div><div class="span5" markdown="1"> |
| + |
| +* This code calls the getter to get the PirateName as a string. |
| + |
| +</div></div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| + |
| +Change `updateBadge()` to generate a PirateName based on the input field value. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +void updateBadge(Event e) { |
| + String inputName = (e.target as InputElement).value; |
| + |
| + [[highlight]]badgeName = new PirateName(firstName: inputName);[[/highlight]] |
| + ... |
| +} |
| +{% endprettify %} |
| +</div> |
| + |
| +</div><div class="span5" markdown="1"> |
| + |
| +* The call to the constructor provides a value for one optional parameter. |
| + |
| +</div></div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| + |
| +Change `generateBadge()` to generate a PirateName instead of using `Anne Bonney`. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +void generateBadge(Event e) { |
| + [[highlight]]badgeName = new PirateName();[[/highlight]] |
| +} |
| +{% endprettify %} |
| +</div> |
| + |
| +</div><div class="span5" markdown="1"> |
| + |
| +* The call to the constructor passes no parameters. |
| + |
| +</div></div> |
| + |
| +##Step 5: Save to local storage {#step-five} |
| + |
| +In this step, you give the app some persistence |
| +by saving the badge name to local storage each time it changes. |
| +When you restart the app, |
| +it initializes the badge from the saved name. |
| + |
| +#### Try it! |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +Click the button, then kill the app by closing this window. |
| +Open this page up in a new window. |
| +</div> |
| + |
| +<div class="trydart-step-details"> |
| +<iframe class="running-app-frame" |
| + style="height:220px;width:530px;" |
| + src="examples/5-localbadge/piratebadge.html"> |
| +</iframe> |
| +</div> |
| + |
| +#### <i class="icon-anchor"> </i> Edit piratebadge.dart. |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +Import the JSON converter from the |
| +<a href="https://api.dartlang.org/dart_convert.html" target="_blank">dart:convert</a> |
| + library. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +import 'dart:html'; |
| +import 'dart:math' show Random; |
| +[[highlight]] |
| +import 'dart:convert' show JSON;[[/highlight]] |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +<i class="icon-key"> </i> <strong> Key Information </strong> |
| + |
| +* `JSON` provides convenient access to the most common JSON use cases. |
| + |
| +</div> </div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| + |
| +Add a new constructor to the PirateName class. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +class PirateName { |
| + ... |
| +[[highlight]] PirateName.fromJSON(String jsonString) { |
| + Map storedName = JSON.decode(jsonString); |
| + _firstName = storedName['f']; |
| + _appellation = storedName['a']; |
| + }[[/highlight]] |
| +} |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* The constructor creates a new PirateName instance from a JSON-encoded string. |
| + |
| +* `PirateName.fromJson` is a named constructor. |
| + |
| +* `JSON.decode()` parses a JSON string and creates Dart objects from it. |
| + |
| +* The pirate name is decoded into a |
| +<a href="https://api.dartlang.org/dart_core/Map.html" target="_blank">Map</a> |
| +object. |
| + |
| +</div> </div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| + |
| +Add a getter to the PirateName class |
| +that encodes a pirate name in a JSON string. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +class PirateName { |
| + ... |
| + [[highlight]]String toJsonString() => '{ "f": "$_firstName", "a": "$_appellation" } ';[[/highlight]] |
| +} |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* The getter formats the JSON string using the map format. |
| + |
| +</div> </div> |
| + |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| + |
| +Declare a top-level boolean variable. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +[[highlight]]final String TREASUREKEY = 'pirateName';[[/highlight]] |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* This string is a key to the local storage, |
| +hopefully unique. |
| + |
| +</div> </div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| + |
| +Save the pirate name when the badge name changes. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +set badgeName(PirateName newName) { |
| + query('#badgeName').text = newName.pirateName; |
| + [[highlight]]window.localStorage[TREASUREKEY] = newName.toJsonString();[[/highlight]] |
| +} |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* Local storage is provided by the browser's window. |
| + |
| + {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} |
| + |
| +</div> </div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| + |
| +Add a top-level getter. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +[[highlight]]PirateName get pirateNameFromStorage { |
| + String storedName = window.localStorage[TREASUREKEY]; |
| + if (storedName != null) { |
| + return new PirateName.fromJSON(storedName); |
| + } else { |
| + return null; |
| + } |
| +}[[/highlight]] |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* The getter retrieves the pirate name from local storage |
| +and creates a PirateName object from it. |
| + |
| + {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} |
| + |
| +</div> </div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +<hr> |
| +Call the getter from the `main()` function. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +void main() { |
| + ... |
| + [[highlight]]badgeName = pirateNameFromStorage;[[/highlight]] |
| +} |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* Initialize the badge name from local storage. |
| + |
| + {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} |
| + |
| +</div> </div> |
| + |
| +##Step 6: Read names from JSON-encoded file {#step-six} |
| + |
| +In this step, you change the PirateName class to get |
| +the list of names and appellations from a JSON file. |
| +This gives you a chance to add more names and |
| +appellations to the program. |
| + |
| +#### Try it! |
| + |
| +<div class="trydart-step-details"> |
| +The final app is running here. |
| +</div> |
| + |
| +<div class="trydart-step-details"> |
| +<iframe class="running-app-frame" |
| + style="height:220px;width:530px;" |
| + src="examples/6-piratebadge_json/piratebadge.html"> |
| +</iframe> |
| +</div> |
| + |
| +#### <i class="icon-anchor"> </i> Create piratenames.json. |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +Create a JSON encoded file named `piratenames.json`. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +{ "names": [ "Anne", "Bette", "Cate", "Dawn", |
| + "Elise", "Faye", "Ginger", "Harriot", |
| + "Izzy", "Jane", "Kaye", "Liz", |
| + "Maria", "Nell", "Olive", "Pat", |
| + "Queenie", "Rae", "Sal", "Tam", |
| + "Uma", "Violet", "Wilma", "Xana", |
| + "Yvonne", "Zelda", |
| + "Abe", "Billy", "Caleb", "Davie", |
| + "Eb", "Frank", "Gabe", "House", |
| + "Icarus", "Jack", "Kurt", "Larry", |
| + "Mike", "Nolan", "Oliver", "Pat", |
| + "Quib", "Roy", "Sal", "Tom", |
| + "Ube", "Val", "Walt", "Xavier", |
| + "Yvan", "Zeb"], |
| + "appellations": [ "Awesome", "Black", "Captain", "Damned", |
| + "Even", "Fighter", "Great", "Hearty", |
| + "Irate", "Jackal", "King", "Lord", |
| + "Mighty", "Noble", "Old", "Powerful", |
| + "Quick", "Red", "Stalwart", "Tank", |
| + "Ultimate", "Vicious", "Wily", "aXe", |
| + "Young", "Zealot", |
| + "Angry", "Brave", "Crazy", "Damned", |
| + "Eager", "Fool", "Greedy", "Hated", |
| + "Idiot", "Jinxed", "Kind", "Lame", |
| + "Maimed", "Naked", "Old", "Pale", |
| + "Queasy", "Rat", "Sandy", "Tired", |
| + "Ugly", "Vile", "Weak", "Xeric", |
| + "Yellow", "Zesty"]} |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +<i class="icon-key"> </i> <strong> Key Information </strong> |
| + |
| +* Put the file alongside the Dart and HTML files for the app. |
| + |
| +* The file contains the code for a map |
| +that contains two lists that each contain strings. |
| + |
| +</div> </div> |
| + |
| +#### <i class="icon-anchor"> </i> Edit piratebadge.html. |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +Disable the input field and the button. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify html %} |
| +... |
| + <div> |
| + <input type="text" id="inputName" [[highlight]]disabled[[/highlight]]> |
| + </div> |
| + <div> |
| + <button id="generateButton" [[highlight]]disabled[[/highlight]]>Generate badge</button> |
| + </div> |
| +... |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| + |
| +* The Dart code enables the text field and |
| +the button after the pirate names are successfully read from |
| +the JSON file. |
| + |
| +</div> </div> |
| + |
| +#### <i class="icon-anchor"> </i> Edit piratebadge.dart. |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +Add an import to the top of the file. |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +import 'dart:html'; |
| +import 'dart:math' show Random; |
| +import 'dart:convert' show JSON; |
| + |
| +[[highlight]]import 'dart:async' show Future;[[/highlight]] |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* The |
| +<a href="https://api.dartlang.org/dart_async.html" target="_blank">dart:async</a> |
| + library provides for asynchronous programming. |
| + |
| +* A <a href="https://api.dartlang.org/dart_async/Future.html" target="_blank">Future</a> |
| +provides a way to get a value in the future. |
| + |
| +</div> </div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| +Replace the list literals with these static empty lists: |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +class PirateName { |
| + ... |
| + [[highlight]]static List<String> names = []; |
| + static List<String> appellations = [];[[/highlight]] |
| + ... |
| +} |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* `[]` is equivalent to `new List()`. |
| + |
| +</div> </div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +<hr> |
| + |
| +Add two static functions to the PirateName class: |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +class PirateName { |
| + ... |
| + |
| + [[highlight]]static Future readyThePirates() { |
| + var path = 'piratenames.json'; |
| + return HttpRequest.getString(path) |
| + .then(_parsePirateNamesFromJSON); |
| + } |
| + |
| + static _parsePirateNamesFromJSON(String jsonString) { |
| + Map pirateNames = JSON.decode(jsonString); |
| + names = pirateNames['names']; |
| + appellations = pirateNames['appellations']; |
| + }[[/highlight]] |
| +} |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* <a href="https://api.dartlang.org/dart_html/HttpRequest.html" target="_blank">HttpRequest</a> |
| +is a utilify for retrieving data from a URL. |
| + |
| +* `getString()` is a convenience method for doing a simple |
| +GET request that returns a string. |
| + |
| +* The code uses a |
| +<a href="https://api.dartlang.org/dart_async/Future.html" target="_blank">Future</a> |
| +to perform the GET asynchronously. |
| + |
| +* The callback function for `.then()` is called when |
| +the Future completes successfully. |
| + |
| +* When the Future completes successfully, |
| +the pirate names are read from the JSON file. |
| + |
| +* Futures are infectious. |
| +`readyThePirates` must return the Future so the main program can handle it. |
| + |
| +</div> </div> |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +<hr> |
| +Modify the `main()` function to look like this: |
| +</div> |
| + |
| +<div class="row"> <div class="span7"> |
| + |
| +<div class="trydart-step-details"> |
| +{% prettify dart %} |
| +void main() { |
| + InputElement inputField = query('#inputName') |
| + ..onInput.listen(updateBadge); |
| + genButton = query('#generateButton') |
| + ..onClick.listen(generateBadge); |
| + |
| + badgeNameElement = query('#badgeName'); |
| + |
| + PirateName.readyThePirates() |
| + .then((_) { |
| + inputField.disabled = false; //enable |
| + genButton.disabled = false; //enable |
| + badgeName = pirateNameFromStorage; |
| + }) |
| + .catchError((arrr) { |
| + print('Error initializing pirate names: $arrr'); |
| + badgeNameElement.text = 'Arrr! No names.'; |
| + }); |
| +} |
| +{% endprettify %} |
| +</div> |
| + |
| +</div> <div class="span5" markdown="1"> |
| + |
| +* When the Future successfully completes, |
| +the `then()` callback function is called. |
| + |
| +* The callback function enables the UI |
| +and gets the stored name. |
| + |
| +* If the Future encounters an error |
| +the `catchError` callback function is called |
| +and the program displays an error message, |
| +leaving the UI disabled. |
| + |
| +</div> </div> |
| + |
| +##Step 7: What next? {#step-seven} |
| + |
| +#### <i class="icon-anchor"> </i> Check out the samples. |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| + |
| +Run some Dart programs online and check out the source code |
| +on our [Samples page](/samples/). |
| +</div> |
| + |
| +#### <i class="icon-anchor"> </i> Read the tutorials. |
| + |
| +<div class="trydart-step-details" markdown="1"> |
| +Learn more about Dart from |
| +the [Dart tutorials](/docs/tutorials/). |
| +</div> |