Служба Observables – недопонимание/лучшая практика

Я борюсь с подходом наблюдения за обслуживанием между двумя компонентами. У меня есть компонент профиля, который включает компонент настроек. Оба используют user.service, где провайдер определен в app.module.ts. Провайдер больше нигде не определен. Поэтому, когда я меняю, например, firstName на settings.component и сохраняю его. Изменение не отразится на боковой панели profile.component, пока я не перезагружу страницу.

В нерабочее время. Я нашел решение сделать это с помощью генератора событий, который сработает, как только произойдет обновление. Это решило бы мою проблему выше, но я думаю, что это неправильный путь, так как я прочитал статью ниже:

Как правильно использовать EventEmitter?

Разве это не должно работать без эмиттера событий?

Итак, мой вопрос: Какой подход вы бы использовали в этой ситуации или как лучше всего? Конечно, в моем коде может быть проблема. Я действительно новичок в 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);
            }
        );
}

person vitalragaz    schedule 02.04.2018    source источник
comment
angular.io/guide/   -  person JB Nizet    schedule 02.04.2018
comment
Лучше всего не использовать для этого EventEmitter, это было объяснено в связанном вопросе stackoverflow.com/questions/36076700/ . Вместо этого используйте тему RxJS.   -  person Estus Flask    schedule 02.04.2018


Ответы (1)


Живой рабочий пример Вам не нужно запускать Событие для совместного использования (и синхронизации) данных между компонентами. Позвольте службам 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>
person Luillyfe    schedule 03.04.2018