javascript 使用来自公共服务的路由器出口组件中的数据

bvn4nwqk  于 2023-03-21  发布在  Java
关注(0)|答案(1)|浏览(107)

在一开始我想写我不知道很好的Angular 和我困惑与我的问题。在我的应用程序中,我有一个大的组件称为ScheduleComponent,其中包括在顶部会议收集和底部3个组件,根据用户的行动而改变(CreateScheduleComponent,SuccessComponent,ScheduleComponent和CreateScheduleComponent正在使用来自公共服务(如ScheduleService)的名为会议的BehaviorSubject对象。
问题出在我的CreateScheduleComponent上,因为在构造函数中,我从会议的公共服务订阅了可观察的会议$ object,在同一个组件中,我使用方法创建新的会议,在这个方法中,我必须发出新的值,因为我的ScheduleComponent也订阅了会议$ object,我想看到我的会议集合中的所有更改(cancel,add),但这会触发我在(ScheduleComponent和CreateScheduleComponent)中的所有订阅,我想阻止CreateScheduleComponent中的订阅。
请告诉我,我该如何解决这个问题。

export class ScheduleComponent {

    meetings$: Observable<Meetings[]> = this.scheduleSvc.meetings$;

    constructor(private scheduleSvc: ScheduleService, private userTokenSvc: UserTokenService, private router : Router) {
        this.scheduleSvc.getMeetings()
            .subscribe(rs => {
                let meetings = rs.filter(meeting => meeting.clientId == this.userTokenSvc.getUser().id && meeting.isScheduled);
                this.scheduleSvc.addMeetings(meetings); <- Im not sure about this line
            });
    }

    hasCreateScheduleBtn(){
        return this.router.url == this.router.createUrlTree(['/schedule']).toString();
    }

    cancelMeeting(meetingId: number): void{
        this.scheduleSvc.cancelMeeting(meetingId)
            .subscribe(rs => this.meetings$ = this.meetings$.pipe(map(meetings => meetings.filter(meeting => meeting.id !== meetingId))));
    }
}

ScheduleComponent.html

<div>
    <div class="text-title">
        Schedule
    </div>

    <div class="schedule-info-box">
        <div class="schedule-info-text">Your scheduled meetings</div>
        <div>
            <div class="schedule-box" *ngFor="let meeting of meetings$ | async">
                <pre style="display:contents;">{{ meeting.startMeetingDate }}        {{ meeting.meetingTopic }}</pre>
                <button class="cancel-schedule-btn" (click)="cancelMeeting(meeting.id)" [hidden]="!meeting.isScheduled">CANCEL</button>
            </div>
        </div>
    </div>

    <button class="create-schedule-btn" *ngIf="hasCreateScheduleBtn()" routerLink="/schedule/create">
        CREATE MEETING
    </button>

    <router-outlet></router-outlet>
</div>

CreateScheduleComponent

export class CreateScheduleComponent{

    @ViewChild('dateInput', { static: true }) dateInput: ElementRef;
    @ViewChild('matSelectTime', { static: true }) matSelectTime: MatSelect;
    @ViewChild('matSelect', { static: true }) topicSelect: MatSelect;

    times = TIME_INFO;
    topics = TOPICS;
    createResultLink: string;
    meetingDate: any[] = [];
    meetings: Meetings[];

    constructor(public scheduleSvc: ScheduleService, private router: Router, public datePipe: DatePipe) { 
      this.scheduleSvc.meetings$
        .pipe(first())    <- only first() prevents triggers after next
      .subscribe(x => 
        {
          this.meetings = x;
          this.createMeetingDates(x);
        });
    }

    createMeeting() {
      let dividedTime = this.matSelectTime.value.split(':') as number[];
      let date = new Date(this.datePipe.transform(this.dateInput.nativeElement.value) as string);
      
      let meeting =
       { 
        createDate: new Date(),
        clientId: 14,
        startMeetingDate: new Date(date.getFullYear(), date.getMonth(), date.getDate(), dividedTime[0], dividedTime[1], 0),
        meetingTopic: this.topicSelect.value,
        isScheduled: true
      };

      this.scheduleSvc.createMeeting(meeting)
      .pipe(
        switchMap(x => 
          { 
            this.createResultLink = '/schedule/success';
            this.scheduleSvc.addMeeting(meeting as Meetings);
            
            return of(x); 
          }),
        catchError(_ => this.createResultLink = '/schedule/error'))
      .subscribe(x => this.router.navigate([this.createResultLink]));
    }

日程服务

export class ScheduleService {

    private meetingsSource = new BehaviorSubject<Meetings[]>([]);
    meetings$ = this.meetingsSource.asObservable();

    constructor(private httpClient: HttpClient) {
    }

    getMeetings(): Observable<Meetings[]> {
        return this.httpClient.get<Meetings[]>(`${baseUrl}/api/schedule/meetings`, httpOptions);
    }

    createMeeting(meeting: any): Observable<any> {
        return this.httpClient.post(`${baseUrl}/api/schedule/createMeeting`, meeting, { responseType: 'text' })
    }

    addMeetings(meetings: Meetings[]){
        this.meetingsSource.next(meetings);
    }

    addMeeting(meeting: Meetings) {
        const currentValue = this.meetingsSource.value;
        const updatedValue = [...currentValue, meeting];
        this.meetingsSource.next(updatedValue);
    }
}
6ojccjat

6ojccjat1#

如果我理解正确的话,这里的问题是CreateScheduleComponent在页面重定向到成功组件之前显示了新创建的会议的一个flash。
如果是这个问题,您可以做的是在成功创建新会议时强制取消订阅scheduleSvc.meetings$,从而防止执行订阅回调。
为此,您可以在CreateScheduleComponent中创建一个RxJS Subject,名称类似于meetingAdded$

meetingAdded$ = new Subject<boolean>();

然后,在scheduleSvc.meetings$管道中,使用takeUntil operatormeetingAdded$发出以下命令时强制取消订阅:

constructor(public scheduleSvc: ScheduleService, private router: Router, public datePipe: DatePipe) { 
  this.scheduleSvc.meetings$.pipe(
    takeUntil(this.meetingAdded$) <--------- add this
  )
  .subscribe(x => 
    {
      this.meetings = x;
      this.createMeetingDates(x);
    });
}

然后,在createMeeting流中,使用tap operator触发meetingAdded$的emit,它用于副作用:

this.scheduleSvc.createMeeting(meeting)
.pipe(
  tap(() => { <----------------------------- add this
    this.meetingAdded$.next(true)
    this.meetingAdded$.complete()
  }),
  switchMap(x => 
    { 
      this.createResultLink = '/schedule/success';
      this.scheduleSvc.addMeeting(meeting as Meetings);
      
      return of(x); 
    })

有了这些部分,一旦添加了会议,组件就应该取消订阅meetings$,因此不会显示新添加的会议。

相关问题