【发布时间】:2018-04-20 16:09:43
【问题描述】:
我试图找出一个简单的计时器可以观察几个星期,但没有运气。我最初是在上周发布的:ngrx and angular 5 on stackoverflow 并没有得到任何地方。我尝试实施建议并使用我的原始解决方案更进一步。此时我有一个计时器,它发出并输出倒计时,但仅在单击播放或暂停按钮时。我试图让倒计时继续在按下播放按钮时向显示组件发出值。我已经控制台记录了计时器,它在播放被推送时发出值,但显示组件没有。我想不通。我是 Angular 5 和 ngrx/rxjs 的新手。
我在 Stackblitz 上以工作形式提供了项目代码。 I have the project code available in a working form on Stackblitz here.
您可以使用用户登录:test 密码:test
定时器代码在 core/services/pomo-timer.ts
容器组件是books/containers/selected-book-page.ts
展示组件为books/components/book-detail.ts
此时它应该显示 6 秒,一旦按下播放按钮,它应该发出并显示每秒倒计时,直到按下 暂停 按钮,此时它应该暂停直到 播放 再次被点击。正如我所提到的,当我 console.log 的值工作得很好。只有在组件中显示时它们才不会显示。
从 UI:使用 test/test 登录。搜索一本书。添加到收藏。单击直通到详细信息页面。有一个播放和暂停按钮。页面上显示的是我从 StackOverflow 上找到的解决方案中尝试过的三种计时器变体。计时器从 6 秒开始倒计时至零。播放被点击计时器开始。暂停点击计时器停止,直到再次点击播放。在显示页面上,发出的值没有倒计时。控制台打开时,它会倒计时发出的值。
定时器由 core/services/pomo-timer.ts 处理
startTimer() {
const resumeButton = document.getElementById('resume');
const pauseButton = document.getElementById('pause');
const resetButton = document.getElementById('reset');
const interval$: any = interval(1000).pipe(mapTo(-1));
const pause$ = fromEvent(pauseButton, 'click').pipe(mapTo(false));
const resume$ = fromEvent(resumeButton, 'click').pipe(mapTo(true));
const timer$ = merge(pause$, resume$).pipe(
startWith(interval$),
switchMap(val => (val ? interval$ : empty())),
scan((acc, curr) => (curr ? curr + acc : acc),
this.countdownSeconds$),
takeWhile(v => v >= 0),
)
.subscribe(
val => { this.timeRemaining = val;
console.log(this.timeRemaining);
},
val => { this.checkTime.emit(val); },
() => {
this.resetTimer();
});
}
显示由 app/books/components/book-detail.ts
处理export class BookDetailComponent {
@Input() simpleObservable: number;
@Input() seconds: string;
@Input() timeRemaining: number;
@Input() timerSubscription: Subscription;
@Input() book: Book;
@Input() inCollection: boolean;
@Output() add = new EventEmitter<Book>();
@Output() remove = new EventEmitter<Book>();
@Output() resumeClicked = new EventEmitter();
@Output() checkTime: EventEmitter<number> = new EventEmitter();
get id() {
return this.book.id;
}
get title() {
return this.book.volumeInfo.title;
}
get subtitle() {
return this.book.volumeInfo.subtitle;
}
get description() {
return this.book.volumeInfo.description;
}
get thumbnail() {
return (
this.book.volumeInfo.imageLinks &&
this.book.volumeInfo.imageLinks.smallThumbnail
);
}
get time() {
return this.timeRemaining;
}
resumeCommand(action: any) {
this.resumeClicked.emit(action);
}
}
与计时器服务的通信由:app/books/containers/selected-book-page.ts
@Component({
selector: 'bc-selected-book-page',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<bc-book-detail
[book]="book$ | async"
[inCollection]="isSelectedBookInCollection$ | async"
[timeRemaining]="this.pomoTimerService.timeRemaining"
[simpleObservable]="this.simpleObservable | async"
[seconds]="this.pomoTimerService.timeRemaining"
(checkTime)="checkCurrentTime($event)"
(add)="addToCollection($event)"
(remove)="removeFromCollection($event)"
(resumeClicked)="resumeClicked($event)"
(resumeClicked)="resumeClicked($event)"
(reset)="resumeClicked($event)">
</bc-book-detail>
`,
})
export class SelectedBookPageComponent implements OnInit {
book$: Observable<Book>;
isSelectedBookInCollection$: Observable<boolean>;
timeRemaining: any;
private timerSubscription: Subscription;
timerSource = new Subject<any>();
simpleObservable;
countDown: any;
counter: number;
seconds: string;
private subscription: Subscription;
checkTime;
constructor(public pomoTimerService: PomoTimerService, private store:
Store<fromBooks.State>) {
this.book$ = store.pipe(select(fromBooks.getSelectedBook));
this.isSelectedBookInCollection$ = store.pipe(
select(fromBooks.isSelectedBookInCollection)
);
}
ngOnInit(): void {
this.pomoTimerService.pomoCount$ = 0;
this.pomoTimerService.pomosCompleted$ = 0;
this.pomoTimerService.pomoTitle$ = 'Time to Work';
this.pomoTimerService.initTimer();
}
addToCollection(book: Book) {
this.store.dispatch(new collection.AddBook(book));
}
removeFromCollection(book: Book) {
this.store.dispatch(new collection.RemoveBook(book));
}
resumeClicked(event) {
console.log(event);
console.log(event.target);
console.log(event.srcElement);
console.log(event.type);
console.log(event.currentTarget.attributes.name.nodeValue);
console.log(event.currentTarget.attributes.id.nodeValue);
if (event.currentTarget.attributes.id.nodeValue === 'resume' &&
!this.pomoTimerService.timerStarted) {
this.pomoTimerService.timerStarted = true;
this.pomoTimerService.startTimer();
}
}
checkCurrentTime(event) {
this.counter = event;
}
}
pomo-timer.ts 正在通过this.remainingTime 输出计时器
您可能能够提供的任何帮助将不胜感激。我已经尝试了所有在 Stackoverflow 上找到的甚至远程相关的示例。非常感谢。
【问题讨论】:
-
您需要提供最低限度的minimal reproducible example这里请。
-
@SurajRao 来自 UI:使用 test/test 登录。搜索一本书。添加到收藏。单击直通到详细信息页面。有一个播放和暂停按钮。页面上显示的是我从 StackOverflow 上找到的解决方案中尝试过的三种计时器变体。计时器从 6 秒开始倒计时至零。播放被点击计时器开始。暂停点击计时器停止,直到再次点击播放。在显示页面上,发出的值没有倒计时。控制台打开时,它会倒计时发出的值。我现在将在原始帖子中添加更多详细信息。
-
@suraj-rao 我在之前的评论中添加了上述步骤,并在原始帖子中添加了更多代码 sn-ps。
-
我在上面添加了@SurajRao 重新创建的步骤。我已使用代码 sn-ps 在原始帖子中添加了更多详细信息。
-
似乎没有检测到来自提供者的更改。您可能需要在您的剩余秒数上使用诸如 behaviorSubject 之类的东西并在容器中订阅