官术网_书友最值得收藏!

Integrating DialogService into our component 

Let's open up track-list.component.ts and inject DialogService for use in our record method. We will also need to determine if the user is logged in to conditionally display a login dialog or confirm prompt, so let's also inject AuthService:

// angular
import { Component, Input } from '@angular/core';

// app
import { ITrack } from '../../../core/models';
import { AuthService, LogService, DialogService } from '../../../core/services';
import { PlayerService } from '../../services/player.service';

@Component({
moduleId: module.id,
selector: 'track-list',
templateUrl: 'track-list.component.html'
})
export class TrackListComponent {

constructor(
private authService: AuthService,
private logService: LogService,
private dialogService: DialogService,
public playerService: PlayerService
) { }

public record(track: ITrack, usernameAttempt?: string) {
if (AuthService.CURRENT_USER) {
this.dialogService.confirm(
'Are you sure you want to re-record this track?'
).then((ok) => {
if (ok) this._navToRecord(track);
});
} else {
this.authService.promptLogin(
'Provide an email and password to record.',
usernameAttempt
).then(
this._navToRecord.bind(this, track),
(usernameAttempt) => {
// initiate sequence again
this.record(track, usernameAttempt);
}
);
}
}

private _navToRecord(track: ITrack) {
// TODO: navigate to record screen
this.logService.debug('yes, re-record', track);
}
}

The record method now first checks to see whether a user is authenticated via the static AuthService.CURRENT_USER reference, which is set when AuthService is first constructed via Angular's dependency injection upon app launch (see Chapter 2, Feature Modules). 

If a user is authenticated, we present a confirmation dialog to ensure the action was intentional.

If the user is not authenticated, we want to prompt the user to log in. To reduce the overload for this book, we will assume the user is already registered via a backend API, so we won't be asking the user to register. 

We need to implement the promptLogin method in AuthService to persist the user's login credentials, so every time they return to the app, it will automatically log them in. The record method now provides an extra optional argument usernameAttempt, which will be useful to repopulate the username field of the login prompt when reinitiating the login sequence after a user input validation error. We won't do a thorough validation of user input here, but we can at least do a lightweight check for a valid email.

In your own app, you should probably do more user input validation.

To maintain a clean separation of concerns, open app/modules/core/services/auth.service.ts to implement promptLogin. Here's the entire service with the modifications:

// angular
import { Injectable } from '@angular/core';

// lib
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

// app
import { DatabaseService } from './database.service';
import { DialogService } from './dialog.service';
import { LogService } from './log.service';

@Injectable()
export class AuthService {

// access our current user from anywhere
public static CURRENT_USER: any;

// subscribe to authenticated state changes
public authenticated$: BehaviorSubject<boolean> =
new BehaviorSubject(false);

constructor(
private databaseService: DatabaseService,
private dialogService: DialogService,
private logService: LogService
) {
this._init();
}

public promptLogin(msg: string, username: string = '')
: Promise<any> {
return new Promise((resolve, reject) => {
this.dialogService.login(msg, username, '')
.then((input) => {
if (input.result) { // result = false when canceled
if (input.userName &&
input.userName.indexOf('@') > -1) {
if (input.password) {
// persist user credentials
this._saveUser(
input.userName, input.password
);
resolve();
} else {
this.dialogService.alert(
'You must provide a password.'
).then(reject.bind(this, input.userName));
}
} else {
// reject, passing userName back
this.dialogService.alert(
'You must provide a valid email address.'
).then(reject.bind(this, input.userName));
}
}
});
});
}

private _saveUser(username: string, password: string) {
AuthService.CURRENT_USER = { username, password };
this.databaseService.setItem(
DatabaseService.KEYS.currentUser,
AuthService.CURRENT_USER
);
this._notifyState(true);
}

private _init() {
AuthService.CURRENT_USER =
this.databaseService
.getItem(DatabaseService.KEYS.currentUser);
this.logService.debug(
`Current user: `, AuthService.CURRENT_USER
);
this._notifyState(!!AuthService.CURRENT_USER);
}

private _notifyState(auth: boolean) {
this.authenticated$.next(auth);
}
}

We use the dialogService.login method to open a native login dialog, allowing the user to input a username and password. Once they choose ok, we do minimal validation of the input and, if successful, proceed to persist the username and password via DatabaseService. Otherwise, we simply alert the user of an error and reject our promise, passing along the username that was entered. This allows us to help the user out by redisplaying the login dialog with the failed username they entered, so they can more easily make corrections.

With these service level details complete, the track-list component is looking pretty good. However, there is one additional step we should take while we are working on this. If you recall, our TrackModel contains an order property that will help the user order the tracks in any way they'd like for convenience. 

主站蜘蛛池模板: 错那县| 乡城县| 加查县| 九龙县| 南安市| 高邑县| 洮南市| 东乡县| 申扎县| 峨边| 凤阳县| 柘城县| 色达县| 安乡县| 顺平县| 安远县| 石泉县| 宜都市| 漯河市| 安庆市| 柏乡县| 大埔县| 临泽县| 乌拉特前旗| 枝江市| 定西市| 武城县| 宁陵县| 平罗县| 大宁县| 牙克石市| 肇庆市| 东阳市| 新源县| 西乡县| 盐津县| 博白县| 天津市| 福海县| 博白县| 手游|