Skip to content
This repository was archived by the owner on Feb 22, 2018. It is now read-only.

Commit a929eb7

Browse files
committed
initial commit. this cl contains routing, creating a normal package/library structure, separating out components and filters to their own files, and stubs out a (currently failing) query service. But the app still works.
1 parent deb9cfc commit a929eb7

21 files changed

+655
-0
lines changed

Chapter_05/add.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<div>
2+
Add recipe
3+
</div>

Chapter_05/categories.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[
2+
"Appetizers",
3+
"Salads",
4+
"Soups",
5+
"Main Dishes",
6+
"Side Dishes",
7+
"Desserts"
8+
]

Chapter_05/category_filter.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
part of recipe_book;
2+
3+
@NgFilter(name: 'categoryfilter')
4+
class CategoryFilter {
5+
call(recipeList, filterMap) {
6+
if (recipeList is List && filterMap != null && filterMap is Map) {
7+
// If there is nothing checked, treat it as "everything is checked"
8+
bool nothingChecked = filterMap.values.every((isChecked) => !isChecked);
9+
if (nothingChecked) {
10+
return recipeList.toList();
11+
}
12+
return recipeList.where((i) => filterMap[i.category] == true).toList();
13+
}
14+
}
15+
}
16+

Chapter_05/edit.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<div ng-bind-route="edit">
2+
Edit recipe
3+
</div>

Chapter_05/index.html

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<!DOCTYPE html>
2+
<html ng-app>
3+
<head>
4+
<title>Chapter Five - A Simple Recipe Book</title>
5+
<link rel="stylesheet" href="style.css">
6+
</head>
7+
<body ng-cloak>
8+
<div recipe-book>
9+
<header id="header">
10+
<h2>Angular is fun! Here's a recipe book to prove it!</h2>
11+
</header>
12+
<nav id="controls">
13+
<recipe-search
14+
name-filter-string="ctrl.nameFilter"
15+
category-filter-map="ctrl.categoryFilterMap">
16+
</recipe-search>
17+
18+
<a href="#/add">add recipe</a><br/>
19+
</nav>
20+
<nav id="results">
21+
<h3>search results</h3>
22+
<div id="recipe-list">
23+
<ul>
24+
<li class="pointer"
25+
ng-repeat="recipe in ctrl.recipes | orderBy:'name' | filter:{name:ctrl.nameFilter} | categoryfilter:ctrl.categoryFilterMap">
26+
<rating max-rating="5" rating="recipe.rating"></rating>
27+
<span class="extra-space"
28+
ng-click="ctrl.selectRecipe(recipe)">{{recipe.name}}</span>
29+
</li>
30+
</ul>
31+
</div>
32+
<a href="#/recipe/1/view">view some recipe</a>
33+
</nav>
34+
<section id="details">
35+
<div ng-if="!ctrl.recipesLoaded && !ctrl.categoriesLoaded">
36+
{{ctrl.message}}
37+
</div>
38+
39+
<ng-view></ng-view>
40+
</section>
41+
</div>
42+
43+
44+
45+
<!--
46+
<div ng-if="ctrl.recipesLoaded && ctrl.categoriesLoaded">
47+
<h3>Recipe List</h3>
48+
49+
50+
</div>
51+
52+
-->
53+
54+
<script type="application/dart" src="main.dart"></script>
55+
<script src="packages/browser/dart.js"></script>
56+
</body>
57+
</html>

Chapter_05/main.dart

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
library recipe_book;
2+
3+
import 'package:angular/angular.dart';
4+
import 'package:angular/routing/module.dart';
5+
import 'dart:convert';
6+
import 'package:perf_api/perf_api.dart';
7+
import 'package:logging/logging.dart';
8+
import 'package:di/di.dart';
9+
10+
part 'category_filter.dart';
11+
part 'query_service.dart';
12+
part 'rating_component.dart';
13+
part 'recipe.dart';
14+
part 'recipe_book_router.dart';
15+
part 'recipe_details_component.dart';
16+
part 'recipe_search_component.dart';
17+
18+
@NgDirective(
19+
selector: '[recipe-book]',
20+
publishAs: 'ctrl')
21+
class RecipeBookController {
22+
23+
static const String LOADING_MESSAGE = "Loading recipe book...";
24+
static const String ERROR_MESSAGE = """Sorry! The cook stepped out of the
25+
kitchen and took the recipe book with him!""";
26+
27+
Http _http;
28+
QueryService _queryService;
29+
QueryService get queryService => _queryService;
30+
31+
// Determine the initial load state of the app
32+
String message = LOADING_MESSAGE;
33+
bool recipesLoaded = false;
34+
bool categoriesLoaded = false;
35+
36+
// Data objects that are loaded from the server side via json
37+
List categories = [];
38+
List<Recipe> recipes = [];
39+
40+
// get rid of this and replace with a recipe service
41+
Map<String, Recipe> recipeMap = {};
42+
43+
List<Recipe> get foofoo => recipeMap.values.toList();
44+
45+
// Filter box
46+
Map<String, bool> categoryFilterMap = {};
47+
String nameFilter = "";
48+
49+
RecipeBookController(Http this._http, QueryService this._queryService) {
50+
_loadData();
51+
}
52+
53+
Recipe selectedRecipe;
54+
55+
void selectRecipe(Recipe recipe) {
56+
selectedRecipe = recipe;
57+
}
58+
59+
void _loadData() {
60+
recipesLoaded = false;
61+
categoriesLoaded = false;
62+
63+
// _queryService.loadData();
64+
// recipesLoaded = _queryService.recipesLoaded;
65+
// categoriesLoaded = _queryService.categoriesLoaded;
66+
//
67+
// if (!recipesLoaded || !categoriesLoaded) {
68+
// message = ERROR_MESSAGE;
69+
// }
70+
71+
_http.get('/angular.dart.tutorial/Chapter_05/recipes.json')
72+
.then((HttpResponse response) {
73+
for (Map recipe in response.data) {
74+
Recipe r = new Recipe.fromJsonMap(recipe);
75+
recipes.add(r);
76+
recipeMap[r.id] = r;
77+
}
78+
recipesLoaded = true;
79+
for (Recipe r in recipeMap.values) {
80+
print(r.name);
81+
}
82+
},
83+
onError: (Object obj) {
84+
recipesLoaded = false;
85+
message = ERROR_MESSAGE;
86+
});
87+
88+
_http.get('/angular.dart.tutorial/Chapter_05/categories.json')
89+
.then((HttpResponse response) {
90+
for (String category in response.data) {
91+
categories.add(category);
92+
categoryFilterMap[category] = false;
93+
}
94+
categoriesLoaded = true;
95+
},
96+
onError: (Object obj) {
97+
categoriesLoaded = false;
98+
message = ERROR_MESSAGE;
99+
});
100+
}
101+
}
102+
103+
// TODO - Remove the Profiler type. It's only needed to get rid of Misko's spam
104+
main() {
105+
// Logger.root.level = Level.FINEST;
106+
// Logger.root.onRecord.listen((LogRecord r) { print(r.message); });
107+
108+
var module = new AngularModule()
109+
..type(RecipeBookController)
110+
..type(RatingComponent)
111+
..type(RecipeSearchComponent)
112+
..type(RecipeDetailsComponent)
113+
..type(CategoryFilter)
114+
..type(QueryService)
115+
..type(RouteInitializer, implementedBy: RecipeBookRouteInitializer)
116+
..factory(NgRoutingUsePushState,
117+
(_) => new NgRoutingUsePushState.value(false))
118+
..type(Profiler, implementedBy: Profiler);
119+
120+
ngBootstrap(module: module);
121+
}

Chapter_05/query_service.dart

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
part of recipe_book;
2+
3+
class QueryService {
4+
String _recipesUrl = '/angular.dart.tutorial/Chapter_05/recipes.json';
5+
String _categoriesUrl = '/angular.dart.tutorial/Chapter_05/categories.json';
6+
7+
Map<String, Recipe> _recipes = {};
8+
List<String> _categories = [];
9+
10+
bool _recipesLoaded = false;
11+
bool _categoriesLoaded = false;
12+
Http _http;
13+
14+
QueryService(Http this._http);
15+
16+
void loadData() {
17+
_recipesLoaded = false;
18+
_categoriesLoaded = false;
19+
20+
_http.get(_recipesUrl)
21+
.then((HttpResponse response) {
22+
for (Map recipe in response.data) {
23+
Recipe r = new Recipe.fromJsonMap(recipe);
24+
_recipes[r.id] = r;
25+
}
26+
_recipesLoaded = true;
27+
},
28+
onError: (Object obj) {
29+
_recipesLoaded = false;
30+
});
31+
32+
_http.get(_categoriesUrl)
33+
.then((HttpResponse response) {
34+
for (String category in response.data) {
35+
_categories.add(category);
36+
}
37+
_categoriesLoaded = true;
38+
},
39+
onError: (Object obj) {
40+
_categoriesLoaded = false;
41+
});
42+
}
43+
44+
Recipe getRecipeById(String id) {
45+
return _recipes[id];
46+
}
47+
48+
List<Recipe> getAllRecipes() {
49+
return _recipes.values.toList();
50+
}
51+
52+
bool get recipesLoaded => _recipesLoaded;
53+
54+
bool get categoriesLoaded => _categoriesLoaded;
55+
56+
}

Chapter_05/rating_component.css

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.star-off {
2+
color: #6E6E6E;
3+
}
4+
.star-on {
5+
color: #FACC2E;
6+
}
7+
.stars {
8+
letter-spacing: -2px;
9+
cursor: pointer;
10+
}

Chapter_05/rating_component.dart

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
part of recipe_book;
2+
3+
/* Use the NgComponent annotation to indicate that this class is an
4+
* Angular Component.
5+
*
6+
* The selector field defines the CSS selector that will trigger the
7+
* component. Typically, the CSS selector is an element name.
8+
*
9+
* The templateUrl field tells the component which HTML template to use
10+
* for its view.
11+
*
12+
* The cssUrl field tells the component which CSS file to use.
13+
*
14+
* The publishAs field specifies that the component instance should be
15+
* assigned to the current scope under the name specified.
16+
*
17+
* The map field publishes the list of attributes that can be set on
18+
* the component. Users of this component will specify these attributes
19+
* in the html tag that is used to create the component. For example:
20+
*
21+
* <rating max-rating="5" rating="mycontrol.rating">
22+
*
23+
* The compnoent's public fields are available for data binding from the
24+
* component's view. Similarly, the component's public methods can be
25+
* invoked from the component's view.
26+
*/
27+
@NgComponent(
28+
selector: 'rating',
29+
templateUrl: 'rating_component.html',
30+
cssUrl: 'rating_component.css',
31+
publishAs: 'ctrl',
32+
map: const {
33+
'max-rating' : '@maxRating',
34+
'rating' : '<=>rating'
35+
}
36+
)
37+
class RatingComponent {
38+
String _starOnChar = "\u2605";
39+
String _starOffChar = "\u2606";
40+
String _starOnClass = "star-on";
41+
String _starOffClass = "star-off";
42+
43+
List<int> stars = [];
44+
45+
int rating;
46+
47+
set maxRating(String value) {
48+
stars = [];
49+
var count = value == null ? 5 : int.parse(value);
50+
for(var i=1; i <= count; i++) {
51+
stars.add(i);
52+
}
53+
}
54+
55+
String starClass(int star) {
56+
return star > rating ? _starOffClass : _starOnClass;
57+
}
58+
59+
String starChar(int star) {
60+
return star > rating ? _starOffChar : _starOnChar;
61+
}
62+
63+
void handleClick(int star) {
64+
if (star == 1 && rating == 1) {
65+
rating = 0;
66+
} else {
67+
rating = star;
68+
}
69+
}
70+
}

Chapter_05/rating_component.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<span class="stars"
2+
ng-if="ctrl.rating != null"
3+
ng-repeat="star in ctrl.stars"
4+
ng-click="ctrl.handleClick(star)"
5+
ng-class="ctrl.starClass(star)">
6+
{{ctrl.starChar(star)}}
7+
</span>

0 commit comments

Comments
 (0)