我有一個墊子表,其中每一行代表一個通話的錄音。在每一行的末尾,有一個播放按鈕,單擊時播放相應的音頻檔案。但是,當我單擊任何播放按鈕時,會播放正確的音頻檔案,但所有播放按鈕都會變為停止按鈕。這是html的一個片段:
<!-- audio display -->
<ng-container matColumnDef="isPlaying">
<mat-header-cell *matHeaderCellDef>Playing</mat-header-cell>
<mat-cell *matCellDef="let recording">
<button mat-button (click)="playToggle(recording)" [disabled]="state?.error" *ngIf="!state?.playing">
<mat-icon mat-list-icon>play_arrow</mat-icon>
</button>
<button mat-button (click)="pause()" *ngIf="state?.playing">
<mat-icon mat-list-icon>pause</mat-icon>
</button>
</mat-cell>
</ng-container>


錄音.component.ts
@Component({
selector: 'recordings',
templateUrl: './recordings.component.html',
styleUrls: ['./recordings.component.scss'],
encapsulation: ViewEncapsulation.None,
animations: fuseAnimations
})
export class RecordingsComponent implements OnInit {
// Class Variables
recordingPlaying = false;
buttonValue = 'Play Recording';
displayColumns: string[] = ['date', 'time'];
dataSource: MatTableDataSource < Recording > ;
currentUser: BehaviorSubject < UserModel > ;
dataLoading = true;
recordings: Recording[];
recording: Recording;
state: RecordingStreamState;
currentFile: any = {};
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
@Input()
telephone: string;
// Private
private audio = new Audio();
private _unsubscribeAll: Subject < any > ;
constructor(
private _recordingsService: RecordingsService,
private _usersService: UserService,
private _matSnackBar: MatSnackBar,
private _fuseSidebarService: FuseSidebarService,
private _matDialog: MatDialog
) {
// Set the defaults
this._unsubscribeAll = new Subject();
}
ngOnInit(): void {
this.currentUser = this._usersService.user;
this.loadRecordings();
// listen to stream state
this._recordingsService.getState().subscribe(state => {
this.state = state;
console.log('this.state: ' JSON.stringify(this.state));
});
}
public loadRecordings(): void {
this._recordingsService.getRecordings(this.telephone).then(data => {
this.recordings = data;
});
this._recordingsService.onRecordingClick
.subscribe((recordings: Recording[]) => this.handleRecordings(recordings),
err => this.handleRecordingsError(err)
);
}
private handleRecordings(recordings: Recording[]): void {
this.dataLoading = false;
this.dataSource = new MatTableDataSource(recordings);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
private handleRecordingsError(err): void {
console.error(err);
// this.alertService.error("Problem loading contacts!");
}
playToggle(recording): void {
// TODO: (remove) if this is the reocrding already playing, pause, else play
if (recording === this.recording) {
this.pause();
this.recording = null;
} else {
this.recording = recording;
console.log('this.recording: ' JSON.stringify(this.recording));
if (this.recording === undefined) {
console.log('could not find recording.');
} else {
this.playStream(this.recording.url);
}
}
}
playStream(url): void {
// subscribes to playStream in our service and starts listening to media events
// like canplay, playing etc. This should be done in the stateChange object
// but we use this method to start the observable and audio playback
this._recordingsService.playStream(url).subscribe(events => {
});
}
pause(): void {
this._recordingsService.pause();
}
play(): void {
this._recordingsService.play();
}
stop(): void {
this._recordingsService.stop();
}
}
錄音.service.ts
@Injectable()
export class RecordingsService implements Resolve < any > {
// Class variables
routeParams: any;
recordings: Recording[];
onRecordingClick: BehaviorSubject < any > ;
private stop$ = new Subject();
private audioObj = new Audio();
audioEvents = [
'ended',
'error',
'play',
'playing',
'pause',
'timeupdate',
'canplay',
'loadedmetadata',
'loadstart',
];
// gets from the interface we created
private state: RecordingStreamState = {
playing: false,
readableCurrentTime: '',
readableDuration: '',
duration: undefined,
currentTime: undefined,
canplay: false,
error: false,
};
private stateChange: BehaviorSubject < RecordingStreamState > = new BehaviorSubject(
this.state
);
// tslint:disable-next-line:typedef
private streamObservable(url) {
console.log('in streamObservable in service');
// tslint:disable-next-line:no-unused-expression
return new Observable(observer => {
// Play audio
this.audioObj.src = url;
this.audioObj.load();
this.audioObj.play();
// a way for the observer to react to items the observable emits
const handler = (event: Event) => {
this.updateStateEvents(event);
observer.next(event);
};
this.addEvents(this.audioObj, this.audioEvents, handler);
return () => {
// stop playing
this.audioObj.pause();
this.audioObj.currentTime = 0;
// remove event listeners
this.removeEvents(this.audioObj, this.audioEvents, handler);
};
});
}
private addEvents(obj, events, handler): void {
events.forEach(event => {
obj.addEventListener(event, handler);
});
}
private removeEvents(obj, events, handler): void {
events.forEach(event => {
obj.removeEventListener(event, handler);
});
}
// how to handle the different events , recording: Recording
private updateStateEvents(event: Event): void {
console.log('event_type: ' event.type);
switch (event.type) {
case 'canplay':
this.state.duration = this.audioObj.duration;
this.state.readableDuration = this.formatTime(this.state.duration);
this.state.canplay = true;
break;
case 'playing':
this.state.playing = true;
break;
case 'pause':
this.state.playing = false;
break;
case 'timeupdate':
this.state.currentTime = this.audioObj.currentTime;
this.state.readableCurrentTime = this.formatTime(
this.state.currentTime
);
break;
case 'error':
this.resetState();
this.state.error = true;
break;
}
this.stateChange.next(this.state);
}
private resetState(): void {
this.state = {
playing: false,
readableCurrentTime: '',
readableDuration: '',
duration: undefined,
currentTime: undefined,
canplay: false,
error: false,
};
}
getState(): Observable < RecordingStreamState > {
return this.stateChange.asObservable();
}
playStream(url): Observable < any > {
return this.streamObservable(url).pipe(takeUntil(this.stop$));
}
play(): void {
this.audioObj.play();
}
pause(): void {
this.audioObj.pause();
}
stop(): void {
this.stop$.next();
}
seekTo(seconds): void {
this.audioObj.currentTime = seconds;
}
formatTime(time: number, format: string = 'HH:mm:ss'): string {
const momentTime = time * 1000;
return moment.utc(momentTime).format(format);
}
/**
* Constructor
*
* @param {HttpClient} _httpClient
*/
constructor(
private _httpClient: HttpClient,
) {
// Set the defaults
this.onRecordingClick = new BehaviorSubject([]);
}
}
uj5u.com熱心網友回復:
查看您的代碼,我可以想到一個可能的解決方案。我不知道Recording物件是如何定義的,但如果它包含一些id它可能會起作用。或者您可以使用其他識別符號。
正如我在評論中所說,state屬性由表中的所有條目共享。所以僅僅確定當前的播放記錄是不夠的。一旦它對一個人是正確的,它對所有人都是正確的。但也許這會有所幫助:
<!-- audio display -->
<ng-container matColumnDef="isPlaying">
<mat-header-cell *matHeaderCellDef>Playing</mat-header-cell>
<mat-cell *matCellDef="let rowRecording">
<button mat-button (click)="playToggle(rowRecording)" [disabled]="state?.error" *ngIf="!state?.playing">
<mat-icon mat-list-icon>play_arrow</mat-icon>
</button>
<button mat-button (click)="pause()" *ngIf="state?.playing && rowRecording.id === recording.id">
<mat-icon mat-list-icon>pause</mat-icon>
</button>
</mat-cell>
</ng-container>
如您所見,我重命名了inside recordingHTML 以rowRecording將其與 .ts 代碼區分開來。然后我正在檢查狀態是否正在播放,以及是否rowRecording.id等于 .ts 中分配的記錄的 ID。您在playToggle函式中執行此操作。
但我建議使用按播放時分配RecordingStreamState的屬性擴展物件。PlayingRecordId然后你可以做這樣的事情(使用你的 HTML 版本)
<button
mat-button
(click)="pause()"
*ngIf="state?.playing && state?.playingRecordId === recording.id"
>
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/492764.html
