假设我们有一个服务,它会对API进行http调用以创建用户。根据结果(200或错误),应用程序应重定向或显示错误(客户端有一些验证,但这不是主题,因为验证应始终在服务器端进行)。
Angular 2文档声明,让服务返回一个observable并在组件中订阅它是不好的做法。该服务应该是自包含的,组件不应该对此有任何了解。拨打userService.createUser(user_data);
但是再次路由应该在组件中发生。所以我想知道如何处理这种情况?我的服务应该返回一个新的Observable吗?或者只是一个价值?但那我该如何处理异步任务呢?
这样做的正确方法是什么?
让我们以此服务创建用户和此组件为例:
// user.service.ts:
import { Http, Headers } from '@angular/http';
import { Inject, Injectable } from '@angular/core';
import { API_CONFIG, Config } from '../config/api.config';
import { User } from '../models/user.model';
@Injectable()
export class UserService {
validation_errors: Array<any> = [];
constructor(
@Inject(API_CONFIG) private api_config: Config,
private http: Http,
@Inject(User) public user: User
) {}
createUser(user: User) {
var body = JSON.stringify({ user });
var myHeader = new Headers();
myHeader.append('Content-Type', 'application/json');
this.http.post(this.api_config.apiEndpoint + '/users/', body, { headers: myHeader })
.map(res => res.json())
.subscribe(
res => {
// User was created successfully
this.user = this.fromJson(res.data);
},
err => {
// Something went wrong, let's collect all errors in a class attribute
let errors = err.json().errors;
for(var i = 0; i < errors.length; i++) {
this.validation_errors.push(errors[i])
}
}
);
}
/**
* @param input_json JSON returned from API, formatted according to jsonapi.org, containing one single user.
* @return UserModel instantiated with the values from input_json
*/
fromJson(input_json: any) {
var user:User = new User();
user = input_json.attributes;
user.id = input_json.id;
return user;
}
}
// user.component.ts:
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, REACTIVE_FORM_DIRECTIVES, Validators } from '@angular/forms';
import { Router, RouteParams, ROUTER_DIRECTIVES } from '@angular/router-deprecated';
import { UserService } from '../../shared/index';
@Component({
selector: 'fac-user-editor',
templateUrl: 'app/+users/editor/user-editor.component.html',
styleUrls: ['app/+users/editor/user-editor.component.css'],
directives: [REACTIVE_FORM_DIRECTIVES, ROUTER_DIRECTIVES],
providers: [UserService]
})
export class UserEditorComponent implements OnInit {
// Setup Form
private email_regex = '[a-z0-9\\.\\-\\_]+@[a-z0-9\\.\\-\\_]+\\.[a-z0-9\\.\\-\\_]+';
userForm: FormGroup;
action: string;
idCtrl = new FormControl('');
nameCtrl = new FormControl('', [Validators.required]);
emailCtrl = new FormControl('', [Validators.required, Validators.pattern(this.email_regex)]);
usernameCtrl = new FormControl('', [Validators.required, Validators.minLength(5)]);
passwordCtrl = new FormControl('', [Validators.minLength(8)]);
passwordConfirmationCtrl = new FormControl('');
public user_id: string;
constructor(private userService: UserService, private router: Router, private params: RouteParams) {}
/**
* Handle submit of form
*/
onSubmit(form: any) {
// Here should happen some error handling / routing, depending on the result of the call to the API
this.userService.createUser(this.userService.user);
}
ngOnInit(): any {
this.userForm = new FormGroup({
id: this.idCtrl,
name: this.nameCtrl,
email: this.emailCtrl,
username: this.usernameCtrl,
password: this.passwordCtrl,
password_confirmation: this.passwordConfirmationCtrl
});
}
}
我可以在模板中显示错误消息,如下所示:
<div class="form-group"
[hidden]="adminService.validation_errors.length === 0"
class="alert alert-warning" role="alert">
<strong>Some errors occured</strong>
<ul>
<li *ngFor="let validation_error of adminService.validation_errors">
<span class="text-capitalize">{{validation_error.source.field}}:</span> {{validation_error.detail}}
</li>
</ul>
</div>
答案 0 :(得分:1)
这就是我解决问题的方法。我的服务现在使用.map()来转换从后端返回的数据(JSON)并返回一个Observable,它将初始化我的用户模型。 Component可以订阅observable。数据存储在组件的变量中,以及验证错误。
我还使用FormBuilder来构建新的Form API。这应该适用于RC 3。
我希望这有助于某人。
// user.service.ts:
import { Http, Headers } from '@angular/http';
import { Inject, Injectable } from '@angular/core';
import { API_CONFIG, Config } from '../config/api.config';
import { User } from '../models/user.model';
@Injectable()
export class UserService {
constructor(
@Inject(API_CONFIG) private api_config: Config,
private http: Http,
@Inject(User) public user: User
) {}
createUser(user: User) {
var body = JSON.stringify({ user });
var myHeader = new Headers();
myHeader.append('Content-Type', 'application/json');
// Use map to transform reply from server (JSON to User Object) and return an Observable
// The component can subscribe to.
return this.http.post(this.api_config.apiEndpoint + '/users/', body, { headers: myHeader })
.map(res => res.json())
.map(res => {
return this.fromJson(res.data);
});
}
/**
* @param input_json JSON returned from API, formatted according to jsonapi.org, containing one single user.
* @return UserModel instantiated with the values from input_json
*/
fromJson(input_json: any) {
var user:User = new User();
user = input_json.attributes;
user.id = input_json.id;
return user;
}
}
// user.component.ts:
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, FormBuilder, REACTIVE_FORM_DIRECTIVES, Validators } from '@angular/forms';
import { Router, RouteParams, ROUTER_DIRECTIVES } from '@angular/router-deprecated';
// Include the User Model
import { User, UserService } from '../../shared/index';
@Component({
selector: 'fac-user-editor',
templateUrl: 'app/+users/editor/user-editor.component.html',
styleUrls: ['app/+users/editor/user-editor.component.css'],
directives: [REACTIVE_FORM_DIRECTIVES, ROUTER_DIRECTIVES],
providers: [User, UserService]
})
export class UserEditorComponent implements OnInit {
// Setup Form
private email_regex = '[a-z0-9\\.\\-\\_]+@[a-z0-9\\.\\-\\_]+\\.[a-z0-9\\.\\-\\_]+';
userForm: FormGroup;
validation_errors: Array<string> = [];
user_id: string;
constructor(private userService: UserService, private user: User, private router: Router, private params: RouteParams, private formBuilder: FormBuilder) {}
/**
* Handle submit of form
*/
onSubmit(form: any) {
// Subscribe to observable and handle errors
this.userService.createUser(this.userService.user).subscribe(
user => {
// Store created user in Component variable. We could now display it or navigate somewhere
this.user = user;
},
err => {
let errors = err.json().errors;
for(var i = 0; i < errors.length; i++) {
// Handle errors in the component and don't store it in the Service
this.validation_errors.push(errors[i])
}
}
);
}
ngOnInit(): any {
// Use the new FormBuilder
this.userForm = this.formBuilder.group({
id: [''],
name: ['', Validators.required],
email: ['', [Validators.required, Validators.pattern(this.email_regex)]],
username: ['', [Validators.required, Validators.minLength(5)]],
password: ['', [Validators.required, Validators.minLength(8)]],
password_confirmation: ['']
});
}
}
user-editor.component.html
<div class="form-group"
[hidden]="validation_errors.length === 0"
class="alert alert-warning" role="alert">
<strong>Some errors occured</strong>
<ul>
<li *ngFor="let validation_error ofvalidation_errors">
<span class="text-capitalize">{{validation_error.source.field}}:</span> {{validation_error.detail}}
</li>
</ul>
</div>