我正在设计一个系统,其中有一个视图,教师可以看到学生的测试数据摘要。以下是它的组成部分:
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';
import { Student } from '../../models/student'
import { StudentsService } from '../../services/students.service';
import { Test } from '../../models/test'
import { TestsService } from '../../services/tests.service';
@Component({
selector: 'app-teacher',
providers: [ StudentsService, TestsService ],
templateUrl: './teacher.component.html',
styleUrls: ['./teacher.component.css']
})
export class TeacherComponent implements OnInit {
// Local properties
students: Student[];
student_search_filter: string = '';
num_items: number = 10000;
page: number = 1;
orderBy: string = 'last_name';
subject: string = 'math';
options: Object = { title : { text : 'Loading...'} };
tests: Test[];
testsInSession: Test[][];
testsCount: number[] = [0,0,0];
mean: number[] = [0,0,0];
median: number[] = [0,0,0];
sessions: string[] = ['Winter 2017','Fall 2016','Spring 2016'];
scores: number[][];
chartData: Object[][];
constructor(private router: Router, private route: ActivatedRoute, private testService: TestsService, private studentService: StudentsService) { }
ngOnInit() {
this.route.params.subscribe(params => {
this.subject = (params['subject'].charAt(0).toUpperCase() + params['subject'].slice(1)); // Uppercase first letter and set the subject from the URL
/*** Reset Variable ***/
this.chartData = [];
this.testsInSession = [];
this.scores = [];
for(var testsSessions = 0; testsSessions < this.sessions.length; testsSessions++){
this.chartData[testsSessions] = [{}];
this.testsInSession[testsSessions] = [];
this.scores[testsSessions] = [];
}
this.testsCount = [0,0,0];
this.mean = [0,0,0];
this.median = [0,0,0];
/**********************/
this.createCharts(); // Load blank placeholder chart until data is loaded
this.loadStudents();
});
}
// Load the students from the API and then call function to load tests
loadStudents() {
this.studentService.getStudents(this.page, this.num_items, this.student_search_filter, this.orderBy)
.subscribe(
students => {
this.students = students, //Assign returned students to local property
this.loadStudentTests();
},
err => { console.log(err); });
}
// Load tests froms API of given students and then call function to generate the graph
loadStudentTests() {
let studentIDs: string = '';
for(var studentsI = 0; studentsI < this.students.length; studentsI++){
studentIDs += this.students[studentsI].student_id + '||';
}
studentIDs = studentIDs.slice(0, -2);
this.testService.getTestScores([{ 'test_type': this.subject },{ 'student_id': studentIDs }])
.subscribe(
chartDataFromApi => {
this.tests = chartDataFromApi; // Assign returned tests to local property
for(var testsSessions = 0; testsSessions < this.sessions.length; testsSessions++){
for(var testsI = 0; testsI < this.tests.length; testsI++){
if (this.tests[testsI].test_season == this.sessions[testsSessions]){ // If test sessions matches current session, add to these variables
this.testsInSession[testsSessions].push(this.tests[testsI]);
this.chartData[testsSessions].push({ "name":this.tests[testsI].student_id, "x":Number(this.testsCount[testsSessions]), "y": Number(this.tests[testsI].score) }, );
this.testsCount[testsSessions]++;
}
}
}
this.getStats();
},
err => { console.log(err); });
}
getStats(){
for(var testsSessions = 0; testsSessions < this.sessions.length; testsSessions++){
for(var testsI = 0; testsI < this.testsInSession[testsSessions].length; testsI++){
this.mean[testsSessions]+=Number(this.testsInSession[testsSessions][testsI].score);
this.scores[testsSessions].push(Number(this.testsInSession[testsSessions][testsI].score));
}
/* Calculate Median */
this.scores[testsSessions].sort((a, b) => a - b);
let lowMiddle = Math.floor((this.scores[testsSessions].length - 1) / 2);
let highMiddle = Math.ceil((this.scores[testsSessions].length - 1) / 2);
this.median[testsSessions] = (this.scores[testsSessions][lowMiddle] + this.scores[testsSessions][highMiddle]) / 2;
/* -Median- */
this.mean[testsSessions]=+(this.mean[testsSessions]/this.testsCount[testsSessions]).toFixed(2);
}
this.createCharts();
}
// Function to calcuate percentiles for the given session
getPercentile(session, percentile){
const index = (percentile/100) * this.scores[session].length;
if (Math.floor(index) == index){
return (this.scores[session][index-1] + this.scores[session][index]/2)
} else {
return this.scores[session][Math.floor(index)];
}
}
createCharts(){
this.options = {
chart: {
type: 'scatter',
zoomType: 'xy'
},
title : { text : this.subject},
xAxis: {
title: {
enabled: true,
text: 'Students'
},
labels: {
enabled: false
},
minorTickLength: 0,
tickLength: 0
},
yAxis: {
title: {
text: 'Scores'
}
},
plotOptions: {
scatter: {
marker: {
radius: 5,
states: {
hover: {
enabled: true,
lineColor: 'rgb(100,100,100)'
}
}
},
states: {
hover: {
marker: {
enabled: false
}
}
},
tooltip: {
headerFormat: '<b>{series.name}</b><br>',
pointFormat: '{point.name}<br />Score: {point.y}'
}
}
},
series: [{
name: this.sessions[0],
color: 'rgba(223, 83, 83, .5)',
data: this.chartData[0]
},{
name: this.sessions[1],
color: 'rgba(119, 152, 191, .5)',
data: this.chartData[1]
},{
name: this.sessions[2],
color: 'rgba(80, 180, 50, .5)',
data: this.chartData[2]
}],
credits: {
enabled: false
}
};
}
}辅助档案:
student.ts模型students.service.ts服务tests.service.ts服务我特别担心的是,我是否应该在这里或在另一个文件中进行平均、百分位数等计算。另外,是否有更好的方法来使用/设置本地属性?我想在整个视图中使用它们,但是当我选择不同的主题时,我似乎需要在ngOnInit中重新设置它们。
发布于 2018-08-27 17:03:59
看起来你只是在一个组件上做所有的事情。这就是你现在应该如何创造角质成分。
在创建组件时,应该记住一条经验法则。也就是说,“组件的目的只应是向用户呈现数据,并让用户与数据交互”。
记住这个大拇指规则,我们就可以创建所谓的Skinny组件。
尽管如此,组件中应该存在的唯一代码应该是从服务中获取数据,然后将其显示给用户。如果需要对数据执行操作,则应将其委托给服务。
我在代码中看到的另一件事是,providers: [ StudentsService, TestsService ],。不知道你是不是故意这么做的。但是这样做将为TeacherComponent及其子服务创建这些服务的单独实例。
我要指出的最后一件事是,TeacherComponent中有几件事情,如createCharts、getPercentile、getStats等,所有这些都应该作为子组件的一部分来完成,然后子组件将依赖于服务以适当的形式获取适当的数据。
希望这能有所帮助。如果您需要更多的评论来获得更好的、更松散的耦合和更好的分离关注点,请让我知道。如果您能够创建一个StackBliz项目并在这里共享它,这样其他人就可以查看它,这也会有所帮助。
https://codereview.stackexchange.com/questions/157951
复制相似问题