Observable Service - 误解/最佳实践
Obseravables Service - Missunderstanding / Best Practise
我正在努力解决两个组件之间的观察服务方法。我有一个包含设置组件的配置文件组件。两者都使用 user.service,其中提供程序在 app.module.ts 中定义。提供者未在其他任何地方定义。因此,当我将 settings.component 上的 firstName 更改为示例并保存时。在我重新加载页面之前,更改不会反映在 profile.component 侧边栏中。
下班后:
我找到了一个解决方案,通过一个事件发射器来做到这一点,该事件发射器将在更新发生时立即触发。这将解决我上面的问题,但我认为这不是正确的方法,因为我阅读了下面的文章:
没有事件发射器它不应该工作吗?
所以我的问题是:
对于这种情况,您会使用什么方法或最佳做法是什么?当然,我的代码中可能存在问题。我真的是 angular 的新手。
app.module.ts
在 app.module.ts 中我定义了:
providers: [UserService]
profile.component.ts
@Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
user: any;
Role = Role;
constructor(private _userService: UserService, ) { }
ngOnInit() {
const token = localStorage.getItem('token');
const role = jwt.decode(token).user.role;
this._userService.getUser().subscribe(v => { this.user = v; });
// Event Emmiter Subscription
this._userService.change.subscribe(v => { this.user = v; });
}
}
profile.component.html
<div *ngIf="user" class="container mt50">
<div class="row profile">
<div class="col-md-3">
<div class="profile-sidebar">
<!-- SIDEBAR USERPIC -->
<div class="profile-userpic">
<img gravatar [email]="user.email" [size]="256" class="img-responsive animated bounceIn" alt="">
</div>
<!-- END SIDEBAR USERPIC -->
<!-- SIDEBAR USER TITLE -->
<div class="profile-usertitle">
<div class="profile-usertitle-name">
{{ user.firstName }} {{ user.lastName }}
</div>
<div class="profile-usertitle-job">
{{ user.email }}
</div>
</div>
</div>
</div>
<div class="col-md-9">
<app-profile-settings-admin *ngIf="user.role === Role.ADMINISTRATOR"></app-profile-settings-admin>
</div>
</div>
</div>
user.service.ts
@Injectable()
export class UserService {
public user: any;
constructor(private http: Http) { }
// EVENT EMIITER
public change: EventEmitter<any> = new EventEmitter();
getUser() {
const token = localStorage.getItem('token')
? '?token=' + localStorage.getItem('token')
: '';
return this.http.get('api/user' + token)
.map((response: Response) => {
this.user = response.json().obj;
return this.user;
})
.catch((error: Response) => Observable.throw(error.json()));
}
updateUser(user) {
const body = JSON.stringify(user);
const headers = new Headers({'Content-Type': 'application/json'});
const token = localStorage.getItem('token')
? '?token=' + localStorage.getItem('token')
: '';
return this.http.patch('api/user/' + token, body, {headers: headers})
.map((response: Response) => {
const result = response.json();
this.user = result.obj;
// EMIT EVENT
this.change.emit(this.user);
return this.user;
})
.catch((error: Response) => Observable.throw(error.json()));
}
}
profile.settings.admin.component.ts
在该组件中,只有一个表单会在提交时触发以下代码:
onSubmit() {
this._userService.updateUser(this.userForm.value)
.subscribe(
data => {
this._toastyService.default('Settings saved!');
console.log(data);
},
error =>{
this._toastyService.default('Error occured!');
console.log(error);
}
);
}
Live working example
您无需触发事件即可在组件之间共享(和同步)数据。让 Angular 服务(和 Angular 表单)为您控制:
Profile.component
ngOnInit() {
const token = localStorage.getItem('token');
const role = jwt.decodeToken(token).user.role;
this._userService.getUser().subscribe(v => {
this.user = v;
});
}
user.service
getUser() {
const token = localStorage.getItem('token')
? '?token=' + localStorage.getItem('token')
: '';
return this.http.get('api/user' + token)
.pipe(map((user: HttpResponse<any>) => {
this.user = user;
return this.user;
}),
catchError((error: HttpErrorResponse) => Observable.throw(error)))
}
updateUser(user) {
const body = JSON.stringify(user);
const headers: HttpHeaders = new HttpHeaders({'Content-Type': 'application/json'});
const token = localStorage.getItem('token')
? '?token=' + localStorage.getItem('token')
: '';
return this.http.patch('api/user/' + token, body, {headers})
.pipe(map((user: HttpResponse<any>) => {
this.user = user;
return this.user;
}),
catchError((error: HttpErrorResponse) => Observable.throw(error)));
}
profile.settings.admin.component.ts
ngOnInit() {
this._userService.getUser().subscribe((user: User) => {
this.user = user;
});
}
onSubmit() {
this._userService.updateUser(this.user)
.subscribe(
data => {
this._toastyService.default('Settings saved!');
console.log(data);
},
error =>{
this._toastyService.default('Error occured!');
console.log(error);
}
);
}
profile.settings.admin.component.html
<form #userForm="ngForm">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="name" aria-describedby="nameHelp"
placeholder="enter name" [(ngModel)]="user.name" name="name" required #name="ngModel">
<div [hidden]="name.valid || name.pristine"
class="alert alert-danger">
Name is required
</div>
</div>
<div class="form-group">
<label for="lastName">Last Name</label>
<input type="text" class="form-control" id="lastName" aria-describedby="lastNameHelp"
placeholder="enter last name" [(ngModel)]="user.lastName" name="lastName" required #lastName="ngModel">
<div [hidden]="lastName.valid || lastName.pristine"
class="alert alert-danger">
last Name is required
</div>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" class="form-control" id="email" aria-describedby="emailHelp"
placeholder="enter email" [(ngModel)]="user.email" name="email" required #email="ngModel">
<div [hidden]="email.valid || email.pristine"
class="alert alert-danger">
email is required
</div>
</div>
<button type="submit" class="btn btn-success" (click)="onSubmit()" >Submit</button>
</form>
我正在努力解决两个组件之间的观察服务方法。我有一个包含设置组件的配置文件组件。两者都使用 user.service,其中提供程序在 app.module.ts 中定义。提供者未在其他任何地方定义。因此,当我将 settings.component 上的 firstName 更改为示例并保存时。在我重新加载页面之前,更改不会反映在 profile.component 侧边栏中。
下班后: 我找到了一个解决方案,通过一个事件发射器来做到这一点,该事件发射器将在更新发生时立即触发。这将解决我上面的问题,但我认为这不是正确的方法,因为我阅读了下面的文章:
没有事件发射器它不应该工作吗?
所以我的问题是: 对于这种情况,您会使用什么方法或最佳做法是什么?当然,我的代码中可能存在问题。我真的是 angular 的新手。
app.module.ts
在 app.module.ts 中我定义了:
providers: [UserService]
profile.component.ts
@Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
user: any;
Role = Role;
constructor(private _userService: UserService, ) { }
ngOnInit() {
const token = localStorage.getItem('token');
const role = jwt.decode(token).user.role;
this._userService.getUser().subscribe(v => { this.user = v; });
// Event Emmiter Subscription
this._userService.change.subscribe(v => { this.user = v; });
}
}
profile.component.html
<div *ngIf="user" class="container mt50">
<div class="row profile">
<div class="col-md-3">
<div class="profile-sidebar">
<!-- SIDEBAR USERPIC -->
<div class="profile-userpic">
<img gravatar [email]="user.email" [size]="256" class="img-responsive animated bounceIn" alt="">
</div>
<!-- END SIDEBAR USERPIC -->
<!-- SIDEBAR USER TITLE -->
<div class="profile-usertitle">
<div class="profile-usertitle-name">
{{ user.firstName }} {{ user.lastName }}
</div>
<div class="profile-usertitle-job">
{{ user.email }}
</div>
</div>
</div>
</div>
<div class="col-md-9">
<app-profile-settings-admin *ngIf="user.role === Role.ADMINISTRATOR"></app-profile-settings-admin>
</div>
</div>
</div>
user.service.ts
@Injectable()
export class UserService {
public user: any;
constructor(private http: Http) { }
// EVENT EMIITER
public change: EventEmitter<any> = new EventEmitter();
getUser() {
const token = localStorage.getItem('token')
? '?token=' + localStorage.getItem('token')
: '';
return this.http.get('api/user' + token)
.map((response: Response) => {
this.user = response.json().obj;
return this.user;
})
.catch((error: Response) => Observable.throw(error.json()));
}
updateUser(user) {
const body = JSON.stringify(user);
const headers = new Headers({'Content-Type': 'application/json'});
const token = localStorage.getItem('token')
? '?token=' + localStorage.getItem('token')
: '';
return this.http.patch('api/user/' + token, body, {headers: headers})
.map((response: Response) => {
const result = response.json();
this.user = result.obj;
// EMIT EVENT
this.change.emit(this.user);
return this.user;
})
.catch((error: Response) => Observable.throw(error.json()));
}
}
profile.settings.admin.component.ts
在该组件中,只有一个表单会在提交时触发以下代码:
onSubmit() {
this._userService.updateUser(this.userForm.value)
.subscribe(
data => {
this._toastyService.default('Settings saved!');
console.log(data);
},
error =>{
this._toastyService.default('Error occured!');
console.log(error);
}
);
}
Live working example 您无需触发事件即可在组件之间共享(和同步)数据。让 Angular 服务(和 Angular 表单)为您控制:
Profile.component
ngOnInit() {
const token = localStorage.getItem('token');
const role = jwt.decodeToken(token).user.role;
this._userService.getUser().subscribe(v => {
this.user = v;
});
}
user.service
getUser() {
const token = localStorage.getItem('token')
? '?token=' + localStorage.getItem('token')
: '';
return this.http.get('api/user' + token)
.pipe(map((user: HttpResponse<any>) => {
this.user = user;
return this.user;
}),
catchError((error: HttpErrorResponse) => Observable.throw(error)))
}
updateUser(user) {
const body = JSON.stringify(user);
const headers: HttpHeaders = new HttpHeaders({'Content-Type': 'application/json'});
const token = localStorage.getItem('token')
? '?token=' + localStorage.getItem('token')
: '';
return this.http.patch('api/user/' + token, body, {headers})
.pipe(map((user: HttpResponse<any>) => {
this.user = user;
return this.user;
}),
catchError((error: HttpErrorResponse) => Observable.throw(error)));
}
profile.settings.admin.component.ts
ngOnInit() {
this._userService.getUser().subscribe((user: User) => {
this.user = user;
});
}
onSubmit() {
this._userService.updateUser(this.user)
.subscribe(
data => {
this._toastyService.default('Settings saved!');
console.log(data);
},
error =>{
this._toastyService.default('Error occured!');
console.log(error);
}
);
}
profile.settings.admin.component.html
<form #userForm="ngForm">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="name" aria-describedby="nameHelp"
placeholder="enter name" [(ngModel)]="user.name" name="name" required #name="ngModel">
<div [hidden]="name.valid || name.pristine"
class="alert alert-danger">
Name is required
</div>
</div>
<div class="form-group">
<label for="lastName">Last Name</label>
<input type="text" class="form-control" id="lastName" aria-describedby="lastNameHelp"
placeholder="enter last name" [(ngModel)]="user.lastName" name="lastName" required #lastName="ngModel">
<div [hidden]="lastName.valid || lastName.pristine"
class="alert alert-danger">
last Name is required
</div>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" class="form-control" id="email" aria-describedby="emailHelp"
placeholder="enter email" [(ngModel)]="user.email" name="email" required #email="ngModel">
<div [hidden]="email.valid || email.pristine"
class="alert alert-danger">
email is required
</div>
</div>
<button type="submit" class="btn btn-success" (click)="onSubmit()" >Submit</button>
</form>