OLD | NEW |
---|---|
(Empty) | |
1 --- | |
2 layout: default | |
3 title: "Try Dart" | |
4 description: "Write some Dart code. Learn some stuff." | |
5 has-permalinks: true | |
6 tutorial: | |
7 id: trydart | |
8 js: | |
9 - url: /js/os-switcher.js | |
10 defer: true | |
11 - url: /js/editor-downloads-analytics.js | |
12 defer: true | |
13 - url: /js/editor-version.js | |
14 defer: true | |
15 header: | |
16 css: ["/articles/trydart/trydart.css"] | |
17 --- | |
18 | |
19 # {{ page.title }} | |
20 | |
21 ## Got an hour? Write a Dart app. | |
22 | |
23 In this code lab, | |
24 you build a pirate badge generator from a skeleton app. | |
25 | |
26 <strong>Build this app!</strong> | |
27 | |
28 <iframe class="running-app-frame" | |
29 style="height:220px;width:530px;" | |
30 src="examples/6-piratebadge_json/piratebadge.html"> | |
31 </iframe> | |
32 | |
33 <hr> | |
34 | |
35 ## The Map | |
36 | |
37 * [Step 0: Set up](#set-up) | |
38 * [Step 1: Run the skeleton app](#step-one) | |
39 * [Step 2: Add an input field](#step-two) | |
40 * [Step 3: Add a button](#step-three) | |
41 * [Step 4: Create a class](#step-four) | |
42 * [Step 5: Save to local storage](#step-five) | |
43 * [Step 6: Read names from JSON file using HttpRequest](#step-six) | |
44 * [Step 7: What next?](#step-seven) | |
45 | |
46 | |
47 <hr> | |
48 | |
49 ## Step 0: Set up {#set-up} | |
50 | |
51 In this step, you download Dart and get the sample code. | |
52 | |
53 #### <i class="icon-anchor"> </i> Get Dart. | |
54 | |
55 <div class="trydart-step-details" markdown="1"> | |
56 If you haven't already done so, | |
57 get the Dart download. | |
58 | |
59 {% include downloads/_dart-editor.html %} | |
60 | |
61 <p markdown="1"> | |
62 The Dart tools | |
63 work in recent versions of | |
64 {% include os-choices.html %} | |
65 Having trouble? Go to the | |
66 [Troubleshooting Dart Editor](/tools/editor/troubleshoot.html) page. | |
67 </p> | |
68 </div> | |
69 | |
70 #### <i class="icon-anchor"> </i> Start the Editor. | |
71 | |
72 <div class="trydart-step-details"> | |
73 Start Dart Editor by double clicking its icon | |
74 <img src="/imgs/Dart_Logo_21.png" | |
75 width="21" height="21" alt="Dart Editor icon">. | |
76 </div> | |
77 | |
78 #### <i class="icon-anchor"> </i> Get the sample code. | |
79 | |
80 <div class="trydart-step-details"> | |
81 <a href="https://github.com/dart-lang/dart-tutorials-samples/archive/master.zip" > | |
82 Download | |
83 </a> | |
84 the sample code. | |
85 Unzip the ZIP file. | |
86 </div> | |
87 | |
88 #### <i class="icon-anchor"> </i> Open the directory. | |
89 | |
90 <div class="trydart-step-details" markdown="1"> | |
91 In Dart Editor, | |
92 open the `piratebadge` directory from the ZIP file | |
93 with **File>Open Existing Folder...**. | |
94 </div> | |
95 | |
96 <div class="row"> <div class="span7" markdown="1"> | |
97 | |
98  | |
99 | |
100 </div> <div class="span5" markdown="1"> | |
101 | |
102 <i class="icon-key"> </i> <strong> Key Information </strong> | |
103 | |
104 * Dart web apps use the public `browser` package to run on a web page. | |
105 This project has all of the package dependencies set up for you | |
106 and the packages installed. | |
107 The packages directory, the `pubspec.yaml`, and `pubspec.lock` files are | |
108 all related to library dependencies. | |
109 | |
110 * Several numbered directories contain the completed code for each step. | |
111 `1-blankbadge` contains the skeletal version of the app that you begin with. | |
112 `6-piratebadge_json` contains the final version of the app. | |
113 | |
114 * The `piratebadge.css` file | |
115 provides the CSS styles for all steps of the app. | |
116 You don't change this file during this code lab. | |
117 | |
118 {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} | |
119 | |
120 </div> </div> | |
121 | |
122 <hr> | |
123 | |
124 ##Step 1: Run the skeleton app {#step-one} | |
125 | |
126 In this step, you open the source files for the skeleton app, | |
127 familiarize yourself with the Dart and HTML code, | |
128 and run the app. | |
129 | |
130 #### <i class="icon-anchor"> </i> Expand the 1-blankbadge directory. | |
131 | |
132 <div class="trydart-step-details" markdown="1"> | |
133 In Dart Editor, expand the `1-blankbadge` directory, | |
134 which contains two files, `piratebadge.html` and `piratebadge.dart`. | |
135 </div> | |
136 | |
137 #### <i class="icon-anchor"> </i> Open the files. | |
138 | |
139 <div class="trydart-step-details" markdown="1"> | |
140 Open both files by double-clicking each filename in Dart Editor. | |
141 </div> | |
142 | |
143 #### <i class="icon-anchor"> </i> Review the code | |
144 | |
145 <div class="trydart-step-details" markdown="1"> | |
146 Get familiar with the HTML and the Dart code for the skeleton version of the app . | |
147 The interesting bits are highlighted below. | |
148 </div> | |
149 | |
150 <div class="trydart-step-details" markdown="1"> | |
151 ##### piratebadge.html | |
152 </div> | |
153 | |
154 <div class="row"> <div class="span7"> | |
155 | |
156 <div class="trydart-step-details" markdown="1"> | |
157 {% prettify html%} | |
158 <html> | |
159 <head> | |
160 <meta charset="utf-8"> | |
161 <title>Pirate badge</title> | |
162 <link rel="stylesheet" href="../piratebadge.css"> | |
163 </head> | |
164 <body> | |
165 <h1>Pirate badge</h1> | |
166 | |
167 <div class="widgets"> | |
168 [[highlight]]<span>TO DO: Put the UI widgets here.</span>[[/highlight]] | |
169 </div> | |
170 <div class="outer"> | |
171 <div class="boilerplate"> | |
172 Arrr! Me name is | |
173 </div> | |
174 <div class="name"> | |
175 [[highlight]]<span id="badgeName"> </span>[[/highlight]] | |
176 </div> | |
177 </div> | |
178 | |
179 [[highlight]]<script type="application/dart" src="piratebadge.dart"></script >[[/highlight]] | |
180 [[highlight]]<script src="packages/browser/dart.js"></script>[[/highlight]] | |
181 </body> | |
182 </html> | |
183 {% endprettify %} | |
184 </div> | |
185 | |
186 </div> <div class="span5" markdown="1"> | |
187 | |
188 <i class="icon-key"> </i> <strong> Key Information </strong> | |
189 | |
190 * During the code lab, | |
191 all the changes you make to `piratebadge.html` are within | |
192 the <div> element identified with the class `widgets`. | |
193 | |
194 * The <span> element with the ID `badgeName` | |
195 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
| |
196 based on user input. | |
197 | |
198 * The `piratebadge.dart` script provides the main program for the app. | |
199 | |
200 * The `packages/browser/dart.js` script is a bootstrap script | |
201 that takes care of turning on the Dart VM, | |
202 as well as compatibility with non-Dart browsers. | |
203 | |
204 </div> </div> | |
205 | |
206 <div class="trydart-step-details" markdown="1"> | |
207 ##### piratebadge.dart | |
208 </div> | |
209 | |
210 <div class="row"> <div class="span7" markdown="1"> | |
211 | |
212 <div class="trydart-step-details" markdown="1"> | |
213 {% prettify dart %} | |
214 [[highlight]]void main() { | |
215 // Your app starts here. | |
216 } | |
217 [[/highlight]] | |
218 {% endprettify %} | |
219 </div> | |
220 | |
221 </div> <div class="span5" markdown="1"> | |
222 | |
223 * 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
| |
224 with the <script> tag. | |
225 | |
226 * The `main()` function is a top-level function. | |
227 Dart calls this function when your app starts. | |
228 | |
229 {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} | |
230 </div> </div> | |
231 | |
232 #### <i class="icon-anchor"> </i> Run the app. | |
233 | |
234 <div class="trydart-step-details" markdown="1"> | |
235 To run the app in Dart Editor, select `piratebadge.html` | |
236 and click the Run button | |
237 <img src="images/run.png" width="16" height="16" | |
238 alt="Run button">. | |
239 | |
240 You should see a TO DO comment on the left | |
241 and a red and white name badge on the right. | |
242 </div> | |
243 | |
244 <div class="trydart-step-details" markdown="1"> | |
245 <iframe class="running-app-frame" | |
246 style="height:220px;width:530px;" | |
247 src="examples/1-blankbadge/piratebadge.html"> | |
248 </iframe> | |
249 </div> | |
250 | |
251 <hr> | |
252 | |
253 ##Step 2: Add an input field {#step-two} | |
254 | |
255 In this step, you add an input field to the app. | |
256 As you type into the text field, | |
257 the Dart code updates the badge from the value of the text field. | |
258 | |
259 #### <i class="icon-anchor"> </i> Try it! | |
260 | |
261 <div class="trydart-step-details" markdown="1"> | |
262 Type in the input field. | |
263 | |
264 <iframe class="running-app-frame" | |
265 style="height:220px;width:530px;" | |
266 src="examples/2-inputnamebadge/piratebadge.html"> | |
267 </iframe> | |
268 </div> | |
269 | |
270 #### <i class="icon-anchor"> </i> Edit piratebadge.html. | |
271 | |
272 <div class="row"> <div class="span7" markdown="1"> | |
273 | |
274 <div class="trydart-step-details" markdown="1"> | |
275 | |
276 Add the <input> tag to the HTML code | |
277 within the `widgets` <div>. | |
278 | |
279 {% prettify html %} | |
280 ... | |
281 <div class="widgets"> | |
282 [[highlight]] <div> | |
283 <input type="text" id="inputName"> | |
284 </div>[[/highlight]] | |
285 </div> | |
286 ... | |
287 {% endprettify %} | |
288 </div> | |
289 | |
290 </div> <div class="span5" markdown="1"> | |
291 | |
292 <i class="icon-key"> </i> <strong> Key Information </strong> | |
293 | |
294 * The ID for the input element is `inputName`. | |
295 Dart uses CSS selectors, like this ID, | |
296 to get elements from the DOM. | |
297 | |
298 {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} | |
299 | |
300 </div> </div> | |
301 | |
302 #### <i class="icon-anchor"> </i> Edit piratebadge.dart. | |
303 | |
304 <div class="trydart-step-details" markdown="1"> | |
305 | |
306 Import the | |
307 <a href="https://api.dartlang.org/dart_html.html" target="_blank">dart:html</a> | |
308 library at the top of the file: | |
309 | |
310 </div> | |
311 | |
312 <div class="row"> <div class="span7"> | |
313 | |
314 <div class="trydart-step-details" markdown="1"> | |
315 | |
316 {% prettify dart %} | |
317 [[highlight]]import 'dart:html';[[/highlight]] | |
318 {% endprettify %} | |
319 </div> | |
320 | |
321 </div> <div class="span5" markdown="1"> | |
322 | |
323 * This imports all classes and other resources from dart:html, | |
324 which provides HTML elements and access to the DOM. | |
325 | |
326 </div> </div> | |
327 | |
328 <div class="trydart-step-details" markdown="1"> | |
329 | |
330 <hr> | |
331 | |
332 Register a function to handle input events on the input field. | |
333 </div> | |
334 | |
335 <div class="row"> <div class="span7"> | |
336 | |
337 <div class="trydart-step-details" markdown="1"> | |
338 | |
339 {% prettify dart %} | |
340 void main() { | |
341 [[highlight]] query('#inputName').onInput.listen(updateBadge);[[/highlight]] | |
342 } | |
343 {% endprettify %} | |
344 </div> | |
345 | |
346 </div> <div class="span5" markdown="1"> | |
347 | |
348 * The `query()` function, defined in | |
349 dart:html, gets an element from the DOM. | |
350 Here, the code uses the ID `#inputName` | |
351 to specify the input field. | |
352 | |
353 * `onInput` registers an event handler for input events. | |
354 | |
355 * An input event occurs when the user presses a key. | |
356 | |
357 * You can use either single or double quotes to create a string. | |
358 | |
359 </div> </div> | |
360 | |
361 <div class="trydart-step-details" markdown="1"> | |
362 | |
363 <hr> | |
364 | |
365 Implement the event handler as a top-level function. | |
366 </div> | |
367 | |
368 <div class="row"> <div class="span7"> | |
369 | |
370 <div class="trydart-step-details" markdown="1"> | |
371 | |
372 {% prettify dart %} | |
373 [[highlight]]void updateBadge(Event e) { | |
374 query('#badgeName').text = (e.target as InputElement).value; | |
375 }[[/highlight]] | |
376 {% endprettify %} | |
377 </div> | |
378 | |
379 </div> <div class="span5" markdown="1"> | |
380 | |
381 * This function sets the text of the `badgeName` element from the value of the i nput field. | |
382 | |
383 * The `updateBadge()` function is an event handler based on its signature. | |
384 | |
385 * The element that generated the event, the input field, is `e.target`. | |
386 | |
387 * The `as` keyword typecasts `e.target` to an | |
388 <a href="https://api.dartlang.org/dart_html/InputElement.html" target="_blank">I nputElement</a> | |
389 to reference its value field. | |
390 | |
391 {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} | |
392 | |
393 </div> </div> | |
394 | |
395 <hr> | |
396 | |
397 ##Step 3: Add a button {#step-three} | |
398 | |
399 In this step, you add a button to the app. | |
400 The button is enabled when the text field contains no text. | |
401 When the user clicks the button, | |
402 the app puts the name `Anne Bonney` on the badge. | |
403 | |
404 #### Try it! | |
405 | |
406 <div class="trydart-step-details" markdown="1"> | |
407 Type in the input field. | |
408 Remove the text from the input field. | |
409 Click the button. | |
410 </div> | |
411 | |
412 <div class="trydart-step-details"> | |
413 <iframe class="running-app-frame" | |
414 style="height:220px;width:530px;" | |
415 src="examples/3-buttonbadge/piratebadge.html"> | |
416 </iframe> | |
417 </div> | |
418 | |
419 #### <i class="icon-anchor"> </i> Edit piratebadge.html. | |
420 | |
421 <div class="trydart-step-details" markdown="1"> | |
422 Add the <button> tag below the input field. | |
423 </div> | |
424 | |
425 <div class="row"> <div class="span7"> | |
426 | |
427 <div class="trydart-step-details"> | |
428 {% prettify html %} | |
429 ... | |
430 <div class="widgets"> | |
431 <div> | |
432 <input type="text" id="inputName"> | |
433 </div> | |
434 [[highlight]] <div> | |
435 <button id="generateButton">Generate badge</button> | |
436 </div>[[/highlight]] | |
437 </div> | |
438 ... | |
439 {% endprettify %} | |
440 </div> | |
441 | |
442 </div> <div class="span5" markdown="1"> | |
443 | |
444 <i class="icon-key"> </i> <strong> Key Information </strong> | |
445 | |
446 * The button has the ID `generateButton` so | |
447 the Dart code can get the element. | |
448 | |
449 * The Dart code changes the button dynamically based on user input. | |
450 | |
451 </div> </div> | |
452 | |
453 #### <i class="icon-anchor"> </i> Edit piragebadge.dart. | |
454 | |
455 <div class="trydart-step-details" markdown="1"> | |
456 Below the import, declare a top-level variable to hold the | |
457 <a href="https://api.dartlang.org/dart_html/ButtonElement.html" target="_blank"> ButtonElement</a>. | |
458 </div> | |
459 | |
460 <div class="row"> <div class="span7"> | |
461 | |
462 <div class="trydart-step-details"> | |
463 {% prettify dart %} | |
464 import `dart:html`; | |
465 | |
466 [[highlight]]ButtonElement genButton;[[/highlight]] | |
467 {% endprettify %} | |
468 </div> | |
469 | |
470 </div> <div class="span5" markdown="1"> | |
471 | |
472 * Top-level variables are names at the library level. | |
473 | |
474 {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} | |
475 | |
476 </div> </div> | |
477 | |
478 <div class="trydart-step-details" markdown="1"> | |
479 | |
480 <hr> | |
481 | |
482 Wire up the button with an event handler. | |
483 </div> | |
484 | |
485 <div class="row"> <div class="span7"> | |
486 | |
487 <div class="trydart-step-details"> | |
488 {% prettify dart %} | |
489 void main() {} | |
490 query('#inputName').onInput.listen(updateBadge); | |
491 [[highlight]]genButton = query('#generateButton') | |
492 ..onClick.listen(generateBadge)[[/highlight]] | |
493 } | |
494 {% endprettify %} | |
495 </div> | |
496 | |
497 </div> <div class="span5" markdown="1"> | |
498 | |
499 * `onClick` registers a mouse click handler. | |
500 | |
501 * The cascade operator (`..`) allows you to perform multiple | |
502 operations on the members of a single object. | |
503 | |
504 {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} | |
505 | |
506 </div> </div> | |
507 | |
508 <div class="trydart-step-details" markdown="1"> | |
509 | |
510 <hr> | |
511 | |
512 Add a top-level setter that changes the name on the badge. | |
513 </div> | |
514 | |
515 <div class="row"> <div class="span7"> | |
516 | |
517 <div class="trydart-step-details"> | |
518 {% prettify dart %} | |
519 [[highlight]]set badgeName(String newName) { | |
520 query('#badgeName').text = newName; | |
521 } [[/highlight]] | |
522 {% endprettify %} | |
523 </div> | |
524 | |
525 </div> <div class="span5" markdown="1"> | |
526 | |
527 * Setters are special methods that provide write access to an object’s propertie s. | |
528 | |
529 * Here the setter updates the HTML page with a new name. | |
530 | |
531 {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} | |
532 | |
533 </div> </div> | |
534 | |
535 <div class="trydart-step-details" markdown="1"> | |
536 | |
537 <hr> | |
538 | |
539 Implement the click handler for the button. | |
540 </div> | |
541 | |
542 <div class="row"> <div class="span7"> | |
543 | |
544 <div class="trydart-step-details"> | |
545 {% prettify dart %} | |
546 [[highlight]]void generateBadge(Event e) { | |
547 badgeName = 'Anne Bonney'; | |
548 }[[/highlight]] | |
549 {% endprettify %} | |
550 </div> | |
551 | |
552 </div> <div class="span5" markdown="1"> | |
553 | |
554 * This function calls the setter to set the badge name to `Anne Bonney`. | |
555 Note that the call to a setter looks like a field assignment. | |
556 | |
557 {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} | |
558 | |
559 </div> </div> | |
560 | |
561 <div class="trydart-step-details" markdown="1"> | |
562 | |
563 <hr> | |
564 | |
565 Replace the contents of the `updateBadge()` function | |
566 with this code. | |
567 </div> | |
568 | |
569 <div class="row"> <div class="span7"> | |
570 | |
571 <div class="trydart-step-details"> | |
572 {% prettify dart %} | |
573 void updateBadge(Event e) { | |
574 [[highlight]] String inputName = (e.target as InputElement).value; | |
575 | |
576 badgeName = inputName; | |
577 if (inputName.trim().isEmpty) { | |
578 genButton..disabled = false | |
579 ..text = 'Generate badge'; | |
580 } else { | |
581 genButton..disabled = true | |
582 ..text = 'Arrr! Remove the text!'; | |
583 }[[/highlight]] | |
584 } | |
585 {% endprettify %} | |
586 </div> | |
587 </div> <div class="span5" markdown="1"> | |
588 | |
589 * The | |
590 <a href="https://api.dartlang.org/dart_core/String.html" target="_blank">String< /a> | |
591 class has useful functions and properties for dealing with strings, | |
592 such as `trim()` and `isEmpty`. | |
593 | |
594 * String comes from the | |
595 <a href="https://api.dartlang.org/dart_core.html" target="_blank">dart:core</a> | |
596 library, which is automatically imported into every Dart program. | |
597 | |
598 * Here, you see the cascade operator in action again. | |
599 | |
600 * This code calls the setter to set the badge name. | |
601 | |
602 * Dart has common programming language constructs like `if`-`else`. | |
603 | |
604 </div></div> | |
605 | |
606 <hr> | |
607 | |
608 ##Step 4: Create a PirateName class {#step-four} | |
609 | |
610 In this step, you change only the Dart code. | |
611 You create a class to represent a pirate name. | |
612 When created, an instance of this class | |
613 randomly selects a name and appellation from a list, | |
614 or optionally you can provide a name | |
615 and an appellation to the constructor. | |
616 | |
617 #### Try it! | |
618 | |
619 <div class="trydart-step-details" markdown="1"> | |
620 Type in the input field. | |
621 Remove the text from the input field. | |
622 Click the button. | |
623 </div> | |
624 | |
625 <div class="trydart-step-details"> | |
626 <iframe class="running-app-frame" | |
627 style="height:220px;width:530px;" | |
628 src="examples/4-classbadge/piratebadge.html"> | |
629 </iframe> | |
630 </div> | |
631 | |
632 #### <i class="icon-anchor"> </i> Edit piratebadge.dart. | |
633 | |
634 <div class="trydart-step-details" markdown="1"> | |
635 Add an import to the top of the file. | |
636 </div> | |
637 | |
638 <div class="row"> <div class="span7"> | |
639 | |
640 <div class="trydart-step-details"> | |
641 {% prettify dart %} | |
642 import 'dart:html'; | |
643 import 'dart:math' show Random; | |
644 {% endprettify %} | |
645 </div> | |
646 </div> <div class="span5" markdown="1"> | |
647 | |
648 <i class="icon-key"> </i> <strong> Key Information </strong> | |
649 | |
650 * Using the `show` keyword, | |
651 you can import just the classes you need. | |
652 | |
653 * <a href="https://api.dartlang.org/dart_math/Random.html" target="_blank">Rando m</a> | |
654 provides a random number generator. | |
655 | |
656 </div></div> | |
657 | |
658 <div class="trydart-step-details" markdown="1"> | |
659 | |
660 <hr> | |
661 | |
662 Add a class declaration to the bottom of the file. | |
663 </div> | |
664 | |
665 <div class="row"> <div class="span7"> | |
666 | |
667 <div class="trydart-step-details"> | |
668 {% prettify dart %} | |
669 class PirateName { | |
670 ... | |
671 } | |
672 {% endprettify %} | |
673 </div> | |
674 </div> <div class="span5" markdown="1"> | |
675 | |
676 * The class declaration provides the class name. | |
677 | |
678 </div></div> | |
679 | |
680 <div class="trydart-step-details" markdown="1"> | |
681 | |
682 <hr> | |
683 | |
684 Create a class-level Random object. | |
685 </div> | |
686 | |
687 <div class="row"> <div class="span7"> | |
688 | |
689 <div class="trydart-step-details"> | |
690 {% prettify dart %} | |
691 class PirateName { | |
692 [[highlight]]static final Random indexGen = new Random();[[/highlight]] | |
693 } | |
694 {% endprettify %} | |
695 </div> | |
696 </div> <div class="span5" markdown="1"> | |
697 | |
698 * `static` defines a class-level field. That is, | |
699 the random number generator is shared with all | |
700 instances of this class. | |
701 | |
702 * Use `new` to call a constructor. | |
703 | |
704 </div></div> | |
705 | |
706 <div class="trydart-step-details" markdown="1"> | |
707 | |
708 <hr> | |
709 | |
710 Add two instance variables to class, | |
711 one for the first name and one for the appellation. | |
712 </div> | |
713 | |
714 <div class="row"> <div class="span7"> | |
715 | |
716 <div class="trydart-step-details"> | |
717 {% prettify dart %} | |
718 class PirateName { | |
719 ... | |
720 [[highlight]] String _firstName; | |
721 String _appellation;[[/highlight]] | |
722 } | |
723 {% endprettify %} | |
724 </div> | |
725 </div> <div class="span5" markdown="1"> | |
726 | |
727 * Private variables start with underscore (`_`). | |
728 | |
729 </div></div> | |
730 | |
731 <div class="trydart-step-details" markdown="1"> | |
732 | |
733 <hr> | |
734 | |
735 Create two static lists within the class | |
736 that provide a small collection of names and appellations to choose from. | |
737 </div> | |
738 | |
739 <div class="row"> <div class="span7"> | |
740 | |
741 <div class="trydart-step-details"> | |
742 {% prettify dart %} | |
743 class PirateName { | |
744 ... | |
745 [[highlight]] static final List names = [ | |
746 'Anne', 'Mary', 'Jack', 'Morgan', 'Roger', | |
747 'Bill', 'Ragnar', 'Ed', 'John', 'Jane' ]; | |
748 static final List appellations = [ | |
749 'Black','Damned', 'Jackal', 'Red', 'Stalwart', 'Axe', | |
750 'Young', 'Old', 'Angry', 'Brave', 'Crazy', 'Noble'];[[/highlight]] | |
751 } | |
752 {% endprettify %} | |
753 </div> | |
754 </div> <div class="span5" markdown="1"> | |
755 | |
756 * `final` variables cannot change. | |
757 | |
758 * Lists are built into the language. | |
759 These lists are created using list literals. | |
760 | |
761 * The | |
762 <a href="https://api.dartlang.org/dart_core/List.html" target="_blank">List</a> | |
763 class provides the API for lists. | |
764 | |
765 </div></div> | |
766 | |
767 | |
768 <div class="trydart-step-details" markdown="1"> | |
769 | |
770 <hr> | |
771 | |
772 Provide a constructor for the class. | |
773 </div> | |
774 | |
775 <div class="row"> <div class="span7"> | |
776 | |
777 <div class="trydart-step-details"> | |
778 {% prettify dart %} | |
779 class PirateName { | |
780 ... | |
781 [[highlight]] PirateName({String firstName, String appellation}) { | |
782 if (firstName == null) { | |
783 _firstName = names[indexGen.nextInt(names.length)]; | |
784 } else { | |
785 _firstName = firstName; | |
786 } | |
787 if (appellation == null) { | |
788 _appellation = appellations[indexGen.nextInt(appellations.length)]; | |
789 } else { | |
790 _appellation = appellation; | |
791 } | |
792 }[[/highlight]] | |
793 } | |
794 {% endprettify %} | |
795 </div> | |
796 | |
797 </div> <div class="span5" markdown="1"> | |
798 | |
799 * Constructors have the same name as the class. | |
800 | |
801 * Optional parameters are enclosed in curly brackets (`{` and `}`). | |
802 | |
803 * The `nextInt()` function gets a new random integer | |
804 from the random number generator. | |
805 | |
806 * Square brackets (`[` and `]`) are operators to index into a list. | |
807 | |
808 * The `length` property returns the length of a list. | |
809 | |
810 * The code uses a random number as an index into the list. | |
811 | |
812 </div> </div> | |
813 | |
814 <div class="trydart-step-details" markdown="1"> | |
815 | |
816 <hr> | |
817 | |
818 Provide a getter for the pirate name. | |
819 </div> | |
820 | |
821 <div class="row"> <div class="span7"> | |
822 | |
823 <div class="trydart-step-details"> | |
824 {% prettify dart %} | |
825 class PirateName { | |
826 ... | |
827 [[highlight]] String get pirateName => '$_firstName the $_appellation';[[/highl ight]] | |
828 } | |
829 {% endprettify %} | |
830 </div> | |
831 | |
832 </div><div class="span5" markdown="1"> | |
833 | |
834 * Getters are special methods that provide read access to an object’s properties . | |
835 | |
836 </div></div> | |
837 | |
838 <div class="trydart-step-details" markdown="1"> | |
839 | |
840 <hr> | |
841 | |
842 Modify the setter `badgeName()` to use a PirateName instead of a String: | |
843 </div> | |
844 | |
845 <div class="row"> <div class="span7"> | |
846 | |
847 <div class="trydart-step-details"> | |
848 {% prettify dart %} | |
849 set badgeName([[highlight]]PirateName newName[[/highlight]]) { | |
850 query('#badgeName').text = [[highlight]]newName.pirateName[[/highlight]]; | |
851 } | |
852 {% endprettify %} | |
853 </div> | |
854 | |
855 </div><div class="span5" markdown="1"> | |
856 | |
857 * This code calls the getter to get the PirateName as a string. | |
858 | |
859 </div></div> | |
860 | |
861 <div class="trydart-step-details" markdown="1"> | |
862 | |
863 <hr> | |
864 | |
865 Change `updateBadge()` to generate a PirateName based on the input field value. | |
866 </div> | |
867 | |
868 <div class="row"> <div class="span7"> | |
869 | |
870 <div class="trydart-step-details"> | |
871 {% prettify dart %} | |
872 void updateBadge(Event e) { | |
873 String inputName = (e.target as InputElement).value; | |
874 | |
875 [[highlight]]badgeName = new PirateName(firstName: inputName);[[/highlight]] | |
876 ... | |
877 } | |
878 {% endprettify %} | |
879 </div> | |
880 | |
881 </div><div class="span5" markdown="1"> | |
882 | |
883 * The call to the constructor provides a value for one optional parameter. | |
884 | |
885 </div></div> | |
886 | |
887 <div class="trydart-step-details" markdown="1"> | |
888 | |
889 <hr> | |
890 | |
891 Change `generateBadge()` to generate a PirateName instead of using `Anne Bonney` . | |
892 </div> | |
893 | |
894 <div class="row"> <div class="span7"> | |
895 | |
896 <div class="trydart-step-details"> | |
897 {% prettify dart %} | |
898 void generateBadge(Event e) { | |
899 [[highlight]]badgeName = new PirateName();[[/highlight]] | |
900 } | |
901 {% endprettify %} | |
902 </div> | |
903 | |
904 </div><div class="span5" markdown="1"> | |
905 | |
906 * The call to the constructor passes no parameters. | |
907 | |
908 </div></div> | |
909 | |
910 ##Step 5: Save to local storage {#step-five} | |
911 | |
912 In this step, you give the app some persistence | |
913 by saving the badge name to local storage each time it changes. | |
914 When you restart the app, | |
915 it initializes the badge from the saved name. | |
916 | |
917 #### Try it! | |
918 | |
919 <div class="trydart-step-details" markdown="1"> | |
920 Click the button, then kill the app by closing this window. | |
921 Open this page up in a new window. | |
922 </div> | |
923 | |
924 <div class="trydart-step-details"> | |
925 <iframe class="running-app-frame" | |
926 style="height:220px;width:530px;" | |
927 src="examples/5-localbadge/piratebadge.html"> | |
928 </iframe> | |
929 </div> | |
930 | |
931 #### <i class="icon-anchor"> </i> Edit piratebadge.dart. | |
932 | |
933 <div class="trydart-step-details" markdown="1"> | |
934 Import the JSON converter from the | |
935 <a href="https://api.dartlang.org/dart_convert.html" target="_blank">dart:conver t</a> | |
936 library. | |
937 </div> | |
938 | |
939 <div class="row"> <div class="span7"> | |
940 | |
941 <div class="trydart-step-details"> | |
942 {% prettify dart %} | |
943 import 'dart:html'; | |
944 import 'dart:math' show Random; | |
945 [[highlight]] | |
946 import 'dart:convert' show JSON;[[/highlight]] | |
947 {% endprettify %} | |
948 </div> | |
949 | |
950 </div> <div class="span5" markdown="1"> | |
951 | |
952 <i class="icon-key"> </i> <strong> Key Information </strong> | |
953 | |
954 * `JSON` provides convenient access to the most common JSON use cases. | |
955 | |
956 </div> </div> | |
957 | |
958 <div class="trydart-step-details" markdown="1"> | |
959 | |
960 <hr> | |
961 | |
962 Add a new constructor to the PirateName class. | |
963 </div> | |
964 | |
965 <div class="row"> <div class="span7"> | |
966 | |
967 <div class="trydart-step-details"> | |
968 {% prettify dart %} | |
969 class PirateName { | |
970 ... | |
971 [[highlight]] PirateName.fromJSON(String jsonString) { | |
972 Map storedName = JSON.decode(jsonString); | |
973 _firstName = storedName['f']; | |
974 _appellation = storedName['a']; | |
975 }[[/highlight]] | |
976 } | |
977 {% endprettify %} | |
978 </div> | |
979 | |
980 </div> <div class="span5" markdown="1"> | |
981 | |
982 * The constructor creates a new PirateName instance from a JSON-encoded string. | |
983 | |
984 * `PirateName.fromJson` is a named constructor. | |
985 | |
986 * `JSON.decode()` parses a JSON string and creates Dart objects from it. | |
987 | |
988 * The pirate name is decoded into a | |
989 <a href="https://api.dartlang.org/dart_core/Map.html" target="_blank">Map</a> | |
990 object. | |
991 | |
992 </div> </div> | |
993 | |
994 <div class="trydart-step-details" markdown="1"> | |
995 | |
996 <hr> | |
997 | |
998 Add a getter to the PirateName class | |
999 that encodes a pirate name in a JSON string. | |
1000 </div> | |
1001 | |
1002 <div class="row"> <div class="span7"> | |
1003 | |
1004 <div class="trydart-step-details"> | |
1005 {% prettify dart %} | |
1006 class PirateName { | |
1007 ... | |
1008 [[highlight]]String toJsonString() => '{ "f": "$_firstName", "a": "$_appellati on" } ';[[/highlight]] | |
1009 } | |
1010 {% endprettify %} | |
1011 </div> | |
1012 | |
1013 </div> <div class="span5" markdown="1"> | |
1014 | |
1015 * The getter formats the JSON string using the map format. | |
1016 | |
1017 </div> </div> | |
1018 | |
1019 | |
1020 <div class="trydart-step-details" markdown="1"> | |
1021 | |
1022 <hr> | |
1023 | |
1024 Declare a top-level boolean variable. | |
1025 </div> | |
1026 | |
1027 <div class="row"> <div class="span7"> | |
1028 | |
1029 <div class="trydart-step-details"> | |
1030 {% prettify dart %} | |
1031 [[highlight]]final String TREASUREKEY = 'pirateName';[[/highlight]] | |
1032 {% endprettify %} | |
1033 </div> | |
1034 | |
1035 </div> <div class="span5" markdown="1"> | |
1036 | |
1037 * This string is a key to the local storage, | |
1038 hopefully unique. | |
1039 | |
1040 </div> </div> | |
1041 | |
1042 <div class="trydart-step-details" markdown="1"> | |
1043 | |
1044 <hr> | |
1045 | |
1046 Save the pirate name when the badge name changes. | |
1047 </div> | |
1048 | |
1049 <div class="row"> <div class="span7"> | |
1050 | |
1051 <div class="trydart-step-details"> | |
1052 {% prettify dart %} | |
1053 set badgeName(PirateName newName) { | |
1054 query('#badgeName').text = newName.pirateName; | |
1055 [[highlight]]window.localStorage[TREASUREKEY] = newName.toJsonString();[[/high light]] | |
1056 } | |
1057 {% endprettify %} | |
1058 </div> | |
1059 | |
1060 </div> <div class="span5" markdown="1"> | |
1061 | |
1062 * Local storage is provided by the browser's window. | |
1063 | |
1064 {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} | |
1065 | |
1066 </div> </div> | |
1067 | |
1068 <div class="trydart-step-details" markdown="1"> | |
1069 | |
1070 <hr> | |
1071 | |
1072 Add a top-level getter. | |
1073 </div> | |
1074 | |
1075 <div class="row"> <div class="span7"> | |
1076 | |
1077 <div class="trydart-step-details"> | |
1078 {% prettify dart %} | |
1079 [[highlight]]PirateName get pirateNameFromStorage { | |
1080 String storedName = window.localStorage[TREASUREKEY]; | |
1081 if (storedName != null) { | |
1082 return new PirateName.fromJSON(storedName); | |
1083 } else { | |
1084 return null; | |
1085 } | |
1086 }[[/highlight]] | |
1087 {% endprettify %} | |
1088 </div> | |
1089 | |
1090 </div> <div class="span5" markdown="1"> | |
1091 | |
1092 * The getter retrieves the pirate name from local storage | |
1093 and creates a PirateName object from it. | |
1094 | |
1095 {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} | |
1096 | |
1097 </div> </div> | |
1098 | |
1099 <div class="trydart-step-details" markdown="1"> | |
1100 <hr> | |
1101 Call the getter from the `main()` function. | |
1102 </div> | |
1103 | |
1104 <div class="row"> <div class="span7"> | |
1105 | |
1106 <div class="trydart-step-details"> | |
1107 {% prettify dart %} | |
1108 void main() { | |
1109 ... | |
1110 [[highlight]]badgeName = pirateNameFromStorage;[[/highlight]] | |
1111 } | |
1112 {% endprettify %} | |
1113 </div> | |
1114 | |
1115 </div> <div class="span5" markdown="1"> | |
1116 | |
1117 * Initialize the badge name from local storage. | |
1118 | |
1119 {% comment %} non-breaking space required for bootstrap/markdown bogosity {% endcomment %} | |
1120 | |
1121 </div> </div> | |
1122 | |
1123 ##Step 6: Read names from JSON-encoded file {#step-six} | |
1124 | |
1125 In this step, you change the PirateName class to get | |
1126 the list of names and appellations from a JSON file. | |
1127 This gives you a chance to add more names and | |
1128 appellations to the program. | |
1129 | |
1130 #### Try it! | |
1131 | |
1132 <div class="trydart-step-details"> | |
1133 The final app is running here. | |
1134 </div> | |
1135 | |
1136 <div class="trydart-step-details"> | |
1137 <iframe class="running-app-frame" | |
1138 style="height:220px;width:530px;" | |
1139 src="examples/6-piratebadge_json/piratebadge.html"> | |
1140 </iframe> | |
1141 </div> | |
1142 | |
1143 #### <i class="icon-anchor"> </i> Create piratenames.json. | |
1144 | |
1145 <div class="trydart-step-details" markdown="1"> | |
1146 Create a JSON encoded file named `piratenames.json`. | |
1147 </div> | |
1148 | |
1149 <div class="row"> <div class="span7"> | |
1150 | |
1151 <div class="trydart-step-details"> | |
1152 {% prettify dart %} | |
1153 { "names": [ "Anne", "Bette", "Cate", "Dawn", | |
1154 "Elise", "Faye", "Ginger", "Harriot", | |
1155 "Izzy", "Jane", "Kaye", "Liz", | |
1156 "Maria", "Nell", "Olive", "Pat", | |
1157 "Queenie", "Rae", "Sal", "Tam", | |
1158 "Uma", "Violet", "Wilma", "Xana", | |
1159 "Yvonne", "Zelda", | |
1160 "Abe", "Billy", "Caleb", "Davie", | |
1161 "Eb", "Frank", "Gabe", "House", | |
1162 "Icarus", "Jack", "Kurt", "Larry", | |
1163 "Mike", "Nolan", "Oliver", "Pat", | |
1164 "Quib", "Roy", "Sal", "Tom", | |
1165 "Ube", "Val", "Walt", "Xavier", | |
1166 "Yvan", "Zeb"], | |
1167 "appellations": [ "Awesome", "Black", "Captain", "Damned", | |
1168 "Even", "Fighter", "Great", "Hearty", | |
1169 "Irate", "Jackal", "King", "Lord", | |
1170 "Mighty", "Noble", "Old", "Powerful", | |
1171 "Quick", "Red", "Stalwart", "Tank", | |
1172 "Ultimate", "Vicious", "Wily", "aXe", | |
1173 "Young", "Zealot", | |
1174 "Angry", "Brave", "Crazy", "Damned", | |
1175 "Eager", "Fool", "Greedy", "Hated", | |
1176 "Idiot", "Jinxed", "Kind", "Lame", | |
1177 "Maimed", "Naked", "Old", "Pale", | |
1178 "Queasy", "Rat", "Sandy", "Tired", | |
1179 "Ugly", "Vile", "Weak", "Xeric", | |
1180 "Yellow", "Zesty"]} | |
1181 {% endprettify %} | |
1182 </div> | |
1183 | |
1184 </div> <div class="span5" markdown="1"> | |
1185 | |
1186 <i class="icon-key"> </i> <strong> Key Information </strong> | |
1187 | |
1188 * Put the file alongside the Dart and HTML files for the app. | |
1189 | |
1190 * The file contains the code for a map | |
1191 that contains two lists that each contain strings. | |
1192 | |
1193 </div> </div> | |
1194 | |
1195 #### <i class="icon-anchor"> </i> Edit piratebadge.html. | |
1196 | |
1197 <div class="trydart-step-details" markdown="1"> | |
1198 Disable the input field and the button. | |
1199 </div> | |
1200 | |
1201 <div class="row"> <div class="span7"> | |
1202 | |
1203 <div class="trydart-step-details"> | |
1204 {% prettify html %} | |
1205 ... | |
1206 <div> | |
1207 <input type="text" id="inputName" [[highlight]]disabled[[/highlight]]> | |
1208 </div> | |
1209 <div> | |
1210 <button id="generateButton" [[highlight]]disabled[[/highlight]]>Generate bad ge</button> | |
1211 </div> | |
1212 ... | |
1213 {% endprettify %} | |
1214 </div> | |
1215 | |
1216 </div> <div class="span5" markdown="1"> | |
1217 | |
1218 | |
1219 * The Dart code enables the text field and | |
1220 the button after the pirate names are successfully read from | |
1221 the JSON file. | |
1222 | |
1223 </div> </div> | |
1224 | |
1225 #### <i class="icon-anchor"> </i> Edit piratebadge.dart. | |
1226 | |
1227 <div class="trydart-step-details" markdown="1"> | |
1228 | |
1229 Add an import to the top of the file. | |
1230 </div> | |
1231 | |
1232 <div class="row"> <div class="span7"> | |
1233 | |
1234 <div class="trydart-step-details"> | |
1235 {% prettify dart %} | |
1236 import 'dart:html'; | |
1237 import 'dart:math' show Random; | |
1238 import 'dart:convert' show JSON; | |
1239 | |
1240 [[highlight]]import 'dart:async' show Future;[[/highlight]] | |
1241 {% endprettify %} | |
1242 </div> | |
1243 | |
1244 </div> <div class="span5" markdown="1"> | |
1245 | |
1246 * The | |
1247 <a href="https://api.dartlang.org/dart_async.html" target="_blank">dart:async</a > | |
1248 library provides for asynchronous programming. | |
1249 | |
1250 * A <a href="https://api.dartlang.org/dart_async/Future.html" target="_blank">Fu ture</a> | |
1251 provides a way to get a value in the future. | |
1252 | |
1253 </div> </div> | |
1254 | |
1255 <div class="trydart-step-details" markdown="1"> | |
1256 | |
1257 <hr> | |
1258 Replace the list literals with these static empty lists: | |
1259 </div> | |
1260 | |
1261 <div class="row"> <div class="span7"> | |
1262 | |
1263 <div class="trydart-step-details"> | |
1264 {% prettify dart %} | |
1265 class PirateName { | |
1266 ... | |
1267 [[highlight]]static List<String> names = []; | |
1268 static List<String> appellations = [];[[/highlight]] | |
1269 ... | |
1270 } | |
1271 {% endprettify %} | |
1272 </div> | |
1273 | |
1274 </div> <div class="span5" markdown="1"> | |
1275 | |
1276 * `[]` is equivalent to `new List()`. | |
1277 | |
1278 </div> </div> | |
1279 | |
1280 <div class="trydart-step-details" markdown="1"> | |
1281 | |
1282 <hr> | |
1283 | |
1284 Add two static functions to the PirateName class: | |
1285 </div> | |
1286 | |
1287 <div class="row"> <div class="span7"> | |
1288 | |
1289 <div class="trydart-step-details"> | |
1290 {% prettify dart %} | |
1291 class PirateName { | |
1292 ... | |
1293 | |
1294 [[highlight]]static Future readyThePirates() { | |
1295 var path = 'piratenames.json'; | |
1296 return HttpRequest.getString(path) | |
1297 .then(_parsePirateNamesFromJSON); | |
1298 } | |
1299 | |
1300 static _parsePirateNamesFromJSON(String jsonString) { | |
1301 Map pirateNames = JSON.decode(jsonString); | |
1302 names = pirateNames['names']; | |
1303 appellations = pirateNames['appellations']; | |
1304 }[[/highlight]] | |
1305 } | |
1306 {% endprettify %} | |
1307 </div> | |
1308 | |
1309 </div> <div class="span5" markdown="1"> | |
1310 | |
1311 * <a href="https://api.dartlang.org/dart_html/HttpRequest.html" target="_blank"> HttpRequest</a> | |
1312 is a utilify for retrieving data from a URL. | |
1313 | |
1314 * `getString()` is a convenience method for doing a simple | |
1315 GET request that returns a string. | |
1316 | |
1317 * The code uses a | |
1318 <a href="https://api.dartlang.org/dart_async/Future.html" target="_blank">Future </a> | |
1319 to perform the GET asynchronously. | |
1320 | |
1321 * The callback function for `.then()` is called when | |
1322 the Future completes successfully. | |
1323 | |
1324 * When the Future completes successfully, | |
1325 the pirate names are read from the JSON file. | |
1326 | |
1327 * Futures are infectious. | |
1328 `readyThePirates` must return the Future so the main program can handle it. | |
1329 | |
1330 </div> </div> | |
1331 | |
1332 <div class="trydart-step-details" markdown="1"> | |
1333 <hr> | |
1334 Modify the `main()` function to look like this: | |
1335 </div> | |
1336 | |
1337 <div class="row"> <div class="span7"> | |
1338 | |
1339 <div class="trydart-step-details"> | |
1340 {% prettify dart %} | |
1341 void main() { | |
1342 InputElement inputField = query('#inputName') | |
1343 ..onInput.listen(updateBadge); | |
1344 genButton = query('#generateButton') | |
1345 ..onClick.listen(generateBadge); | |
1346 | |
1347 badgeNameElement = query('#badgeName'); | |
1348 | |
1349 PirateName.readyThePirates() | |
1350 .then((_) { | |
1351 inputField.disabled = false; //enable | |
1352 genButton.disabled = false; //enable | |
1353 badgeName = pirateNameFromStorage; | |
1354 }) | |
1355 .catchError((arrr) { | |
1356 print('Error initializing pirate names: $arrr'); | |
1357 badgeNameElement.text = 'Arrr! No names.'; | |
1358 }); | |
1359 } | |
1360 {% endprettify %} | |
1361 </div> | |
1362 | |
1363 </div> <div class="span5" markdown="1"> | |
1364 | |
1365 * When the Future successfully completes, | |
1366 the `then()` callback function is called. | |
1367 | |
1368 * The callback function enables the UI | |
1369 and gets the stored name. | |
1370 | |
1371 * If the Future encounters an error | |
1372 the `catchError` callback function is called | |
1373 and the program displays an error message, | |
1374 leaving the UI disabled. | |
1375 | |
1376 </div> </div> | |
1377 | |
1378 ##Step 7: What next? {#step-seven} | |
1379 | |
1380 #### <i class="icon-anchor"> </i> Check out the samples. | |
1381 | |
1382 <div class="trydart-step-details" markdown="1"> | |
1383 | |
1384 Run some Dart programs online and check out the source code | |
1385 on our [Samples page](/samples/). | |
1386 </div> | |
1387 | |
1388 #### <i class="icon-anchor"> </i> Read the tutorials. | |
1389 | |
1390 <div class="trydart-step-details" markdown="1"> | |
1391 Learn more about Dart from | |
1392 the [Dart tutorials](/docs/tutorials/). | |
1393 </div> | |
OLD | NEW |