diff --git a/.gitignore b/.gitignore index d87ff9b..d33ad71 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ packages .idea node_modules build +.pub diff --git a/Chapter_01/README.md b/Chapter_01/README.md index d2ed946..519690b 100644 --- a/Chapter_01/README.md +++ b/Chapter_01/README.md @@ -1,4 +1 @@ "Hello World" AngularDart application - -For a runnable version of this app, see this community-contributed demo: -http://runnable.com/UvLvODhQortBAAAu/angular-dart-tutorial-chapter-01 \ No newline at end of file diff --git a/Chapter_01/pubspec.lock b/Chapter_01/pubspec.lock index 1be98f2..a81bb1a 100644 --- a/Chapter_01/pubspec.lock +++ b/Chapter_01/pubspec.lock @@ -4,11 +4,11 @@ packages: analyzer: description: analyzer source: hosted - version: "0.18.0" + version: "0.15.7" angular: description: angular source: hosted - version: "0.13.0" + version: "1.0.0" args: description: args source: hosted @@ -32,7 +32,7 @@ packages: di: description: di source: hosted - version: "2.0.1" + version: "3.3.1" html5lib: description: html5lib source: hosted @@ -45,18 +45,14 @@ packages: description: logging source: hosted version: "0.9.1+1" - matcher: - description: matcher - source: hosted - version: "0.10.0" meta: description: meta source: hosted version: "0.8.8" - mock: - description: mock + observe: + description: observe source: hosted - version: "0.10.0+1" + version: "0.10.1+2" path: description: path source: hosted @@ -64,27 +60,27 @@ packages: perf_api: description: perf_api source: hosted - version: "0.0.8" + version: "0.0.9" route_hierarchical: description: route_hierarchical source: hosted - version: "0.4.21" + version: "0.5.0" + smoke: + description: smoke + source: hosted + version: "0.1.0+1" source_maps: description: source_maps source: hosted version: "0.9.0" + source_span: + description: source_span + source: hosted + version: "1.0.0" stack_trace: description: stack_trace source: hosted version: "0.9.3+1" - typed_mock: - description: typed_mock - source: hosted - version: "0.0.4" - unittest: - description: unittest - source: hosted - version: "0.10.1+2" utf: description: utf source: hosted @@ -92,4 +88,4 @@ packages: web_components: description: web_components source: hosted - version: "0.3.5+1" + version: "0.8.0" diff --git a/Chapter_01/pubspec.yaml b/Chapter_01/pubspec.yaml index 7757788..84adfed 100644 --- a/Chapter_01/pubspec.yaml +++ b/Chapter_01/pubspec.yaml @@ -1,8 +1,8 @@ -name: angular_dart_demo -version: 0.0.1 +name: tutorial +version: 1.0.0 dependencies: - angular: 0.13.0 -dev_dependencies: - unittest: any + angular: "1.0.0" + web_components: ">=0.8.0 <0.9.0" + browser: ">=0.10.0+2 <0.11.0" transformers: - angular diff --git a/Chapter_01/web/index.html b/Chapter_01/web/index.html index b40f1a3..102918e 100644 --- a/Chapter_01/web/index.html +++ b/Chapter_01/web/index.html @@ -1,14 +1,12 @@ - Hello, World! - + Chapter One - Hello, World! - -

Hello {{name}}!

+

Hello {{name}}!

Name: diff --git a/Chapter_01/web/main.dart b/Chapter_01/web/main.dart index 9d3b812..7094cde 100644 --- a/Chapter_01/web/main.dart +++ b/Chapter_01/web/main.dart @@ -1,6 +1,13 @@ -import 'package:angular/angular.dart'; import 'package:angular/application_factory.dart'; +import 'package:di/annotations.dart'; + +@Injectable() +class Greeter { + String name; +} void main() { - applicationFactory().run(); + applicationFactory() + .rootContextType(Greeter) + .run(); } diff --git a/Chapter_02/README.md b/Chapter_02/README.md index faac44f..8a94918 100644 --- a/Chapter_02/README.md +++ b/Chapter_02/README.md @@ -1,5 +1,2 @@ Recipe Book AngularDart application -Illustrates how to create a basic Angular controller - -For a runnable version of this app, see this community-contributed demo: -http://runnable.com/UvLw-HVhFtxBAAAf/angular-dart-tutorial-chapter-02 \ No newline at end of file +Illustrates how to create a basic Angular component diff --git a/Chapter_03/lib/recipe_book.dart b/Chapter_02/lib/component/recipe_book.dart similarity index 64% rename from Chapter_03/lib/recipe_book.dart rename to Chapter_02/lib/component/recipe_book.dart index 93a3b3e..4b281d9 100644 --- a/Chapter_03/lib/recipe_book.dart +++ b/Chapter_02/lib/component/recipe_book.dart @@ -1,15 +1,21 @@ -library recipe_book_controller; +library recipe_book_component; import 'package:angular/angular.dart'; -@Controller( - selector: '[recipe-book]', - publishAs: 'ctrl') -class RecipeBookController { +/* The selector field defines the CSS selector that will trigger the component. It can be any valid + * CSS selector which does not cross element boundaries. + * + * The component's public fields are available for data binding from the view. + * Similarly, the component's public methods can be invoked from the view. + */ +@Component( + selector: 'recipe-book', + templateUrl: 'recipe_book.html') +class RecipeBookComponent { Recipe selectedRecipe; - List recipes; + List recipes; - RecipeBookController() { + RecipeBookComponent() { recipes = _loadData(); } @@ -45,12 +51,11 @@ class RecipeBookController { } class Recipe { - String name; - String category; - List ingredients; - String directions; + final String name; + final String category; + final List ingredients; + final String directions; int rating; - Recipe(this.name, this.category, this.ingredients, this.directions, - this.rating); + Recipe(this.name, this.category, this.ingredients, this.directions, this.rating); } diff --git a/Chapter_02/lib/component/recipe_book.html b/Chapter_02/lib/component/recipe_book.html new file mode 100644 index 0000000..f2b618f --- /dev/null +++ b/Chapter_02/lib/component/recipe_book.html @@ -0,0 +1,21 @@ +

Recipe List

+
    +
  • + {{recipe.name}} +
  • +
+ +

Recipe Details

+
Name: {{selectedRecipe.name}}
+
Category: {{selectedRecipe.category}}
+
Rating: {{selectedRecipe.rating}}
+
+
    +
  • + {{ingredient}} +
  • +
+
+
Directions: {{selectedRecipe.directions}}
diff --git a/Chapter_02/pubspec.lock b/Chapter_02/pubspec.lock index 1be98f2..2230e60 100644 --- a/Chapter_02/pubspec.lock +++ b/Chapter_02/pubspec.lock @@ -4,11 +4,11 @@ packages: analyzer: description: analyzer source: hosted - version: "0.18.0" + version: "0.15.7" angular: description: angular source: hosted - version: "0.13.0" + version: "1.0.0" args: description: args source: hosted @@ -16,7 +16,7 @@ packages: barback: description: barback source: hosted - version: "0.13.0" + version: "0.14.2" browser: description: browser source: hosted @@ -24,15 +24,15 @@ packages: code_transformers: description: code_transformers source: hosted - version: "0.1.5" + version: "0.1.6" collection: description: collection source: hosted - version: "0.9.1" + version: "0.9.4" di: description: di source: hosted - version: "2.0.1" + version: "3.3.1" html5lib: description: html5lib source: hosted @@ -40,56 +40,68 @@ packages: intl: description: intl source: hosted - version: "0.8.10+4" + version: "0.11.9" logging: description: logging source: hosted - version: "0.9.1+1" + version: "0.9.2" matcher: description: matcher source: hosted - version: "0.10.0" - meta: - description: meta - source: hosted - version: "0.8.8" + version: "0.11.1" mock: description: mock source: hosted - version: "0.10.0+1" + version: "0.11.0+2" + observe: + description: observe + source: hosted + version: "0.10.1+2" path: description: path source: hosted - version: "1.2.2" + version: "1.3.0" perf_api: description: perf_api source: hosted - version: "0.0.8" + version: "0.0.9" + petitparser: + description: petitparser + source: hosted + version: "1.2.2" + pool: + description: pool + source: hosted + version: "1.0.1" route_hierarchical: description: route_hierarchical source: hosted - version: "0.4.21" + version: "0.5.0" + smoke: + description: smoke + source: hosted + version: "0.1.0+1" source_maps: description: source_maps source: hosted - version: "0.9.0" + version: "0.9.4" + source_span: + description: source_span + source: hosted + version: "1.0.0" stack_trace: description: stack_trace source: hosted - version: "0.9.3+1" - typed_mock: - description: typed_mock - source: hosted - version: "0.0.4" + version: "1.1.1" unittest: description: unittest source: hosted - version: "0.10.1+2" + version: "0.11.0+5" utf: description: utf source: hosted - version: "0.9.0" + version: "0.9.0+1" web_components: description: web_components source: hosted - version: "0.3.5+1" + version: "0.8.0" diff --git a/Chapter_02/pubspec.yaml b/Chapter_02/pubspec.yaml index 7757788..c04b589 100644 --- a/Chapter_02/pubspec.yaml +++ b/Chapter_02/pubspec.yaml @@ -1,8 +1,14 @@ -name: angular_dart_demo -version: 0.0.1 +name: tutorial +version: 1.0.0 dependencies: - angular: 0.13.0 + angular: "1.0.0" + web_components: ">=0.8.0 <0.9.0" + browser: ">=0.10.0+2 <0.11.0" dev_dependencies: - unittest: any + unittest: ">=0.11.0+5 <0.12.0" + mock: ">=0.11.0+2 <0.12.0" transformers: -- angular +- angular: + html_files: + - lib/component/recipe_book.html + diff --git a/Chapter_02/test/main_test.dart b/Chapter_02/test/main_test.dart index 6c3e293..ae27cff 100644 --- a/Chapter_02/test/main_test.dart +++ b/Chapter_02/test/main_test.dart @@ -4,6 +4,7 @@ import 'package:unittest/unittest.dart'; import 'package:di/di.dart'; import 'package:angular/angular.dart'; import 'package:angular/mock/module.dart'; +import 'package:tutorial/component/recipe_book.dart'; import '../web/main.dart'; @@ -11,17 +12,17 @@ main() { setUp(setUpInjector); tearDown(tearDownInjector); - group('recipe-book', () { + group('recipe book component', () { setUp(module((Module m) => m.install(new MyAppModule()))); - test('should load recipes', inject((RecipeBookController recipesController) { - expect(recipesController.recipes, isNot(isEmpty)); + test('should load recipes', inject((RecipeBookComponent recipeBook) { + expect(recipeBook.recipes, isNot(isEmpty)); })); - test('should select recipe', inject((RecipeBookController recipesController) { - var recipe = recipesController.recipes[0]; - recipesController.selectRecipe(recipe); - expect(recipesController.selectedRecipe, same(recipe)); + test('should select recipe', inject((RecipeBookComponent recipeBook) { + var recipe = recipeBook.recipes[0]; + recipeBook.selectRecipe(recipe); + expect(recipeBook.selectedRecipe, same(recipe)); })); }); } diff --git a/Chapter_02/web/index.html b/Chapter_02/web/index.html index 83c10ff..9497ec4 100644 --- a/Chapter_02/web/index.html +++ b/Chapter_02/web/index.html @@ -1,5 +1,5 @@ - + Chapter Two - A Simple Recipe Book @@ -8,30 +8,7 @@ - -
-

Recipe List

-
    -
  • - {{recipe.name}} -
  • -
- -

Recipe Details

-
Name: {{ctrl.selectedRecipe.name}}
-
Category: {{ctrl.selectedRecipe.category}}
-
Rating: {{ctrl.selectedRecipe.rating}}
-
-
    -
  • - {{ingredient}} -
  • -
-
-
Directions: {{ctrl.selectedRecipe.directions}}
-
+ diff --git a/Chapter_02/web/main.dart b/Chapter_02/web/main.dart index 22c1beb..2f18a72 100644 --- a/Chapter_02/web/main.dart +++ b/Chapter_02/web/main.dart @@ -2,77 +2,11 @@ library recipe_book; import 'package:angular/angular.dart'; import 'package:angular/application_factory.dart'; - -/* Use the @Controller annotation to indicate that this class is an - * Angular controller. Angular will instantiate the controller if - * it finds an element matching its selector in the DOM. - * - * The selector field defines the CSS selector that will trigger the - * controller. It can be any valid CSS selector which does not cross - * element boundaries. - * - * The publishAs field specifies that the controller instance should be - * assigned to the current scope under the name specified. - * - * The controller's public fields are available for data binding from the view. - * Similarly, the controller's public methods can be invoked from the view. - */ -@Controller( - selector: '[recipe-book]', - publishAs: 'ctrl') -class RecipeBookController { - Recipe selectedRecipe; - List recipes; - - RecipeBookController() { - recipes = _loadData(); - } - - void selectRecipe(Recipe recipe) { - selectedRecipe = recipe; - } - - List _loadData() { - return [ - new Recipe('My Appetizer','Appetizers', - ["Ingredient 1", "Ingredient 2"], - "Some Directions", 1), - new Recipe('My Salad','Salads', - ["Ingredient 1", "Ingredient 2"], - "Some Directions", 3), - new Recipe('My Soup','Soups', - ["Ingredient 1", "Ingredient 2"], - "Some Directions", 4), - new Recipe('My Main Dish','Main Dishes', - ["Ingredient 1", "Ingredient 2"], - "Some Directions", 2), - new Recipe('My Side Dish','Side Dishes', - ["Ingredient 1", "Ingredient 2"], - "Some Directions", 3), - new Recipe('My Awesome Dessert','Desserts', - ["Ingredient 1", "Ingredient 2"], - "Some Directions", 5), - new Recipe('My So-So Dessert','Desserts', - ["Ingredient 1", "Ingredient 2"], - "Some Directions", 3), - ]; - } -} - -class Recipe { - String name; - String category; - List ingredients; - String directions; - int rating; - - Recipe(this.name, this.category, this.ingredients, this.directions, - this.rating); -} +import 'package:tutorial/component/recipe_book.dart'; class MyAppModule extends Module { MyAppModule() { - bind(RecipeBookController); + bind(RecipeBookComponent); } } diff --git a/Chapter_03/README.md b/Chapter_03/README.md index 92ab0f6..ecf4937 100644 --- a/Chapter_03/README.md +++ b/Chapter_03/README.md @@ -1,5 +1,2 @@ Recipe Book AngularDart application -Illustrates the use of an Angular component - -For a runnable version of this app, see this community-contributed demo: -http://runnable.com/UvLzx4BMROhBAABH/angular-dart-tutorial-chapter-03 \ No newline at end of file +Illustrates the use of an Angular components diff --git a/Chapter_03/lib/rating/rating_component.css b/Chapter_03/lib/component/rating.css similarity index 100% rename from Chapter_03/lib/rating/rating_component.css rename to Chapter_03/lib/component/rating.css diff --git a/Chapter_04/lib/rating/rating_component.dart b/Chapter_03/lib/component/rating.dart similarity index 85% rename from Chapter_04/lib/rating/rating_component.dart rename to Chapter_03/lib/component/rating.dart index f0e20ee..5ef1fcc 100644 --- a/Chapter_04/lib/rating/rating_component.dart +++ b/Chapter_03/lib/component/rating.dart @@ -29,9 +29,8 @@ import 'package:angular/angular.dart'; */ @Component( selector: 'rating', - templateUrl: 'packages/angular_dart_demo/rating/rating_component.html', - cssUrl: 'packages/angular_dart_demo/rating/rating_component.css', - publishAs: 'cmp') + templateUrl: 'rating.html', + cssUrl: 'rating.css') class RatingComponent { static const String _STAR_ON_CHAR = "\u2605"; static const String _STAR_OFF_CHAR = "\u2606"; @@ -54,9 +53,10 @@ class RatingComponent { } String starClass(int star) => - star > rating ? _STAR_OFF_CLASS : _STAR_ON_CLASS; + rating == null || star > rating ? _STAR_OFF_CLASS : _STAR_ON_CLASS; - String starChar(int star) => star > rating ? _STAR_OFF_CHAR : _STAR_ON_CHAR; + String starChar(int star) => + rating == null || star > rating ? _STAR_OFF_CHAR : _STAR_ON_CHAR; void handleClick(int star) { rating = (star == 1 && rating == 1) ? 0 : star; diff --git a/Chapter_03/lib/component/rating.html b/Chapter_03/lib/component/rating.html new file mode 100644 index 0000000..0d89be9 --- /dev/null +++ b/Chapter_03/lib/component/rating.html @@ -0,0 +1,6 @@ + + {{starChar(star)}} + diff --git a/Chapter_03/lib/component/recipe_book.dart b/Chapter_03/lib/component/recipe_book.dart new file mode 100644 index 0000000..4b281d9 --- /dev/null +++ b/Chapter_03/lib/component/recipe_book.dart @@ -0,0 +1,61 @@ +library recipe_book_component; + +import 'package:angular/angular.dart'; + +/* The selector field defines the CSS selector that will trigger the component. It can be any valid + * CSS selector which does not cross element boundaries. + * + * The component's public fields are available for data binding from the view. + * Similarly, the component's public methods can be invoked from the view. + */ +@Component( + selector: 'recipe-book', + templateUrl: 'recipe_book.html') +class RecipeBookComponent { + Recipe selectedRecipe; + List recipes; + + RecipeBookComponent() { + recipes = _loadData(); + } + + void selectRecipe(Recipe recipe) { + selectedRecipe = recipe; + } + + List _loadData() { + return [ + new Recipe('My Appetizer','Appetizers', + ["Ingredient 1", "Ingredient 2"], + "Some Directions", 1), + new Recipe('My Salad','Salads', + ["Ingredient 1", "Ingredient 2"], + "Some Directions", 3), + new Recipe('My Soup','Soups', + ["Ingredient 1", "Ingredient 2"], + "Some Directions", 4), + new Recipe('My Main Dish','Main Dishes', + ["Ingredient 1", "Ingredient 2"], + "Some Directions", 2), + new Recipe('My Side Dish','Side Dishes', + ["Ingredient 1", "Ingredient 2"], + "Some Directions", 3), + new Recipe('My Awesome Dessert','Desserts', + ["Ingredient 1", "Ingredient 2"], + "Some Directions", 5), + new Recipe('My So-So Dessert','Desserts', + ["Ingredient 1", "Ingredient 2"], + "Some Directions", 3), + ]; + } +} + +class Recipe { + final String name; + final String category; + final List ingredients; + final String directions; + int rating; + + Recipe(this.name, this.category, this.ingredients, this.directions, this.rating); +} diff --git a/Chapter_03/lib/component/recipe_book.html b/Chapter_03/lib/component/recipe_book.html new file mode 100644 index 0000000..c880fb5 --- /dev/null +++ b/Chapter_03/lib/component/recipe_book.html @@ -0,0 +1,23 @@ +

Recipe List

+
    +
  • + + {{recipe.name}} +
  • +
+ +

Recipe Details

+
Name: {{selectedRecipe.name}}
+
Category: {{selectedRecipe.category}}
+
Rating:
+
+
    +
  • + {{ingredient}} +
  • +
+
+
Directions: {{selectedRecipe.directions}}
diff --git a/Chapter_03/lib/rating/rating_component.html b/Chapter_03/lib/rating/rating_component.html deleted file mode 100644 index 05e77de..0000000 --- a/Chapter_03/lib/rating/rating_component.html +++ /dev/null @@ -1,6 +0,0 @@ - - {{cmp.starChar(star)}} - diff --git a/Chapter_03/pubspec.lock b/Chapter_03/pubspec.lock index 1be98f2..59b0e11 100644 --- a/Chapter_03/pubspec.lock +++ b/Chapter_03/pubspec.lock @@ -4,11 +4,13 @@ packages: analyzer: description: analyzer source: hosted - version: "0.18.0" + version: "0.15.7" angular: - description: angular - source: hosted - version: "0.13.0" + description: + path: "/home/victor/dart/angular.dart" + relative: false + source: path + version: "1.0.0" args: description: args source: hosted @@ -32,7 +34,7 @@ packages: di: description: di source: hosted - version: "2.0.1" + version: "3.3.1" html5lib: description: html5lib source: hosted @@ -56,7 +58,11 @@ packages: mock: description: mock source: hosted - version: "0.10.0+1" + version: "0.11.0+2" + observe: + description: observe + source: hosted + version: "0.10.1+2" path: description: path source: hosted @@ -64,27 +70,31 @@ packages: perf_api: description: perf_api source: hosted - version: "0.0.8" + version: "0.0.9" route_hierarchical: description: route_hierarchical source: hosted - version: "0.4.21" + version: "0.5.0" + smoke: + description: smoke + source: hosted + version: "0.1.0+1" source_maps: description: source_maps source: hosted version: "0.9.0" + source_span: + description: source_span + source: hosted + version: "1.0.0" stack_trace: description: stack_trace source: hosted version: "0.9.3+1" - typed_mock: - description: typed_mock - source: hosted - version: "0.0.4" unittest: description: unittest source: hosted - version: "0.10.1+2" + version: "0.11.0+5" utf: description: utf source: hosted @@ -92,4 +102,4 @@ packages: web_components: description: web_components source: hosted - version: "0.3.5+1" + version: "0.8.0" diff --git a/Chapter_03/pubspec.yaml b/Chapter_03/pubspec.yaml index 7757788..041c3e0 100644 --- a/Chapter_03/pubspec.yaml +++ b/Chapter_03/pubspec.yaml @@ -1,8 +1,16 @@ -name: angular_dart_demo -version: 0.0.1 +name: tutorial +version: 1.0.0 dependencies: - angular: 0.13.0 + angular: + path: /home/victor/dart/angular.dart + web_components: ">=0.8.0 <0.9.0" + browser: ">=0.10.0+2 <0.11.0" dev_dependencies: - unittest: any + unittest: ">=0.11.0+5 <0.12.0" + mock: ">=0.11.0+2 <0.12.0" transformers: -- angular +- angular: + html_files: + - lib/component/recipe_book.html + - lib/component/rating.html + diff --git a/Chapter_03/test/main_test.dart b/Chapter_03/test/main_test.dart index 6352bc3..6aba479 100644 --- a/Chapter_03/test/main_test.dart +++ b/Chapter_03/test/main_test.dart @@ -4,27 +4,28 @@ import 'package:unittest/unittest.dart'; import 'package:di/di.dart'; import 'package:angular/angular.dart'; import 'package:angular/mock/module.dart'; -import 'package:angular_dart_demo/recipe_book.dart'; -import 'package:angular_dart_demo/rating/rating_component.dart'; +import 'package:tutorial/component/recipe_book.dart'; +import 'package:tutorial/component/rating.dart'; import '../web/main.dart'; main() { setUp(() { - setUpInjector(); - module((Module m) => m.install(new MyAppModule())); + setUpInjector(); + module((Module m) => m.install(new MyAppModule())); }); + tearDown(tearDownInjector); - group('recipe-book', () { - test('should load recipes', inject((RecipeBookController recipesController) { - expect(recipesController.recipes, isNot(isEmpty)); + group('recipe book component', () { + test('should load recipes', inject((RecipeBookComponent recipeBook) { + expect(recipeBook.recipes, isNot(isEmpty)); })); - test('should select recipe', inject((RecipeBookController recipesController) { - var recipe = recipesController.recipes[0]; - recipesController.selectRecipe(recipe); - expect(recipesController.selectedRecipe, same(recipe)); + test('should select recipe', inject((RecipeBookComponent recipeBook) { + var recipe = recipeBook.recipes[0]; + recipeBook.selectRecipe(recipe); + expect(recipeBook.selectedRecipe, same(recipe)); })); }); diff --git a/Chapter_03/web/index.html b/Chapter_03/web/index.html index 04d4473..799b55a 100644 --- a/Chapter_03/web/index.html +++ b/Chapter_03/web/index.html @@ -8,36 +8,8 @@ - -
-

Recipe List

-
    -
  • - - {{recipe.name}} -
  • -
- -
-

Recipe Details

-
Name: {{ctrl.selectedRecipe.name}}
-
Category: {{ctrl.selectedRecipe.category}}
-
Rating: - -
-
-
    -
  • - {{ingredient}} -
  • -
-
-
Directions: {{ctrl.selectedRecipe.directions}}
-
-
- + + diff --git a/Chapter_03/web/main.dart b/Chapter_03/web/main.dart index 1f6797b..4acce41 100644 --- a/Chapter_03/web/main.dart +++ b/Chapter_03/web/main.dart @@ -3,12 +3,12 @@ library recipe_book; import 'package:angular/angular.dart'; import 'package:angular/application_factory.dart'; -import 'package:angular_dart_demo/rating/rating_component.dart'; -import 'package:angular_dart_demo/recipe_book.dart'; +import 'package:tutorial/component/rating.dart'; +import 'package:tutorial/component/recipe_book.dart'; class MyAppModule extends Module { MyAppModule() { - bind(RecipeBookController); + bind(RecipeBookComponent); bind(RatingComponent); } } diff --git a/Chapter_04/README.md b/Chapter_04/README.md index ad23985..e744bf5 100644 --- a/Chapter_04/README.md +++ b/Chapter_04/README.md @@ -1,5 +1,2 @@ Recipe Book AngularDart application Illustrates the use of an Angular directive - -For a runnable version of this app, see this community-contributed demo: -http://runnable.com/UvL2Q4UQl05CAAAX/angular-dart-tutorial-chapter-04 \ No newline at end of file diff --git a/Chapter_04/lib/rating/rating_component.css b/Chapter_04/lib/component/rating.css similarity index 100% rename from Chapter_04/lib/rating/rating_component.css rename to Chapter_04/lib/component/rating.css diff --git a/Chapter_03/lib/rating/rating_component.dart b/Chapter_04/lib/component/rating.dart similarity index 87% rename from Chapter_03/lib/rating/rating_component.dart rename to Chapter_04/lib/component/rating.dart index f0e20ee..ebe1a81 100644 --- a/Chapter_03/lib/rating/rating_component.dart +++ b/Chapter_04/lib/component/rating.dart @@ -29,9 +29,8 @@ import 'package:angular/angular.dart'; */ @Component( selector: 'rating', - templateUrl: 'packages/angular_dart_demo/rating/rating_component.html', - cssUrl: 'packages/angular_dart_demo/rating/rating_component.css', - publishAs: 'cmp') + templateUrl: 'rating.html', + cssUrl: 'rating.css') class RatingComponent { static const String _STAR_ON_CHAR = "\u2605"; static const String _STAR_OFF_CHAR = "\u2606"; @@ -53,8 +52,7 @@ class RatingComponent { stars = new List.generate(count, (i) => i + 1); } - String starClass(int star) => - star > rating ? _STAR_OFF_CLASS : _STAR_ON_CLASS; + String starClass(int star) => star > rating ? _STAR_OFF_CLASS : _STAR_ON_CLASS; String starChar(int star) => star > rating ? _STAR_OFF_CHAR : _STAR_ON_CHAR; diff --git a/Chapter_04/lib/component/rating.html b/Chapter_04/lib/component/rating.html new file mode 100644 index 0000000..0d89be9 --- /dev/null +++ b/Chapter_04/lib/component/rating.html @@ -0,0 +1,6 @@ + + {{starChar(star)}} + diff --git a/Chapter_04/lib/recipe_book.dart b/Chapter_04/lib/component/recipe_book.dart similarity index 69% rename from Chapter_04/lib/recipe_book.dart rename to Chapter_04/lib/component/recipe_book.dart index 61008de..3ae1845 100644 --- a/Chapter_04/lib/recipe_book.dart +++ b/Chapter_04/lib/component/recipe_book.dart @@ -1,17 +1,22 @@ -library recipe_book_controller; +library recipe_book_component; import 'package:angular/angular.dart'; +import 'package:tutorial/tooltip/tooltip.dart' show TooltipModel; -import 'tooltip/tooltip.dart'; - -@Controller( - selector: '[recipe-book]', - publishAs: 'ctrl') -class RecipeBookController { +/* The selector field defines the CSS selector that will trigger the component. It can be any valid + * CSS selector which does not cross element boundaries. + * + * The component's public fields are available for data binding from the view. + * Similarly, the component's public methods can be invoked from the view. + */ +@Component( + selector: 'recipe-book', + templateUrl: 'recipe_book.html') +class RecipeBookComponent { Recipe selectedRecipe; - List recipes; + List recipes; - RecipeBookController() { + RecipeBookComponent() { recipes = _loadData(); } @@ -60,13 +65,12 @@ class RecipeBookController { } class Recipe { - String name; - String category; - List ingredients; - String directions; + final String name; + final String category; + final List ingredients; + final String directions; + final String imgUrl; int rating; - String imgUrl; - Recipe(this.name, this.category, this.ingredients, this.directions, - this.rating, this.imgUrl); + Recipe(this.name, this.category, this.ingredients, this.directions, this.rating, this.imgUrl); } diff --git a/Chapter_04/lib/component/recipe_book.html b/Chapter_04/lib/component/recipe_book.html new file mode 100644 index 0000000..65065fb --- /dev/null +++ b/Chapter_04/lib/component/recipe_book.html @@ -0,0 +1,25 @@ +

Recipe List

+
    +
  • + + + {{recipe.name}} + +
  • +
+ +

Recipe Details

+
Name: {{selectedRecipe.name}}
+
Category: {{selectedRecipe.category}}
+
Rating:
+
+
    +
  • + {{ingredient}} +
  • +
+
+
Directions: {{selectedRecipe.directions}}
diff --git a/Chapter_04/lib/rating/rating_component.html b/Chapter_04/lib/rating/rating_component.html deleted file mode 100644 index 05e77de..0000000 --- a/Chapter_04/lib/rating/rating_component.html +++ /dev/null @@ -1,6 +0,0 @@ - - {{cmp.starChar(star)}} - diff --git a/Chapter_04/lib/tooltip/tooltip.dart b/Chapter_04/lib/tooltip/tooltip.dart index f3d783b..85e97a4 100644 --- a/Chapter_04/lib/tooltip/tooltip.dart +++ b/Chapter_04/lib/tooltip/tooltip.dart @@ -3,8 +3,7 @@ library tooltip; import 'dart:html' as dom; import 'package:angular/angular.dart'; -@Decorator( - selector: '[tooltip]') +@Decorator(selector: '[tooltip]') class Tooltip { final dom.Element element; @@ -53,9 +52,8 @@ class Tooltip { ..top = "${elTopRight.y}px" ..left = "${elTopRight.x + 10}px"; - // Add the tooltip to the document body. We add it here because - // we need to position it absolutely, without reference to its - // parent element. + // Add the tooltip to the document body. We add it here because we need to position it + // absolutely, without reference to its parent element. dom.document.body.append(tooltipElem); } @@ -65,9 +63,9 @@ class Tooltip { } class TooltipModel { - String imgUrl; - String text; - int imgWidth; + final String imgUrl; + final String text; + final int imgWidth; TooltipModel(this.imgUrl, this.text, this.imgWidth); } diff --git a/Chapter_04/pubspec.lock b/Chapter_04/pubspec.lock index 1be98f2..f65f28e 100644 --- a/Chapter_04/pubspec.lock +++ b/Chapter_04/pubspec.lock @@ -4,11 +4,11 @@ packages: analyzer: description: analyzer source: hosted - version: "0.18.0" + version: "0.15.7" angular: description: angular source: hosted - version: "0.13.0" + version: "1.0.0" args: description: args source: hosted @@ -32,7 +32,7 @@ packages: di: description: di source: hosted - version: "2.0.1" + version: "3.3.1" html5lib: description: html5lib source: hosted @@ -56,7 +56,11 @@ packages: mock: description: mock source: hosted - version: "0.10.0+1" + version: "0.11.0+2" + observe: + description: observe + source: hosted + version: "0.10.1+2" path: description: path source: hosted @@ -64,27 +68,31 @@ packages: perf_api: description: perf_api source: hosted - version: "0.0.8" + version: "0.0.9" route_hierarchical: description: route_hierarchical source: hosted - version: "0.4.21" + version: "0.5.0" + smoke: + description: smoke + source: hosted + version: "0.1.0+1" source_maps: description: source_maps source: hosted version: "0.9.0" + source_span: + description: source_span + source: hosted + version: "1.0.0" stack_trace: description: stack_trace source: hosted version: "0.9.3+1" - typed_mock: - description: typed_mock - source: hosted - version: "0.0.4" unittest: description: unittest source: hosted - version: "0.10.1+2" + version: "0.11.0+5" utf: description: utf source: hosted @@ -92,4 +100,4 @@ packages: web_components: description: web_components source: hosted - version: "0.3.5+1" + version: "0.8.0" diff --git a/Chapter_04/pubspec.yaml b/Chapter_04/pubspec.yaml index 7757788..019f34c 100644 --- a/Chapter_04/pubspec.yaml +++ b/Chapter_04/pubspec.yaml @@ -1,8 +1,14 @@ -name: angular_dart_demo -version: 0.0.1 +name: tutorial +version: 1.0.0 dependencies: - angular: 0.13.0 + angular: "1.0.0" + web_components: ">=0.8.0 <0.9.0" + browser: ">=0.10.0+2 <0.11.0" dev_dependencies: - unittest: any + unittest: ">=0.11.0+5 <0.12.0" + mock: ">=0.11.0+2 <0.12.0" transformers: -- angular +- angular: + html_files: + - lib/component/recipe_book.html + - lib/component/rating.html diff --git a/Chapter_04/test/main_test.dart b/Chapter_04/test/main_test.dart index 6352bc3..6aba479 100644 --- a/Chapter_04/test/main_test.dart +++ b/Chapter_04/test/main_test.dart @@ -4,27 +4,28 @@ import 'package:unittest/unittest.dart'; import 'package:di/di.dart'; import 'package:angular/angular.dart'; import 'package:angular/mock/module.dart'; -import 'package:angular_dart_demo/recipe_book.dart'; -import 'package:angular_dart_demo/rating/rating_component.dart'; +import 'package:tutorial/component/recipe_book.dart'; +import 'package:tutorial/component/rating.dart'; import '../web/main.dart'; main() { setUp(() { - setUpInjector(); - module((Module m) => m.install(new MyAppModule())); + setUpInjector(); + module((Module m) => m.install(new MyAppModule())); }); + tearDown(tearDownInjector); - group('recipe-book', () { - test('should load recipes', inject((RecipeBookController recipesController) { - expect(recipesController.recipes, isNot(isEmpty)); + group('recipe book component', () { + test('should load recipes', inject((RecipeBookComponent recipeBook) { + expect(recipeBook.recipes, isNot(isEmpty)); })); - test('should select recipe', inject((RecipeBookController recipesController) { - var recipe = recipesController.recipes[0]; - recipesController.selectRecipe(recipe); - expect(recipesController.selectedRecipe, same(recipe)); + test('should select recipe', inject((RecipeBookComponent recipeBook) { + var recipe = recipeBook.recipes[0]; + recipeBook.selectRecipe(recipe); + expect(recipeBook.selectedRecipe, same(recipe)); })); }); diff --git a/Chapter_04/web/index.html b/Chapter_04/web/index.html index 90d97e7..e47d0c5 100644 --- a/Chapter_04/web/index.html +++ b/Chapter_04/web/index.html @@ -8,37 +8,7 @@ - -
-

Recipe List

-
    -
  • - - - {{recipe.name}} - -
  • -
- -
-

Recipe Details

-
Name: {{ctrl.selectedRecipe.name}}
-
Category: {{ctrl.selectedRecipe.category}}
-
Rating: - -
-
-
    -
  • - {{ingredient}} -
  • -
-
-
Directions: {{ctrl.selectedRecipe.directions}}
-
-
+ diff --git a/Chapter_04/web/main.dart b/Chapter_04/web/main.dart index 9e2398d..bf2236c 100644 --- a/Chapter_04/web/main.dart +++ b/Chapter_04/web/main.dart @@ -3,13 +3,13 @@ library recipe_book; import 'package:angular/angular.dart'; import 'package:angular/application_factory.dart'; -import 'package:angular_dart_demo/recipe_book.dart'; -import 'package:angular_dart_demo/rating/rating_component.dart'; -import 'package:angular_dart_demo/tooltip/tooltip.dart'; +import 'package:tutorial/component/recipe_book.dart'; +import 'package:tutorial/component/rating.dart'; +import 'package:tutorial/tooltip/tooltip.dart'; class MyAppModule extends Module { MyAppModule() { - bind(RecipeBookController); + bind(RecipeBookComponent); bind(RatingComponent); bind(Tooltip); } diff --git a/Chapter_05/README.md b/Chapter_05/README.md index 9485969..27eca95 100644 --- a/Chapter_05/README.md +++ b/Chapter_05/README.md @@ -1,5 +1,2 @@ Recipe Book AngularDart application -Illustrates the use of filters and services - -For a runnable version of this app, see this community-contributed demo: -http://runnable.com/UvL5t92j1pVCAAAQ/angular-dart-tutorial-chapter-05 \ No newline at end of file +Illustrates the use of formatters and services diff --git a/Chapter_05/lib/rating/rating_component.css b/Chapter_05/lib/component/rating.css similarity index 100% rename from Chapter_05/lib/rating/rating_component.css rename to Chapter_05/lib/component/rating.css diff --git a/Chapter_06/lib/rating/rating_component.dart b/Chapter_05/lib/component/rating.dart similarity index 87% rename from Chapter_06/lib/rating/rating_component.dart rename to Chapter_05/lib/component/rating.dart index f0e20ee..ebe1a81 100644 --- a/Chapter_06/lib/rating/rating_component.dart +++ b/Chapter_05/lib/component/rating.dart @@ -29,9 +29,8 @@ import 'package:angular/angular.dart'; */ @Component( selector: 'rating', - templateUrl: 'packages/angular_dart_demo/rating/rating_component.html', - cssUrl: 'packages/angular_dart_demo/rating/rating_component.css', - publishAs: 'cmp') + templateUrl: 'rating.html', + cssUrl: 'rating.css') class RatingComponent { static const String _STAR_ON_CHAR = "\u2605"; static const String _STAR_OFF_CHAR = "\u2606"; @@ -53,8 +52,7 @@ class RatingComponent { stars = new List.generate(count, (i) => i + 1); } - String starClass(int star) => - star > rating ? _STAR_OFF_CLASS : _STAR_ON_CLASS; + String starClass(int star) => star > rating ? _STAR_OFF_CLASS : _STAR_ON_CLASS; String starChar(int star) => star > rating ? _STAR_OFF_CHAR : _STAR_ON_CHAR; diff --git a/Chapter_05/lib/component/rating.html b/Chapter_05/lib/component/rating.html new file mode 100644 index 0000000..0d89be9 --- /dev/null +++ b/Chapter_05/lib/component/rating.html @@ -0,0 +1,6 @@ + + {{starChar(star)}} + diff --git a/Chapter_05/lib/recipe_book.dart b/Chapter_05/lib/component/recipe_book.dart similarity index 67% rename from Chapter_05/lib/recipe_book.dart rename to Chapter_05/lib/component/recipe_book.dart index 40e28dc..751203e 100644 --- a/Chapter_05/lib/recipe_book.dart +++ b/Chapter_05/lib/component/recipe_book.dart @@ -1,15 +1,19 @@ -library recipe_book_controller; +library recipe_book_component; import 'package:angular/angular.dart'; +import 'package:tutorial/tooltip/tooltip.dart' show TooltipModel; +import 'package:tutorial/recipe.dart'; -import 'recipe.dart'; -import 'tooltip/tooltip.dart'; - -@Controller( - selector: '[recipe-book]', - publishAs: 'ctrl') -class RecipeBookController { - +/* The selector field defines the CSS selector that will trigger the component. It can be any valid + * CSS selector which does not cross element boundaries. + * + * The component's public fields are available for data binding from the view. + * Similarly, the component's public methods can be invoked from the view. + */ +@Component( + selector: 'recipe-book', + templateUrl: 'recipe_book.html') +class RecipeBookComponent { static const String LOADING_MESSAGE = "Loading recipe book..."; static const String ERROR_MESSAGE = "Sorry! The cook stepped out of the " "kitchen and took the recipe book with him!"; @@ -22,33 +26,34 @@ class RecipeBookController { bool categoriesLoaded = false; // Data objects that are loaded from the server side via json - List categories = []; List recipes = []; // Filter box final categoryFilterMap = {}; + Iterable get categories => categoryFilterMap.keys; String nameFilterString = ""; - RecipeBookController(this._http) { + Recipe selectedRecipe; + + RecipeBookComponent(this._http) { _loadData(); } - Recipe selectedRecipe; - void selectRecipe(Recipe recipe) { selectedRecipe = recipe; } // Tooltip - static final _tooltip = new Expando(); + static final tooltip = new Expando(); + TooltipModel tooltipForRecipe(Recipe recipe) { - if (_tooltip[recipe] == null) { - _tooltip[recipe] = new TooltipModel(recipe.imgUrl, + if (tooltip[recipe] == null) { + tooltip[recipe] = new TooltipModel(recipe.imgUrl, "I don't have a picture of these recipes, " "so here's one of my cat instead!", 80); } - return _tooltip[recipe]; // recipe.tooltip + return tooltip[recipe]; // recipe.tooltip } void clearFilters() { @@ -75,7 +80,6 @@ class RecipeBookController { .then((HttpResponse response) { print(response); for (String category in response.data) { - categories.add(category); categoryFilterMap[category] = false; } categoriesLoaded = true; diff --git a/Chapter_05/lib/component/recipe_book.html b/Chapter_05/lib/component/recipe_book.html new file mode 100644 index 0000000..88603cb --- /dev/null +++ b/Chapter_05/lib/component/recipe_book.html @@ -0,0 +1,56 @@ +
+
+ {{message}} +
+
+

Recipe List

+ +
+
+ + +
+
+ Filter recipes by category: + + + +
+ +
+ +
+
    +
  • + + + {{recipe.name}} + +
  • +
+
+ +
+

Recipe Details

+
Name: {{selectedRecipe.name}}
+
Category: {{selectedRecipe.category}}
+
Rating: + +
+
+
    +
  • + {{ingredient}} +
  • +
+
+
Directions: {{selectedRecipe.directions}}
+
+
+
diff --git a/Chapter_05/lib/rating/rating_component.html b/Chapter_05/lib/rating/rating_component.html deleted file mode 100644 index 05e77de..0000000 --- a/Chapter_05/lib/rating/rating_component.html +++ /dev/null @@ -1,6 +0,0 @@ - - {{cmp.starChar(star)}} - diff --git a/Chapter_05/lib/recipe.dart b/Chapter_05/lib/recipe.dart index 9957df6..967bdeb 100644 --- a/Chapter_05/lib/recipe.dart +++ b/Chapter_05/lib/recipe.dart @@ -6,11 +6,11 @@ class Recipe { String category; List ingredients; String directions; - int rating; String imgUrl; + int rating; - Recipe(this.id, this.name, this.category, this.ingredients, this.directions, - this.rating, this.imgUrl); + Recipe(this.id, this.name, this.category, this.ingredients, this.directions, this.rating, + this.imgUrl); Map toJson() => { "id": id, @@ -22,7 +22,6 @@ class Recipe { "imgUrl": imgUrl }; - Recipe.fromJson(Map json) : this(json['id'], - json['name'], json['category'], json['ingredients'], json['directions'], - json['rating'], json['imgUrl']); + Recipe.fromJson(Map json): this(json['id'], json['name'], json['category'], + json['ingredients'], json['directions'], json['rating'], json['imgUrl']); } diff --git a/Chapter_05/lib/tooltip/tooltip.dart b/Chapter_05/lib/tooltip/tooltip.dart index f3d783b..85e97a4 100644 --- a/Chapter_05/lib/tooltip/tooltip.dart +++ b/Chapter_05/lib/tooltip/tooltip.dart @@ -3,8 +3,7 @@ library tooltip; import 'dart:html' as dom; import 'package:angular/angular.dart'; -@Decorator( - selector: '[tooltip]') +@Decorator(selector: '[tooltip]') class Tooltip { final dom.Element element; @@ -53,9 +52,8 @@ class Tooltip { ..top = "${elTopRight.y}px" ..left = "${elTopRight.x + 10}px"; - // Add the tooltip to the document body. We add it here because - // we need to position it absolutely, without reference to its - // parent element. + // Add the tooltip to the document body. We add it here because we need to position it + // absolutely, without reference to its parent element. dom.document.body.append(tooltipElem); } @@ -65,9 +63,9 @@ class Tooltip { } class TooltipModel { - String imgUrl; - String text; - int imgWidth; + final String imgUrl; + final String text; + final int imgWidth; TooltipModel(this.imgUrl, this.text, this.imgWidth); } diff --git a/Chapter_05/pubspec.lock b/Chapter_05/pubspec.lock index 1be98f2..f65f28e 100644 --- a/Chapter_05/pubspec.lock +++ b/Chapter_05/pubspec.lock @@ -4,11 +4,11 @@ packages: analyzer: description: analyzer source: hosted - version: "0.18.0" + version: "0.15.7" angular: description: angular source: hosted - version: "0.13.0" + version: "1.0.0" args: description: args source: hosted @@ -32,7 +32,7 @@ packages: di: description: di source: hosted - version: "2.0.1" + version: "3.3.1" html5lib: description: html5lib source: hosted @@ -56,7 +56,11 @@ packages: mock: description: mock source: hosted - version: "0.10.0+1" + version: "0.11.0+2" + observe: + description: observe + source: hosted + version: "0.10.1+2" path: description: path source: hosted @@ -64,27 +68,31 @@ packages: perf_api: description: perf_api source: hosted - version: "0.0.8" + version: "0.0.9" route_hierarchical: description: route_hierarchical source: hosted - version: "0.4.21" + version: "0.5.0" + smoke: + description: smoke + source: hosted + version: "0.1.0+1" source_maps: description: source_maps source: hosted version: "0.9.0" + source_span: + description: source_span + source: hosted + version: "1.0.0" stack_trace: description: stack_trace source: hosted version: "0.9.3+1" - typed_mock: - description: typed_mock - source: hosted - version: "0.0.4" unittest: description: unittest source: hosted - version: "0.10.1+2" + version: "0.11.0+5" utf: description: utf source: hosted @@ -92,4 +100,4 @@ packages: web_components: description: web_components source: hosted - version: "0.3.5+1" + version: "0.8.0" diff --git a/Chapter_05/pubspec.yaml b/Chapter_05/pubspec.yaml index 7757788..019f34c 100644 --- a/Chapter_05/pubspec.yaml +++ b/Chapter_05/pubspec.yaml @@ -1,8 +1,14 @@ -name: angular_dart_demo -version: 0.0.1 +name: tutorial +version: 1.0.0 dependencies: - angular: 0.13.0 + angular: "1.0.0" + web_components: ">=0.8.0 <0.9.0" + browser: ">=0.10.0+2 <0.11.0" dev_dependencies: - unittest: any + unittest: ">=0.11.0+5 <0.12.0" + mock: ">=0.11.0+2 <0.12.0" transformers: -- angular +- angular: + html_files: + - lib/component/recipe_book.html + - lib/component/rating.html diff --git a/Chapter_05/test/main_test.dart b/Chapter_05/test/main_test.dart index ac36853..4c4db90 100644 --- a/Chapter_05/test/main_test.dart +++ b/Chapter_05/test/main_test.dart @@ -4,51 +4,51 @@ import 'package:unittest/unittest.dart'; import 'package:di/di.dart'; import 'package:angular/angular.dart'; import 'package:angular/mock/module.dart'; -import 'package:angular_dart_demo/recipe_book.dart'; -import 'package:angular_dart_demo/recipe.dart'; -import 'package:angular_dart_demo/formatter/category_filter.dart'; -import 'package:angular_dart_demo/rating/rating_component.dart'; +import 'package:tutorial/component/recipe_book.dart'; +import 'package:tutorial/component/rating.dart'; +import 'package:tutorial/recipe.dart'; +import 'package:tutorial/formatter/category_filter.dart'; import '../web/main.dart'; main() { setUp(() { - setUpInjector(); - module((Module m) => m.install(new MyAppModule())); + setUpInjector(); + module((Module m) => m.install(new MyAppModule())); }); + tearDown(tearDownInjector); - group('recipe-book', () { - test('should load recipes', async(inject((Injector injector, - MockHttpBackend backend) { + group('recipe book component', () { + test('should load recipes', async(inject((Injector injector, MockHttpBackend backend) { + backend.expectGET('recipes.json').respond('[{"name": "test1"}]'); backend.expectGET('categories.json').respond('["c1"]'); - var recipesController = injector.get(RecipeBookController); - expect(recipesController.recipes, isEmpty); + var recipeBook = injector.get(RecipeBookComponent); + expect(recipeBook.recipes, isEmpty); microLeap(); backend.flush(); microLeap(); - expect(recipesController.recipes, isNot(isEmpty)); + expect(recipeBook.recipes, isNot(isEmpty)); }))); - test('should select recipe', async(inject((Injector injector, - MockHttpBackend backend) { + test('should select recipe', async(inject((Injector injector, MockHttpBackend backend) { backend.expectGET('recipes.json').respond('[{"name": "test1"}]'); backend.expectGET('categories.json').respond('["c1"]'); - var recipesController = injector.get(RecipeBookController); - expect(recipesController.recipes, isEmpty); + var recipeBook = injector.get(RecipeBookComponent); + expect(recipeBook.recipes, isEmpty); microLeap(); backend.flush(); microLeap(); - var recipe = recipesController.recipes[0]; - recipesController.selectRecipe(recipe); - expect(recipesController.selectedRecipe, same(recipe)); + var recipe = recipeBook.recipes[0]; + recipeBook.selectRecipe(recipe); + expect(recipeBook.selectedRecipe, same(recipe)); }))); }); diff --git a/Chapter_05/web/index.html b/Chapter_05/web/index.html index b7a631d..7ad91d5 100644 --- a/Chapter_05/web/index.html +++ b/Chapter_05/web/index.html @@ -7,66 +7,9 @@ - -
-
- {{ctrl.message}} -
-
-

Recipe List

+ -
-
- - -
-
- Filter recipes by category: - - - -
- -
- -
-
    -
  • - - - {{recipe.name}} - -
  • -
-
- -
-

Recipe Details

-
Name: {{ctrl.selectedRecipe.name}}
-
Category: {{ctrl.selectedRecipe.category}}
-
Rating: - -
-
-
    -
  • - {{ingredient}} -
  • -
-
-
Directions: {{ctrl.selectedRecipe.directions}}
-
-
- -
- - + diff --git a/Chapter_05/web/main.dart b/Chapter_05/web/main.dart index 8aa2b2f..e09808c 100644 --- a/Chapter_05/web/main.dart +++ b/Chapter_05/web/main.dart @@ -3,14 +3,14 @@ library recipe_book; import 'package:angular/angular.dart'; import 'package:angular/application_factory.dart'; -import 'package:angular_dart_demo/recipe_book.dart'; -import 'package:angular_dart_demo/formatter/category_filter.dart'; -import 'package:angular_dart_demo/rating/rating_component.dart'; -import 'package:angular_dart_demo/tooltip/tooltip.dart'; +import 'package:tutorial/component/recipe_book.dart'; +import 'package:tutorial/component/rating.dart'; +import 'package:tutorial/formatter/category_filter.dart'; +import 'package:tutorial/tooltip/tooltip.dart'; class MyAppModule extends Module { MyAppModule() { - bind(RecipeBookController); + bind(RecipeBookComponent); bind(RatingComponent); bind(Tooltip); bind(CategoryFilter); diff --git a/Chapter_06/README.md b/Chapter_06/README.md index 4932b36..b27834e 100644 --- a/Chapter_06/README.md +++ b/Chapter_06/README.md @@ -1,5 +1,2 @@ Recipe Book AngularDart application Illustrates the use of routing to create views - -For a runnable version of this app, see this community-contributed demo: -http://runnable.com/UvL9HZPUCvpCAAAX/angular-dart-tutorial-chapter-06 \ No newline at end of file diff --git a/Chapter_06/lib/rating/rating_component.css b/Chapter_06/lib/component/rating.css similarity index 100% rename from Chapter_06/lib/rating/rating_component.css rename to Chapter_06/lib/component/rating.css diff --git a/Chapter_05/lib/rating/rating_component.dart b/Chapter_06/lib/component/rating.dart similarity index 87% rename from Chapter_05/lib/rating/rating_component.dart rename to Chapter_06/lib/component/rating.dart index f0e20ee..ebe1a81 100644 --- a/Chapter_05/lib/rating/rating_component.dart +++ b/Chapter_06/lib/component/rating.dart @@ -29,9 +29,8 @@ import 'package:angular/angular.dart'; */ @Component( selector: 'rating', - templateUrl: 'packages/angular_dart_demo/rating/rating_component.html', - cssUrl: 'packages/angular_dart_demo/rating/rating_component.css', - publishAs: 'cmp') + templateUrl: 'rating.html', + cssUrl: 'rating.css') class RatingComponent { static const String _STAR_ON_CHAR = "\u2605"; static const String _STAR_OFF_CHAR = "\u2606"; @@ -53,8 +52,7 @@ class RatingComponent { stars = new List.generate(count, (i) => i + 1); } - String starClass(int star) => - star > rating ? _STAR_OFF_CLASS : _STAR_ON_CLASS; + String starClass(int star) => star > rating ? _STAR_OFF_CLASS : _STAR_ON_CLASS; String starChar(int star) => star > rating ? _STAR_OFF_CHAR : _STAR_ON_CHAR; diff --git a/Chapter_06/lib/component/rating.html b/Chapter_06/lib/component/rating.html new file mode 100644 index 0000000..0d89be9 --- /dev/null +++ b/Chapter_06/lib/component/rating.html @@ -0,0 +1,6 @@ + + {{starChar(star)}} + diff --git a/Chapter_06/lib/recipe_book.dart b/Chapter_06/lib/component/recipe_book.dart similarity index 70% rename from Chapter_06/lib/recipe_book.dart rename to Chapter_06/lib/component/recipe_book.dart index 0257707..3d92dc7 100644 --- a/Chapter_06/lib/recipe_book.dart +++ b/Chapter_06/lib/component/recipe_book.dart @@ -1,15 +1,20 @@ -library recipe_book_controller; +library recipe_book_component; import 'package:angular/angular.dart'; - -import 'tooltip/tooltip.dart'; -import 'service/recipe.dart'; -import 'service/query_service.dart'; - -@Controller( - selector: '[recipe-book]', - publishAs: 'ctrl') -class RecipeBookController { +import 'package:tutorial/tooltip/tooltip.dart' show TooltipModel; +import 'package:tutorial/service/recipe.dart'; +import 'package:tutorial/service/query.dart'; + +/* The selector field defines the CSS selector that will trigger the component. It can be any valid + * CSS selector which does not cross element boundaries. + * + * The component's public fields are available for data binding from the view. + * Similarly, the component's public methods can be invoked from the view. + */ +@Component( + selector: 'recipe-book', + templateUrl: 'recipe_book.html') +class RecipeBookComponent { static const String LOADING_MESSAGE = "Loading recipe book..."; static const String ERROR_MESSAGE = "Sorry! The cook stepped out of the" @@ -23,21 +28,19 @@ class RecipeBookController { bool recipesLoaded = false; bool categoriesLoaded = false; - // Data objects that are loaded from the server side via json - List _categories = []; - List get categories => _categories; - Map _recipeMap = {}; Map get recipeMap => _recipeMap; + List _allRecipes = []; List get allRecipes => _allRecipes; // Filter box final categoryFilterMap = {}; + Iterable get categories => categoryFilterMap.keys; String nameFilter = ""; - RecipeBookController(this._http, this.queryService) { + RecipeBookComponent(this._http, this.queryService) { _loadData(); } @@ -74,8 +77,7 @@ class RecipeBookController { queryService.getAllCategories() .then((List allCategories) { - _categories = allCategories; - for (String category in _categories) { + for (String category in allCategories) { categoryFilterMap[category] = false; } categoriesLoaded = true; @@ -86,4 +88,4 @@ class RecipeBookController { message = ERROR_MESSAGE; }); } -} \ No newline at end of file +} diff --git a/Chapter_06/lib/component/recipe_book.html b/Chapter_06/lib/component/recipe_book.html new file mode 100644 index 0000000..53eca46 --- /dev/null +++ b/Chapter_06/lib/component/recipe_book.html @@ -0,0 +1,32 @@ +
+
+ {{message}} +
+
+

Recipe List

+ + + + +
+ +
+
+
diff --git a/Chapter_06/lib/component/search_recipe_component.dart b/Chapter_06/lib/component/search_recipe.dart similarity index 86% rename from Chapter_06/lib/component/search_recipe_component.dart rename to Chapter_06/lib/component/search_recipe.dart index 9bd98f8..1f2805e 100644 --- a/Chapter_06/lib/component/search_recipe_component.dart +++ b/Chapter_06/lib/component/search_recipe.dart @@ -4,11 +4,11 @@ import 'package:angular/angular.dart'; @Component( selector: 'search-recipe', - templateUrl: 'packages/angular_dart_demo/component/search_recipe_component.html', - publishAs: 'cmp') + templateUrl: 'search_recipe.html') class SearchRecipeComponent { Map _categoryFilterMap; List _categories; + List get categories => _categories; @NgTwoWay('name-filter-string') String nameFilterString = ""; @@ -20,10 +20,8 @@ class SearchRecipeComponent { _categories = categoryFilterMap.keys.toList(); } - List get categories => _categories; - void clearFilters() { _categoryFilterMap.keys.forEach((f) => _categoryFilterMap[f] = false); nameFilterString = ""; } -} \ No newline at end of file +} diff --git a/Chapter_06/lib/component/search_recipe.html b/Chapter_06/lib/component/search_recipe.html new file mode 100644 index 0000000..e362d12 --- /dev/null +++ b/Chapter_06/lib/component/search_recipe.html @@ -0,0 +1,17 @@ +
+
+ + +
+
+ Filter recipes by category: + + + +
+ +
diff --git a/Chapter_06/lib/component/search_recipe_component.html b/Chapter_06/lib/component/search_recipe_component.html deleted file mode 100644 index 52e5549..0000000 --- a/Chapter_06/lib/component/search_recipe_component.html +++ /dev/null @@ -1,18 +0,0 @@ -
-
- - -
-
- Filter recipes by category: - - - -
- -
diff --git a/Chapter_06/lib/component/view_recipe_component.css b/Chapter_06/lib/component/view_recipe.css similarity index 100% rename from Chapter_06/lib/component/view_recipe_component.css rename to Chapter_06/lib/component/view_recipe.css diff --git a/Chapter_06/lib/component/view_recipe_component.dart b/Chapter_06/lib/component/view_recipe.dart similarity index 65% rename from Chapter_06/lib/component/view_recipe_component.dart rename to Chapter_06/lib/component/view_recipe.dart index fe7496d..063b70d 100644 --- a/Chapter_06/lib/component/view_recipe_component.dart +++ b/Chapter_06/lib/component/view_recipe.dart @@ -1,13 +1,12 @@ library view_recipe_component; -import '../service/recipe.dart'; +import 'package:tutorial/service/recipe.dart'; import 'package:angular/angular.dart'; @Component( selector: 'view-recipe', - templateUrl: 'packages/angular_dart_demo/component/view_recipe_component.html', - cssUrl: 'packages/angular_dart_demo/component/view_recipe_component.css', - publishAs: 'cmp') + templateUrl: 'view_recipe.html', + cssUrl: 'view_recipe.css') class ViewRecipeComponent { @NgOneWay('recipe-map') Map recipeMap; diff --git a/Chapter_06/lib/component/view_recipe_component.html b/Chapter_06/lib/component/view_recipe.html similarity index 50% rename from Chapter_06/lib/component/view_recipe_component.html rename to Chapter_06/lib/component/view_recipe.html index 3ccf0a3..cafe46e 100644 --- a/Chapter_06/lib/component/view_recipe_component.html +++ b/Chapter_06/lib/component/view_recipe.html @@ -1,29 +1,29 @@

Recipe Details

-
- +
+ -
Name: {{cmp.recipe.name}}
-
Category: {{cmp.recipe.category}}
+
Name: {{recipe.name}}
+
Category: {{recipe.category}}
Rating: - +
Ingredients:
    -
  • +
  • {{ingredient}}
Directions: - {{cmp.recipe.directions}} + {{recipe.directions}}
-
+

Sorry, we could not find the details of the recipe you requested.

diff --git a/Chapter_06/lib/rating/rating_component.html b/Chapter_06/lib/rating/rating_component.html deleted file mode 100644 index 05e77de..0000000 --- a/Chapter_06/lib/rating/rating_component.html +++ /dev/null @@ -1,6 +0,0 @@ - - {{cmp.starChar(star)}} - diff --git a/Chapter_06/lib/service/query_service.dart b/Chapter_06/lib/service/query.dart similarity index 100% rename from Chapter_06/lib/service/query_service.dart rename to Chapter_06/lib/service/query.dart diff --git a/Chapter_06/lib/service/recipe.dart b/Chapter_06/lib/service/recipe.dart index 9957df6..967bdeb 100644 --- a/Chapter_06/lib/service/recipe.dart +++ b/Chapter_06/lib/service/recipe.dart @@ -6,11 +6,11 @@ class Recipe { String category; List ingredients; String directions; - int rating; String imgUrl; + int rating; - Recipe(this.id, this.name, this.category, this.ingredients, this.directions, - this.rating, this.imgUrl); + Recipe(this.id, this.name, this.category, this.ingredients, this.directions, this.rating, + this.imgUrl); Map toJson() => { "id": id, @@ -22,7 +22,6 @@ class Recipe { "imgUrl": imgUrl }; - Recipe.fromJson(Map json) : this(json['id'], - json['name'], json['category'], json['ingredients'], json['directions'], - json['rating'], json['imgUrl']); + Recipe.fromJson(Map json): this(json['id'], json['name'], json['category'], + json['ingredients'], json['directions'], json['rating'], json['imgUrl']); } diff --git a/Chapter_06/lib/tooltip/tooltip.dart b/Chapter_06/lib/tooltip/tooltip.dart index 755ea01..85e97a4 100644 --- a/Chapter_06/lib/tooltip/tooltip.dart +++ b/Chapter_06/lib/tooltip/tooltip.dart @@ -1,11 +1,9 @@ library tooltip; import 'dart:html' as dom; -import 'dart:math'; import 'package:angular/angular.dart'; -@Decorator( - selector: '[tooltip]') +@Decorator(selector: '[tooltip]') class Tooltip { final dom.Element element; @@ -54,9 +52,8 @@ class Tooltip { ..top = "${elTopRight.y}px" ..left = "${elTopRight.x + 10}px"; - // Add the tooltip to the document body. We add it here because - // we need to position it absolutely, without reference to its - // parent element. + // Add the tooltip to the document body. We add it here because we need to position it + // absolutely, without reference to its parent element. dom.document.body.append(tooltipElem); } @@ -66,9 +63,9 @@ class Tooltip { } class TooltipModel { - String imgUrl; - String text; - int imgWidth; + final String imgUrl; + final String text; + final int imgWidth; TooltipModel(this.imgUrl, this.text, this.imgWidth); } diff --git a/Chapter_06/pubspec.lock b/Chapter_06/pubspec.lock index 3781173..3287676 100644 --- a/Chapter_06/pubspec.lock +++ b/Chapter_06/pubspec.lock @@ -4,11 +4,13 @@ packages: analyzer: description: analyzer source: hosted - version: "0.18.0" + version: "0.15.7" angular: - description: angular - source: hosted - version: "0.13.0" + description: + path: "/home/victor/dart/angular.dart" + relative: false + source: path + version: "1.0.0" args: description: args source: hosted @@ -32,7 +34,7 @@ packages: di: description: di source: hosted - version: "2.0.1" + version: "3.3.1" html5lib: description: html5lib source: hosted @@ -40,7 +42,7 @@ packages: http_server: description: http_server source: hosted - version: "0.9.2" + version: "0.9.3" intl: description: intl source: hosted @@ -64,7 +66,11 @@ packages: mock: description: mock source: hosted - version: "0.10.0+1" + version: "0.11.0+2" + observe: + description: observe + source: hosted + version: "0.10.1+2" path: description: path source: hosted @@ -72,27 +78,31 @@ packages: perf_api: description: perf_api source: hosted - version: "0.0.8" + version: "0.0.9" route_hierarchical: description: route_hierarchical source: hosted - version: "0.4.21" + version: "0.5.0" + smoke: + description: smoke + source: hosted + version: "0.1.0+1" source_maps: description: source_maps source: hosted version: "0.9.0" + source_span: + description: source_span + source: hosted + version: "1.0.0" stack_trace: description: stack_trace source: hosted version: "0.9.3+1" - typed_mock: - description: typed_mock - source: hosted - version: "0.0.4" unittest: description: unittest source: hosted - version: "0.10.1+2" + version: "0.11.0+5" utf: description: utf source: hosted @@ -100,4 +110,4 @@ packages: web_components: description: web_components source: hosted - version: "0.3.5+1" + version: "0.8.0" diff --git a/Chapter_06/pubspec.yaml b/Chapter_06/pubspec.yaml index e52a237..7f0b23e 100644 --- a/Chapter_06/pubspec.yaml +++ b/Chapter_06/pubspec.yaml @@ -1,9 +1,18 @@ -name: angular_dart_demo -version: 0.0.1 +name: tutorial +version: 1.0.0 dependencies: - angular: 0.13.0 - http_server: any + angular: + path: /home/victor/dart/angular.dart + web_components: ">=0.8.0 <0.9.0" + browser: any + http_server: ">=0.9.3 <0.10.0" dev_dependencies: - unittest: any + unittest: ">=0.11.0+5 <0.12.0" + mock: ">=0.11.0+2 <0.12.0" transformers: -- angular +- angular: + html_files: + - lib/component/recipe_book.html + - lib/component/rating.html + - lib/component/search_recipe.html + - lib/component/view_recipe.html diff --git a/Chapter_06/test/main_test.dart b/Chapter_06/test/main_test.dart index e5544d4..7e7f67c 100644 --- a/Chapter_06/test/main_test.dart +++ b/Chapter_06/test/main_test.dart @@ -4,10 +4,10 @@ import 'package:unittest/unittest.dart'; import 'package:di/di.dart'; import 'package:angular/angular.dart'; import 'package:angular/mock/module.dart'; -import 'package:angular_dart_demo/recipe_book.dart'; -import 'package:angular_dart_demo/formatter/category_filter.dart'; -import 'package:angular_dart_demo/rating/rating_component.dart'; -import 'package:angular_dart_demo/service/recipe.dart'; +import 'package:tutorial/component/recipe_book.dart'; +import 'package:tutorial/component/rating.dart'; +import 'package:tutorial/formatter/category_filter.dart'; +import 'package:tutorial/service/recipe.dart'; import '../web/main.dart'; @@ -24,14 +24,14 @@ main() { backend.expectGET('recipes.json').respond('[{"name": "test1"}]'); backend.expectGET('categories.json').respond('["c1"]'); - var recipesController = injector.get(RecipeBookController); - expect(recipesController.allRecipes, isEmpty); + var recipeBook = injector.get(RecipeBookComponent); + expect(recipeBook.allRecipes, isEmpty); microLeap(); backend.flush(); microLeap(); - expect(recipesController.allRecipes, isNot(isEmpty)); + expect(recipeBook.allRecipes, isNot(isEmpty)); }))); test('should select recipe', async(inject((Injector injector, @@ -39,16 +39,16 @@ main() { backend.expectGET('recipes.json').respond('[{"name": "test1"}]'); backend.expectGET('categories.json').respond('["c1"]'); - var recipesController = injector.get(RecipeBookController); - expect(recipesController.allRecipes, isEmpty); + var recipeBook = injector.get(RecipeBookComponent); + expect(recipeBook.allRecipes, isEmpty); microLeap(); backend.flush(); microLeap(); - var recipe = recipesController.allRecipes[0]; - recipesController.selectRecipe(recipe); - expect(recipesController.selectedRecipe, same(recipe)); + var recipe = recipeBook.allRecipes[0]; + recipeBook.selectRecipe(recipe); + expect(recipeBook.selectedRecipe, same(recipe)); }))); }); diff --git a/Chapter_06/web/index.html b/Chapter_06/web/index.html index dbebc21..021bc06 100644 --- a/Chapter_06/web/index.html +++ b/Chapter_06/web/index.html @@ -7,43 +7,8 @@ - -
-
- {{ctrl.message}} -
-
-

Recipe List

- - - - - -
- -
- -
- -
+ + diff --git a/Chapter_06/web/main.dart b/Chapter_06/web/main.dart index 58cb475..52ec092 100644 --- a/Chapter_06/web/main.dart +++ b/Chapter_06/web/main.dart @@ -4,20 +4,18 @@ import 'package:angular/angular.dart'; import 'package:angular/application_factory.dart'; import 'package:logging/logging.dart'; -import 'package:angular_dart_demo/recipe_book.dart'; -import 'package:angular_dart_demo/formatter/category_filter.dart'; -import 'package:angular_dart_demo/rating/rating_component.dart'; -import 'package:angular_dart_demo/tooltip/tooltip.dart'; -import 'package:angular_dart_demo/service/query_service.dart'; -import 'package:angular_dart_demo/routing/recipe_book_router.dart'; -import 'package:angular_dart_demo/component/view_recipe_component.dart'; -import 'package:angular_dart_demo/component/search_recipe_component.dart'; +import 'package:tutorial/component/recipe_book.dart'; +import 'package:tutorial/component/rating.dart'; +import 'package:tutorial/component/search_recipe.dart'; +import 'package:tutorial/component/view_recipe.dart'; +import 'package:tutorial/formatter/category_filter.dart'; +import 'package:tutorial/routing/recipe_book_router.dart'; +import 'package:tutorial/service/query.dart'; +import 'package:tutorial/tooltip/tooltip.dart'; class MyAppModule extends Module { MyAppModule() { - Binding.printInjectWarning = false; // needed for https://github.com/angular/angular.dart/issues/1272 - - bind(RecipeBookController); + bind(RecipeBookComponent); bind(RatingComponent); bind(Tooltip); bind(CategoryFilter); @@ -32,6 +30,7 @@ class MyAppModule extends Module { void main() { Logger.root..level = Level.FINEST ..onRecord.listen((LogRecord r) { print(r.message); }); + applicationFactory() .addModule(new MyAppModule()) .run(); diff --git a/Chapter_06/web/view/viewRecipe.html b/Chapter_06/web/view/viewRecipe.html index 92d7ce5..71cdcc8 100644 --- a/Chapter_06/web/view/viewRecipe.html +++ b/Chapter_06/web/view/viewRecipe.html @@ -1,4 +1,3 @@
- - +