You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: index.html
+32-16
Original file line number
Diff line number
Diff line change
@@ -924,7 +924,6 @@ <h4 class="exercise-start">
924
924
</code></pre>
925
925
<p>Now that <code>app.component.ts</code> is empty, let’s add in the appropriate Angular 2 routing code. Open app/app.component.ts back up and paste in the following code:</p>
926
926
<pre><codeclass="lang-TypeScript">import {Component} from "angular2/core";
927
-
import {HTTP_PROVIDERS} from "angular2/http";
928
927
import {RouteConfig} from "angular2/router";
929
928
import {NS_ROUTER_DIRECTIVES, NS_ROUTER_PROVIDERS} from "nativescript-angular/router";
930
929
import {LoginPage} from "./pages/login/login.component";
<p>We’ll talk about the new syntax in a moment, but first let’s define the class names used in the previous example. Open <code>app/app.css</code> and paste the following code at the bottom of the file, which defines a few utility class names you can use throughout your app:</p>
<p>The <ahref="http://docs.nativescript.org/ApiReference/ui/list-view/ListView"><code><ListView></code> UI element</a> requires an <code>items</code> property that points at an array of data—in this case, the <code>groceryList</code> array you added to your <code>ListPage</code> class. The list view element requires a child <code><template></code> element that specifies how to render each item in the <code>items</code> array.</p>
1182
+
<p>The <code>#item</code> syntax is Angular 2’s for syntax for <ahref="https://angular.io/docs/ts/latest/guide/template-syntax.html#!#star-template">creating local template variables</a>. This gives you the ability to refer to each item in the array as <code>item</code> within the template. For this template, you render each item in the array with a single <code><Label></code> UI element, and because of the <code>[text]="item.name"</code> binding, those labels contain the text from the <code>name</code> property of each of the items in <code>groceryList</code> TypeScript array.</p>
1183
+
<p>Now that you have a hardcoded list displaying, let’s see how to swap that out with live data.</p>
1180
1184
<h4class="exercise-start">
1181
-
<b>Exercise</b>: ???
1185
+
<b>Exercise</b>: Populate the list view
1182
1186
</h4>
1183
1187
1184
1188
<p>Open <code>app/shared/grocery/grocery.ts</code> and paste in the following code:</p>
1185
1189
<pre><codeclass="lang-TypeScript">export class Grocery {
1186
1190
constructor(public id: string, public name: string) {}
1187
1191
}
1188
1192
</code></pre>
1189
-
<p>Open <code>app/shared/grocery/grocery-list.service.ts</code> and paste in the following code:</p>
1193
+
<p>This creates a simple <code>Grocery</code> model object that you can use throughout your app. Next, let’s create a simple service that reads grocery lists from our backend. Open <code>app/shared/grocery/grocery-list.service.ts</code> and paste in the following code:</p>
1190
1194
<pre><codeclass="lang-TypeScript">import {Injectable} from "angular2/core";
1191
1195
import {Http, Headers} from "angular2/http";
1192
1196
import {Config} from "../config";
@@ -1222,7 +1226,8 @@ <h4 class="exercise-start">
1222
1226
}
1223
1227
}
1224
1228
</code></pre>
1225
-
<p>Open <code>app/pages/list/list.component.ts</code> and add the following two lines to the top of the file:</p>
1229
+
<p>The code here is very similar to the code you used in the <code>UserService</code> earlier in this guide. You use the <code>Http</code> service’s <code>get()</code> method to load JSON data, and RxJS’s <code>map()</code> function to format the data into an array of <code>Grocery</code> objects.</p>
1230
+
<p>To use this service, open <code>app/pages/list/list.component.ts</code> and add the following two lines to the top of the file:</p>
1226
1231
<pre><codeclass="lang-TypeScript">import {Grocery} from "../../shared/grocery/grocery";
1227
1232
import {GroceryListService} from "../../shared/grocery/grocery-list.service";
<p>Because we’re injecting a service we must also add it as a provider within our component decorator:</p>
1240
+
<p>Next, because you’re injecting a service into your constructor you must also include it as a provider within your component decorator. To do so, replace the existing <code>@Component</code> decorator with the code below:</p>
<p>Finally, replace the existing <code>ngOnInit()</code> function with the code below:</p>
1248
+
<p>Finally, to kick off the call to <code>load()</code> when this page initializes, replace the existing <code>ngOnInit()</code> function with the code below:</p>
1244
1249
<pre><codeclass="lang-TypeScript">ngOnInit() {
1245
1250
this._groceryListService.load()
1246
1251
.subscribe(loadedGroceries => {
@@ -1252,7 +1257,6 @@ <h4 class="exercise-start">
1252
1257
</code></pre>
1253
1258
<p>The full version of your <code>app/pages/list/list.component.ts</code> file should now look like this:</p>
1254
1259
<pre><codeclass="lang-TypeScript">import {Component, OnInit} from "angular2/core";
1255
-
1256
1260
import {Grocery} from "../../shared/grocery/grocery";
1257
1261
import {GroceryListService} from "../../shared/grocery/grocery-list.service";
<p>Talk about the code you just added. But then note that if you try the code, you’ll get an exception about no provider for Http. Talk about best practices of where to declare shared providers. Let’s fix the problem now.</p>
1286
+
<p>Once you run this code you may expect to see a list of groceries, but instead you’ll see this error in your terminal:</p>
1287
+
<pre><code>JS: EXCEPTION: No provider for Http! (ListPage -> GroceryListService -> Http)
1288
+
JS: STACKTRACE:
1289
+
JS: Error: DI Exception
1290
+
JS: at NoProviderError.BaseException [as constructor] (/data/data/org.nativescript.groceries/files/app/tns_modules/angular2/src/facade/exceptions.js:16:23)
1291
+
JS: at NoProviderError.AbstractProviderError [as constructor] (/data/data/org.nativescript.groceries/files/app/tns_modules/angular2/src/core/di/exceptions.js:38:16)
1292
+
</code></pre><p>The problem here is your new <code>GroceryListService</code> uses the <code>Http</code> service, but that <code>Http</code> service is never included in your component’s <code>providers</code> array. You could add <code>HTTP_PROVIDERS</code> to this array, as you did in <code>login.component.ts</code>, but it seems a little silly to add <code>HTTP_PROVIDERS</code> to every page that you build. And as it turns out, Angular 2 providers a simpler way of handling this, by allowing you to add common providers to parent components.</p>
1283
1293
<h4class="exercise-start">
1284
-
<b>Exercise</b>: ???
1294
+
<b>Exercise</b>: Declaring providers
1285
1295
</h4>
1286
1296
1287
1297
<p>Open <code>app/pages/login/login.component.ts</code> and <em>remove</em> the following line from the top of the file:</p>
1298
+
<divclass="no-copy-button"></div>
1299
+
1288
1300
<pre><codeclass="lang-TypeScript">import {HTTP_PROVIDERS} from "angular2/http";
1289
1301
</code></pre>
1290
1302
<p>Next, in the same file, remove <code>HTTP_PROVIDERS</code> from the component decorator’s <code>providers</code> array. The array should now look this like:</p>
<p>Show an image of the list with backend-driven data. Talk about how the next step is letting users add to the list.</p>
1313
+
<p>Generally, it’s only a good idea to declare providers in parent components if all of the component’s children actually use that provider. Although you <em>could</em> declare all your providers in <code>AppComponent</code>, your <code>providers</code> would become unwieldy as your app grows, and difficult to refactor as your app changes.</p>
1314
+
<p>If you load the list page with the account you created earlier you’ll see a blank page, as your account is newly created, and therefore your grocery list is empty. If you want to see some data to verify your changes worked, try logging in with the credentials “[email protected]” and “password”. You should some data that looks something like this:</p>
1315
+
<p><imgsrc="images/chapter4/android/4.png" alt="Grocery data on Android">
1316
+
<imgsrc="images/chapter4/ios/4.png" alt="Grocery data on iOS"></p>
1317
+
<p>At this point you have a list of data associated with each account that you display in a list view control, but a grocery list isn’t very useful if you can’t add to the list. Let’s look at how to do that next.</p>
1302
1318
<h3id="gridlayout">GridLayout</h3>
1303
1319
<p>Introduce what a grid layout actually is. Should be able to copy from the existing guide liberally.</p>
We’lltalkaboutthenewsyntaxinamoment, butfirstlet’sdefinetheclassnamesusedinthepreviousexample. Open `app/app.css` andpastethefollowingcodeatthebottomofthefile, whichdefinesafewutilityclassnamesyoucanusethroughoutyourapp:
@@ -205,10 +207,14 @@ How does this work? Let’s return to this chunk of code:
205
207
</ListView>
206
208
```
207
209
210
+
The [`<ListView>` UI element](http://docs.nativescript.org/ApiReference/ui/list-view/ListView) requires an `items` property that points at an array of data—in this case, the `groceryList` array you added to your `ListPage` class. The list view element requires a child `<template>` element that specifies how to render each item in the `items` array.
211
+
212
+
The `#item` syntax is Angular 2’s for syntax for [creating local template variables](https://angular.io/docs/ts/latest/guide/template-syntax.html#!#star-template). This gives you the ability to refer to each item in the array as `item` within the template. For this template, you render each item in the array with a single `<Label>` UI element, and because of the `[text]="item.name"` binding, those labels contain the text from the `name` property of each of the items in `groceryList` TypeScript array.
208
213
214
+
Now that you have a hardcoded list displaying, let’s see how to swap that out with live data.
209
215
210
216
<h4 class="exercise-start">
211
-
<b>Exercise</b>: ???
217
+
<b>Exercise</b>: Populate the list view
212
218
</h4>
213
219
214
220
Open `app/shared/grocery/grocery.ts` and paste in the following code:
@@ -219,7 +225,7 @@ export class Grocery {
219
225
}
220
226
```
221
227
222
-
Open `app/shared/grocery/grocery-list.service.ts` and paste in the following code:
228
+
This creates a simple `Grocery` model object that you can use throughout your app. Next, let’s create a simple service that reads grocery lists from our backend. Open `app/shared/grocery/grocery-list.service.ts` and paste in the following code:
223
229
224
230
``` TypeScript
225
231
import {Injectable} from"angular2/core";
@@ -258,7 +264,9 @@ export class GroceryListService {
258
264
}
259
265
```
260
266
261
-
Open `app/pages/list/list.component.ts` and add the following two lines to the top of the file:
267
+
The code here is very similar to the code you used in the `UserService` earlier in this guide. You use the `Http` service’s `get()` method to load JSON data, andRxJS’s`map()`function to format the data into an array of `Grocery` objects.
268
+
269
+
To use this service, open `app/pages/list/list.component.ts` and add the following two lines to the top of the file:
Next, becauseyou’reinjectingaserviceintoyourconstructor you must also include it as a provider within your component decorator. To do so, replacetheexisting`@Component`decoratorwiththecode below:
281
289
282
290
``` TypeScript
283
291
@Component({
@@ -288,7 +296,7 @@ Because we’re injecting a service we must also add it as a provider within our
288
296
})
289
297
```
290
298
291
-
Finally, replacetheexisting`ngOnInit()`function with the code below:
299
+
Finally, tokickoffthecallto`load()`whenthispage initializes, replacetheexisting`ngOnInit()`function with the code below:
292
300
293
301
``` TypeScript
294
302
ngOnInit() {
@@ -305,7 +313,6 @@ The full version of your `app/pages/list/list.component.ts` file should now look
@@ -333,22 +340,34 @@ export class ListPage implements OnInit {
333
340
334
341
<div class="exercise-end"></div>
335
342
336
-
Talk about the code you just added. But then note that if you try the code, you’ll get an exception about no provider for Http. Talk about best practices of where to declare shared providers. Let’s fix the problem now.
343
+
Once you run this code you may expect to see a list of groceries, but instead you’ll see this error in your terminal:
The problem here is your new `GroceryListService` uses the `Http` service, but that `Http` service is never included in your component’s `providers` array. You could add `HTTP_PROVIDERS` to this array, as you did in `login.component.ts`, but it seems a little silly to add `HTTP_PROVIDERS` to every page that you build. And as it turns out, Angular 2 providers a simpler way of handling this, by allowing you to add common providers to parent components.
337
354
338
355
<h4 class="exercise-start">
339
-
<b>Exercise</b>: ???
356
+
<b>Exercise</b>: Declaring providers
340
357
</h4>
341
358
342
359
Open `app/pages/login/login.component.ts` and _remove_ the following line from the top of the file:
343
360
361
+
<div class="no-copy-button"></div>
362
+
344
363
``` TypeScript
345
364
import {HTTP_PROVIDERS} from"angular2/http";
346
365
```
347
366
348
367
Next, in the same file, remove `HTTP_PROVIDERS` from the component decorator’s `providers` array. The array should now look this like:
349
368
350
369
``` TypeScript
351
-
providers: [UserService]
370
+
providers: [UserService],
352
371
```
353
372
354
373
After that, open `app/app.component.ts` and _add_ the following import to the top of the file:
Show an image of the list with backend-driven data. Talk about how the next step is letting users add to the list.
387
+
Generally, it’s only a good idea to declare providers in parent components if all of the component’s children actually use that provider. Although you _could_ declare all your providers in `AppComponent`, your `providers` would become unwieldy as your app grows, and difficult to refactor as your app changes.
388
+
389
+
If you load the list page with the account you created earlier you’ll see a blank page, as your account is newly created, and therefore your grocery list is empty. If you want to see some data to verify your changes worked, try logging in with the credentials “[email protected]” and “password”. You should some data that looks something like this:
390
+
391
+

392
+

393
+
394
+
At this point you have a list of data associated with each account that you display in a list view control, but a grocery list isn’t very useful if you can’t add to the list. Let’s look at how to do that next.
0 commit comments