Skip to content

Commit 9ec757c

Browse files
committed
Adding in some more of the instructions for chapter 3
1 parent 80e3b72 commit 9ec757c

File tree

2 files changed

+385
-42
lines changed

2 files changed

+385
-42
lines changed

index.html

Lines changed: 174 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -542,18 +542,18 @@ <h4 class="exercise-start">
542542
</h4>
543543

544544
<p>Open <code>app/app.component.ts</code>, find the existing sign in button within your component’s <code>template</code> (<code>&lt;Button text=&quot;Sign in&quot;&gt;&lt;/Button&gt;</code>), and replace it with the following code:</p>
545-
<pre><code class="lang-JavaScript">&lt;Button text=&quot;Sign in&quot; id=&quot;submit-button&quot; (tap)=&quot;signIn()&quot;&gt;&lt;/Button&gt;
545+
<pre><code class="lang-JavaScript">&lt;Button text=&quot;Sign in&quot; id=&quot;submit-button&quot; (tap)=&quot;submit()&quot;&gt;&lt;/Button&gt;
546546
</code></pre>
547547
<p>Next, in the same file, replace the current <code>AppComponent</code> declaration with the one shown below:</p>
548548
<pre><code class="lang-JavaScript">export class AppComponent {
549-
signIn() {
549+
submit() {
550550
console.log(&quot;hello&quot;);
551551
}
552552
}
553553
</code></pre>
554554
<div class="exercise-end"></div>
555555

556-
<p>The <code>(eventName)=&quot;functionName()&quot;</code> syntax is part of <a href="https://angular.io/docs/ts/latest/guide/template-syntax.html#!#event-binding">Angular 2’s event binding system</a>, which lets you bind an event that occurs on a UI element to a function in your component’s class. In this case, the <code>(tap)=&quot;signIn()&quot;</code> syntax tells Angular to run the <code>AppComponent</code> class’s <code>signIn()</code> function whenever the user taps the sign in button.</p>
556+
<p>The <code>(eventName)=&quot;functionName()&quot;</code> syntax is part of <a href="https://angular.io/docs/ts/latest/guide/template-syntax.html#!#event-binding">Angular 2’s event binding system</a>, which lets you bind an event that occurs on a UI element to a function in your component’s class. In this case, the <code>(tap)=&quot;submit()&quot;</code> syntax tells Angular to run the <code>AppComponent</code> class’s <code>submit()</code> function whenever the user taps the sign in button.</p>
557557
<p>To verify this binding works tap the “Sign In” button in your app; you should see “hello” logged in your terminal or command prompt as such:</p>
558558
<p><img alt="Terminal showing the word hello logged" src="images/chapter3/terminal-1.png" class="plain"></p>
559559
<blockquote>
@@ -571,10 +571,10 @@ <h4 class="exercise-start">
571571
<b>Exercise</b>: Using Angular 2 attribute binding
572572
</h4>
573573

574-
<p>In <code>app/app.component.ts</code> replace the current <code>AppComponent</code> declaration with the one shown below, which adds a new <code>email</code> property, and changes the <code>signIn()</code> method to display its value:</p>
574+
<p>In <code>app/app.component.ts</code> replace the current <code>AppComponent</code> declaration with the one shown below, which adds a new <code>email</code> property, and changes the <code>submit()</code> method to display its value:</p>
575575
<pre><code class="lang-TypeScript">export class AppComponent {
576576
email = &quot;nativescriptrocks@telerik.com&quot;;
577-
signIn() {
577+
submit() {
578578
alert(&quot;You’re using: &quot; + this.email);
579579
}
580580
}
@@ -592,7 +592,7 @@ <h4 class="exercise-start">
592592
<p><strong>NOTE</strong>: It’s very easy to confuse Angular 2’s event binding syntax <code>(eventName)=&quot;functionName()&quot;</code> with its attribute binding syntax <code>[attributeName]=&quot;propertyName&quot;</code> 🤔. Don’t worry though; if you get them backwards, the problem is usually easy to debug, as the functionality you’re attempting to add just won’t work. These syntaxes are common enough that you’ll be using them a lot, and eventually you should be able to commit them to memory.</p>
593593
</blockquote>
594594
<p>This attribute binding approach works really well when you need the data binding to be one way—that is, when you need TypeScript properties, and changes to those properties done in TypeScript code, to appear in the user interface. But in the case of user interface controls that accept user input, such as the text field in this example, usually you need data binding to work two way—that is, you additionally need changes the user makes to be reflected in your TypeScript code.</p>
595-
<p>To show that the current example’s data binding is only one way, head back to your app, change the email text field’s value (type a few extra letters or something like that), and then tap the “Sign In” button. Because your <code>signIn()</code> function alerts the current value of your component’s <code>email</code> property—<code>alert(&quot;You’re using: &quot; + this.email)</code>—you might expect to see the updated value in the alert. Instead, however, you see the original value. Notice how the typed text and the alert value don’t match in the screenshot below.</p>
595+
<p>To show that the current example’s data binding is only one way, head back to your app, change the email text field’s value (type a few extra letters or something like that), and then tap the “Sign In” button. Because your <code>submit()</code> function alerts the current value of your component’s <code>email</code> property—<code>alert(&quot;You’re using: &quot; + this.email)</code>—you might expect to see the updated value in the alert. Instead, however, you see the original value. Notice how the typed text and the alert value don’t match in the screenshot below.</p>
596596
<p><img src="images/chapter3/android/2.png" alt="Android with email address that do not match"></p>
597597
<p>To fix this, you need to switch to Angular 2’s two-way data binding syntax.</p>
598598
<h4 class="exercise-start">
@@ -609,6 +609,31 @@ <h4 class="exercise-start">
609609
<p>Don’t worry too much about the details here while we’re still getting started. In your head you can think of <code>[(ngModel)]</code> as the way to implement two-way data binding when you need it on form controls. And to show that it works, if you again modify your app’s email address and click the “Sign In” button, you’ll see the updated value in the alert as expected:</p>
610610
<p><img src="images/chapter3/android/3.png" alt="Android with email addresses that do match"></p>
611611
<p>At this point, you have a basic login screen setup with two-way data binding—not bad for 20 some lines of code of TypeScript. (Think about how much code you’d have to write in Android Studio <em>and</em> Xcode to accomplish the same task.) To this point though you’ve been placing all of your logic in a single TypeScript file, which doesn’t scale all that well for real-world applications.</p>
612+
<p>TODO: Transition</p>
613+
<h4 class="exercise-start">
614+
<b>Exercise</b>: ???
615+
</h4>
616+
617+
<p>app.component.ts — Replace the two buttons with this</p>
618+
<pre><code class="lang-XML">&lt;Button [text]=&quot;isLoggingIn ? &#39;Sign in&#39; : &#39;Sign up&#39;&quot; id=&quot;submit-button&quot; (tap)=&quot;submit()&quot;&gt;&lt;/Button&gt;
619+
&lt;Button [text]=&quot;isLoggingIn ? &#39;Sign up&#39; : &#39;Back to login&#39;&quot; (tap)=&quot;toggleDisplay()&quot;&gt;&lt;/Button&gt;
620+
</code></pre>
621+
<p>app.component.ts - Use this for the AppComponent class:</p>
622+
<pre><code class="lang-TypeScript">export class AppComponent {
623+
email = &quot;nativescriptrocks@telerik.com&quot;;
624+
isLoggingIn = true;
625+
626+
submit() {
627+
alert(&quot;You’re using: &quot; + this.email);
628+
}
629+
toggleDisplay() {
630+
this.isLoggingIn = !this.isLoggingIn;
631+
}
632+
}
633+
</code></pre>
634+
<div class="exercise-end"></div>
635+
636+
<p>TODO: Transition</p>
612637
<p>Before we tie this app to a backend and make this login screen fully functional, let’s take a step back and setup a structure that can scale.</p>
613638
<h3 id="structuring-your-app">Structuring your app</h3>
614639
<p>There are many reasons to segment any application into modular units, and you can <a href="https://en.wikipedia.org/wiki/Modular_programming">read about the various benefits on Wikipedia</a>. However, keeping NativeScript apps modular has one unique benefit: the ability to share the code you write between Angular-2-built web apps, and Angular-2-built native apps.</p>
@@ -632,12 +657,17 @@ <h4 class="exercise-start">
632657
<p>Next, replace the existing <code>AppComponent</code> definition with the one below, which uses the <code>User</code> class you just imported.</p>
633658
<pre><code class="lang-JavaScript">export class AppComponent {
634659
user: User;
660+
isLoggingIn = true;
661+
635662
constructor() {
636663
this.user = new User();
637664
}
638-
signIn() {
665+
submit() {
639666
alert(&quot;You’re using: &quot; + this.user.email);
640667
}
668+
toggleDisplay() {
669+
this.isLoggingIn = !this.isLoggingIn;
670+
}
641671
}
642672
</code></pre>
643673
<p>Instead of storing data on the <code>AppComponent</code> directly, you’re now using the <code>User</code> model object, which is reusable outside of this page and even outside of this application. You instantiate an instance of the <code>User</code> class in a new <code>constructor</code> function, which Angular 2 invokes when it bootstraps your application.</p>
@@ -646,33 +676,29 @@ <h4 class="exercise-start">
646676
autocorrect=&quot;false&quot; autocapitalizationType=&quot;none&quot;&gt;&lt;/TextField&gt;
647677
&lt;TextField hint=&quot;Password&quot; secure=&quot;true&quot; [(ngModel)]=&quot;user.password&quot;&gt;&lt;/TextField&gt;
648678
</code></pre>
679+
<p>TODO: Better explanation. Move the full template into the login.html file and use <code>templateUrl</code>. </p>
649680
<p>If you got lost during this section, here’s a copy-and-paste friendly version of the full <code>app.component.ts</code> you should have at this point:</p>
650681
<pre><code class="lang-JavaScript">import {Component} from &quot;angular2/core&quot;;
651682
import {User} from &quot;./shared/user/user&quot;;
652683

653684
@Component({
654685
selector: &quot;my-app&quot;,
655-
template: `
656-
&lt;StackLayout&gt;
657-
&lt;Image src=&quot;res://logo&quot; stretch=&quot;none&quot; horizontalAlignment=&quot;center&quot;&gt;&lt;/Image&gt;
658-
659-
&lt;TextField hint=&quot;Email Address&quot; keyboardType=&quot;email&quot; [(ngModel)]=&quot;user.email&quot;
660-
autocorrect=&quot;false&quot; autocapitalizationType=&quot;none&quot;&gt;&lt;/TextField&gt;
661-
&lt;TextField hint=&quot;Password&quot; secure=&quot;true&quot; [(ngModel)]=&quot;user.password&quot;&gt;&lt;/TextField&gt;
662-
663-
&lt;Button text=&quot;Sign in&quot; (tap)=&quot;signIn()&quot;&gt;&lt;/Button&gt;
664-
&lt;Button text=&quot;Sign up for Groceries&quot; class=&quot;link&quot;&gt;&lt;/Button&gt;
665-
&lt;/StackLayout&gt;
666-
`
686+
templateUrl: &quot;pages/login/login.html&quot;,
687+
styleUrls: [&quot;pages/login/login-common.css&quot;, &quot;pages/login/login.css&quot;]
667688
})
668689
export class AppComponent {
669690
user: User;
691+
isLoggingIn = true;
692+
670693
constructor() {
671694
this.user = new User();
672695
}
673-
signIn() {
696+
submit() {
674697
alert(&quot;You’re using: &quot; + this.user.email);
675698
}
699+
toggleDisplay() {
700+
this.isLoggingIn = !this.isLoggingIn;
701+
}
676702
}
677703
</code></pre>
678704
<div class="exercise-end"></div>
@@ -689,10 +715,137 @@ <h4 class="exercise-start">
689715
</h4>
690716

691717
<p>Open <code>app/shared/user/user.service.ts</code> and paste in the following code:</p>
692-
<pre><code class="lang-JavaScript">
718+
<pre><code class="lang-TypeScript">import {Injectable} from &quot;angular2/core&quot;;
719+
import {Http, Headers, Response} from &quot;angular2/http&quot;;
720+
import {User} from &quot;./user&quot;;
721+
import {Config} from &quot;../config&quot;;
722+
import {Observable} from &quot;rxjs/Rx&quot;;
723+
import &quot;rxjs/add/operator/do&quot;;
724+
import &quot;rxjs/add/operator/map&quot;;
725+
726+
@Injectable()
727+
export class UserService {
728+
constructor(private _http: Http) {}
729+
730+
register(user: User) {
731+
var headers = new Headers();
732+
headers.append(&quot;Content-Type&quot;, &quot;application/json&quot;);
733+
734+
return this._http.post(
735+
Config.apiUrl + &quot;Users&quot;,
736+
JSON.stringify({
737+
Username: user.email,
738+
Email: user.email,
739+
Password: user.password
740+
}),
741+
{ headers: headers }
742+
)
743+
.catch(this.handleErrors);
744+
}
745+
746+
handleErrors(error: Response) {
747+
console.log(JSON.stringify(error.json()));
748+
return Observable.throw(error);
749+
}
750+
}
751+
</code></pre>
752+
<p>TODO: Explain that mess above, and probably break it into a lot of steps.</p>
753+
<p>In app.component.ts. Add the line below to the top:</p>
754+
<pre><code class="lang-TypeScript">import {UserService} from &quot;./shared/user/user.service&quot;;
755+
</code></pre>
756+
<p>Then change the constructor to this:</p>
757+
<pre><code class="lang-TypeScript">constructor(private _userService: UserService) {
758+
this.user = new User();
759+
}
760+
</code></pre>
761+
<p>Add this line to the @Component:</p>
762+
<pre><code class="lang-TypeScript">providers: [UserService],
763+
</code></pre>
764+
<p>Then change the submit function to this:</p>
765+
<pre><code class="lang-TypeScript">submit() {
766+
if (this.isLoggingIn) {
767+
this.login();
768+
} else {
769+
this.signUp();
770+
}
771+
}
772+
</code></pre>
773+
<p>Then add these two functions:</p>
774+
<pre><code class="lang-TypeScript">login() {
775+
// TODO: Define
776+
}
777+
signUp() {
778+
this._userService.register(this.user)
779+
.subscribe(
780+
() =&gt; {
781+
alert(&quot;Your account was successfully created.&quot;)
782+
this.toggleDisplay();
783+
},
784+
() =&gt; alert(&quot;Unfortunately we were unable to create your account.&quot;)
785+
);
786+
}
787+
</code></pre>
788+
<p>Create an account, then hardcode those credentials in your constructor to make testing easier:</p>
789+
<pre><code class="lang-TypeScript">constructor(private _userService: UserService) {
790+
this.user = new User();
791+
this.user.email = &quot;nativescriptrocks@telerik.com&quot;;
792+
this.user.password = &quot;password&quot;;
793+
}
794+
</code></pre>
795+
<p>Full app.component.ts:</p>
796+
<pre><code class="lang-TypeScript">import {Component} from &quot;angular2/core&quot;;
797+
import {User} from &quot;./shared/user/user&quot;;
798+
import {UserService} from &quot;./shared/user/user.service&quot;;
799+
800+
@Component({
801+
selector: &quot;my-app&quot;,
802+
templateUrl: &quot;pages/login/login.html&quot;,
803+
styleUrls: [&quot;pages/login/login-common.css&quot;, &quot;pages/login/login.css&quot;],
804+
providers: [UserService]
805+
})
806+
export class AppComponent {
807+
user: User;
808+
isLoggingIn = true;
809+
810+
constructor(private _userService: UserService) {
811+
this.user = new User();
812+
}
813+
submit() {
814+
if (this.isLoggingIn) {
815+
this.login();
816+
} else {
817+
this.signUp();
818+
}
819+
}
820+
login() {
821+
// TODO: Define
822+
}
823+
signUp() {
824+
this._userService.register(this.user)
825+
.subscribe(
826+
() =&gt; {
827+
alert(&quot;Your account was successfully created.&quot;)
828+
this.toggleDisplay();
829+
},
830+
() =&gt; alert(&quot;Unfortunately we were unable to create your account.&quot;)
831+
);
832+
}
833+
toggleDisplay() {
834+
this.isLoggingIn = !this.isLoggingIn;
835+
}
836+
}
837+
</code></pre>
838+
<p>Also change main.ts to use this:</p>
839+
<pre><code class="lang-TypeScript">import {HTTP_PROVIDERS} from &quot;angular2/http&quot;;
840+
import {nativeScriptBootstrap} from &quot;nativescript-angular/application&quot;;
841+
import {AppComponent} from &quot;./app.component&quot;;
842+
843+
nativeScriptBootstrap(AppComponent, [HTTP_PROVIDERS]);
693844
</code></pre>
694845
<div class="exercise-end"></div>
695846

847+
848+
696849
<h3 id="routing">Routing</h3>
697850

698851
</div>

0 commit comments

Comments
 (0)