【发布时间】:2018-07-09 11:01:45
【问题描述】:
我在后端使用 Ruby on Rails API 应用程序,在前端使用 Angular 6。这是我从后端得到的 json 响应:
loclhost3000/courses.json
[
{
id:1,
title:"Introduction",
author:"Dana Inbar",
segments:[
]
},
{
id:2,
title:"Master the ELN",
author:"Dana Inbar",
segments:[
]
},
{
id:3,
title:"Master the Inventory",
author:"Dana Inbar",
segments:[
{
id:1,
unit_id:1,
unit_title:"Introduction",
name:"Lesson 1: Introduction to the inventory module- looking at one collection",
data:"www.video01.com/vid.avi"
},
{
id:2,
unit_id:2,
unit_title:"Inventory Customisation",
name:"Lesson 2: Setting up custom collections",
data:"www.video02.com/vid.avi"
},
{
id:3,
unit_id:2,
unit_title:"Inventory Customisation",
name:"Lesson 3: Adding a custom field",
data:"www.video03.com/vid.avi"
},
{
id:4,
unit_id:2,
unit_title:"Inventory Customisation",
name:"Lesson 4: Creating derived collections",
data:"www.video04.com/vid.avi"
},
{
id:5,
unit_id:2,
unit_title:"Inventory Customisation",
name:"Lesson 5: Using repositories",
data:"www.video05.com/vid.avi"
},
{
id:6,
unit_id:2,
unit_title:"Inventory Customisation",
name:"Quiz",
data:"'[ { "
question 1":"___",
"answers":{
"1":"____",
"2":"____",
"3":"____"
},
"correct_answer":"2"
},
{
"question 2":"___",
"answers":{
"1":"____",
"2":"____"
},
"correct_answer":"1"
}
}
] ' "
}
]
}
]
我的课程模型有很多段,段是视频或测验。 我有课程列表、课程详细信息和课程播放组件。 我对课程详细信息有疑问,我希望课程详细信息页面如下所示:course-detail image
我认为我可以在 course.service 中使用 groupBy 与 unit_id 和 unit_title 并执行两个 ngFor(或 ngFor 组)的功能,但因为我是 Angular 新手,我不知道如何最好地实现这一点。
我正在从程序中添加一些可以提供帮助的文件:
./courses/course.module
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes } from '@angular/router';
import { MatSidenavModule } from '@angular/material/sidenav';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { CourseListComponent } from './course-list/course-list.component';
import { CourseDetailComponent } from './course-detail/course-detail.component';
import { CourseService } from './course.service';
import { CoursePlayComponent } from './course-play/course-play.component';
const coursesRoutes: Routes = [
{ path: 'courses', component: CourseListComponent },
{ path: 'courses/:id', component: CourseDetailComponent },
{ path: 'courses/:id/:segment_id', component: CoursePlayComponent }
]
@NgModule({
imports: [
CommonModule,
MatSidenavModule,
BrowserAnimationsModule,
RouterModule.forChild(
coursesRoutes
)
],
declarations: [
CourseListComponent,
CourseDetailComponent,
CoursePlayComponent
],
providers: [
CourseService
]
})
export class CourseModule { }
./courses/course
export interface ICourse {
course_id: number;
title: string;
autor: string;
segments: ISegment[];
}
export interface ISegment {
segment_id: number;
unit_id: number;
unit_title: string;
name: string;
type: string;
data: string;
}
./courses/course.service
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { map, catchError, retry, groupBy, Filter } from 'rxjs/operators';
import { Course } from './course';
// Inject Data from Rails app to Angular app
@Injectable()
export class CourseService{
constructor(private http: HttpClient) { }
private url = 'http://localhost:3000/courses';
private courseUrl = 'http://localhost:3000/courses.json';
// Handle Any Kind of Errors
private handleError(error: HttpErrorResponse) {
// A client-side or network error occured. Handle it accordingly.
if (error.error instanceof ErrorEvent) {
console.error('An error occured:', error.error.message);
}
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong.
else {
console.error(
'Backend returned code ${error.status}, ' +
'body was ${error.error}');
}
// return an Observable with a user-facing error error message
return throwError(
'Something bad happend; please try again later.');
}
// Get All Courses from Rails API App
getCourses(): Observable<ICourse[]> {
const coursesUrl = `${this.url}` + '.json';
return this.http.get<ICourse[]>(coursesUrl)
.pipe(
catchError(this.handleError)
);
}
// Get Single Course by id. will 404 if id not found
getCourse(id: number): Observable<ICourse> {
const detailUrl = `${this.url}/${id}` + '.json';
return this.http.get<ICourse[]>(detailUrl)
.pipe(
catchError(this.handleError)
);
}
}
./courses/course-detail/course-detail.component
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Course } from '../course';
import { CourseService } from '../course.service';
@Component({
selector: 'lg-course-detail',
templateUrl: './course-detail.component.html',
styleUrls: ['./course-detail.component.sass']
})
export class CourseDetailComponent implements OnInit {
course: ICourse;
errorMessage: string;
constructor(private courseService: CourseService,
private route: ActivatedRoute,
private router: Router) {
}
ngOnInit() {
const id = +this.route.snapshot.paramMap.get('id');
this.getCourse(id);
}
// Get course detail by id
getCourse(id: number) {
this.courseService.getCourse(id).subscribe(
course => this.course = course,
error => this.errorMessage = <any>error);
}
onBack(): void {
this.router.navigate(['/courses']);
}
}
./courses/course-detail/course-detail.html
<div id="main" *ngIf="course">
<div class="row" id="image">
<div class="col-lg-8">
<br>
<img src="./assets/images/lg-white.png" class="d-inline-block align-top" alt="">
</div>
</div>
<div class="row" id="header">
<div class="container text-center">
<br>
<h1>{{course.title}}</h1>
<br>
</div>
</div>
<div class="row justify-content-lg-center" id="progress">
<div class="container text-center">
<div class="progress">
<div class="progress-bar bg-white"></div>
</div>
<td>Your Progress</td>
<br><br><br>
</div>
</div>
<div class="row" id="body">
<div class="container">
<br>
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item">
<a class="nav-link active" href="#Curiculum" role="tab" data-toggle="tab">Curiculum</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#About" role="tab" data-toggle="tab">About this course</a>
</li>
</ul>
<br>
<!-- Tab panes -->
<div class="tab-content">
<div role="tabpanel" class="tab-pane fade in active" id="Curiculum">
<h1>Course Overview</h1>
<br>
<ul *ngFor="let segment of course.segmentsByUnitId">
<ul>
<li id="title">Unit {{segment.unit_id}}: {{segment.unit_title}}</li>
<li>{{segment.name}}</li>
</ul>
</ul>
</div>
<div role="tabpanel" class="tab-pane fade" id="About">
<h1>Course Topics:</h1>
</div>
</div>
<br>
</div>
</div>
</div>
./courses/course-detail/course-detail.sass
$color: #FFFFFF
$bg-col: #5c0099
$prog-size: 10px
#image
background-color: $bg-col
color: $color
#header
background-color: $bg-col
color: $color
#body
background-color: $color
height: 100vh
max-width: initial
display: flex
#title
font-weight: bold
#progress
background-color: $bg-col
color: $color
font-size: $prog-size
.progress
height: 10px
left: 30%
.progress-bar
width: 10%
height: 20px
background-color: transparent
【问题讨论】:
标签: json angular group-by rxjs httpclient