Add course lists to subjects with add/edit option
Added count() method for hasManyThrough relations in a slightly hacky way
This commit is contained in:
parent
2a7aa2a65a
commit
9f78639690
28 changed files with 350 additions and 80 deletions
134
backend/src/controllers/course.controller.ts
Normal file
134
backend/src/controllers/course.controller.ts
Normal file
|
@ -0,0 +1,134 @@
|
|||
import { Count, CountSchema, Filter, FilterExcludingWhere, repository, Where, } from '@loopback/repository';
|
||||
import { del, get, getModelSchemaRef, param, patch, post, put, requestBody, response, } from '@loopback/rest';
|
||||
import { Course } from '../models';
|
||||
import { CourseRepository } from '../repositories';
|
||||
|
||||
export class CourseController {
|
||||
constructor(
|
||||
@repository(CourseRepository)
|
||||
public courseRepository: CourseRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
@post('/courses')
|
||||
@response(200, {
|
||||
description: 'Course model instance',
|
||||
content: {'application/json': {schema: getModelSchemaRef(Course)}},
|
||||
})
|
||||
async create(
|
||||
@requestBody({
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(Course, {
|
||||
title: 'NewCourse',
|
||||
exclude: ['id'],
|
||||
}),
|
||||
},
|
||||
},
|
||||
})
|
||||
course: Omit<Course, 'id'>,
|
||||
): Promise<Course> {
|
||||
return this.courseRepository.create(course);
|
||||
}
|
||||
|
||||
@get('/courses/count')
|
||||
@response(200, {
|
||||
description: 'Course model count',
|
||||
content: {'application/json': {schema: CountSchema}},
|
||||
})
|
||||
async count(
|
||||
@param.where(Course) where?: Where<Course>,
|
||||
): Promise<Count> {
|
||||
return this.courseRepository.count(where);
|
||||
}
|
||||
|
||||
@get('/courses')
|
||||
@response(200, {
|
||||
description: 'Array of Course model instances',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'array',
|
||||
items: getModelSchemaRef(Course, {includeRelations: true}),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
async find(
|
||||
@param.filter(Course) filter?: Filter<Course>,
|
||||
): Promise<Course[]> {
|
||||
return this.courseRepository.find(filter);
|
||||
}
|
||||
|
||||
@patch('/courses')
|
||||
@response(200, {
|
||||
description: 'Course PATCH success count',
|
||||
content: {'application/json': {schema: CountSchema}},
|
||||
})
|
||||
async updateAll(
|
||||
@requestBody({
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(Course, {partial: true}),
|
||||
},
|
||||
},
|
||||
})
|
||||
course: Course,
|
||||
@param.where(Course) where?: Where<Course>,
|
||||
): Promise<Count> {
|
||||
return this.courseRepository.updateAll(course, where);
|
||||
}
|
||||
|
||||
@get('/courses/{id}')
|
||||
@response(200, {
|
||||
description: 'Course model instance',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(Course, {includeRelations: true}),
|
||||
},
|
||||
},
|
||||
})
|
||||
async findById(
|
||||
@param.path.number('id') id: number,
|
||||
@param.filter(Course, {exclude: 'where'}) filter?: FilterExcludingWhere<Course>
|
||||
): Promise<Course> {
|
||||
return this.courseRepository.findById(id, filter);
|
||||
}
|
||||
|
||||
@patch('/courses/{id}')
|
||||
@response(204, {
|
||||
description: 'Course PATCH success',
|
||||
})
|
||||
async updateById(
|
||||
@param.path.number('id') id: number,
|
||||
@requestBody({
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: getModelSchemaRef(Course, {partial: true}),
|
||||
},
|
||||
},
|
||||
})
|
||||
course: Course,
|
||||
): Promise<void> {
|
||||
await this.courseRepository.updateById(id, course);
|
||||
}
|
||||
|
||||
@put('/courses/{id}')
|
||||
@response(204, {
|
||||
description: 'Course PUT success',
|
||||
})
|
||||
async replaceById(
|
||||
@param.path.number('id') id: number,
|
||||
@requestBody() course: Course,
|
||||
): Promise<void> {
|
||||
await this.courseRepository.replaceById(id, course);
|
||||
}
|
||||
|
||||
@del('/courses/{id}')
|
||||
@response(204, {
|
||||
description: 'Course DELETE success',
|
||||
})
|
||||
async deleteById(@param.path.number('id') id: number): Promise<void> {
|
||||
await this.courseRepository.deleteById(id);
|
||||
}
|
||||
}
|
|
@ -7,3 +7,4 @@ export * from './user-course.controller';
|
|||
export * from './course-requirement.controller';
|
||||
export * from './course-requirement.controller';
|
||||
export * from './subject.controller';
|
||||
export * from './course.controller';
|
||||
|
|
|
@ -1,24 +1,6 @@
|
|||
import {
|
||||
Count,
|
||||
CountSchema,
|
||||
Filter,
|
||||
repository,
|
||||
Where,
|
||||
} from '@loopback/repository';
|
||||
import {
|
||||
del,
|
||||
get,
|
||||
getModelSchemaRef,
|
||||
getWhereSchemaFor,
|
||||
param,
|
||||
patch,
|
||||
post,
|
||||
requestBody,
|
||||
} from '@loopback/rest';
|
||||
import {
|
||||
Subject,
|
||||
Course,
|
||||
} from '../models';
|
||||
import { Count, CountSchema, Filter, repository, Where, } from '@loopback/repository';
|
||||
import { del, get, getModelSchemaRef, getWhereSchemaFor, param, patch, post, requestBody, response, } from '@loopback/rest';
|
||||
import { Course, Subject, } from '../models';
|
||||
import { SubjectRepository } from '../repositories';
|
||||
|
||||
export class SubjectCourseController {
|
||||
|
@ -46,6 +28,18 @@ export class SubjectCourseController {
|
|||
return this.subjectRepository.courses(id).find(filter);
|
||||
}
|
||||
|
||||
@get('/subjects/{id}/courses/count')
|
||||
@response(200, {
|
||||
description: 'Course model count',
|
||||
content: {'application/json': {schema: CountSchema}},
|
||||
})
|
||||
async count(
|
||||
@param.path.number('id') id: number,
|
||||
@param.where(Course) where?: Where<Course>,
|
||||
): Promise<Count> {
|
||||
return this.subjectRepository.courses(id).count(where);
|
||||
}
|
||||
|
||||
@post('/subjects/{id}/courses', {
|
||||
responses: {
|
||||
'200': {
|
||||
|
|
29
backend/src/repositories/CustomHasManyRepository.ts
Normal file
29
backend/src/repositories/CustomHasManyRepository.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
import { constrainWhere, Count, DefaultHasManyRepository, Entity, EntityCrudRepository, Where } from '@loopback/repository';
|
||||
import { Options } from '@loopback/repository/src/common-types';
|
||||
import { HasManyRepository } from '@loopback/repository/src/relations/has-many/has-many.repository';
|
||||
import { InclusionResolver } from '@loopback/repository/src/relations/relation.types';
|
||||
|
||||
export interface CustomHasManyRepositoryFactory<Target extends Entity,
|
||||
ForeignKeyType,
|
||||
> {
|
||||
/**
|
||||
* Invoke the function to obtain HasManyRepository.
|
||||
*/
|
||||
(fkValue: ForeignKeyType): CustomHasManyRepository<Target>;
|
||||
|
||||
/**
|
||||
* Use `resolver` property to obtain an InclusionResolver for this relation.
|
||||
*/
|
||||
inclusionResolver: InclusionResolver<Entity, Target>;
|
||||
}
|
||||
|
||||
export interface CustomHasManyRepository<Target extends Entity> extends HasManyRepository<Target> {
|
||||
count(where?: Where<Target>, options?: Options): Promise<Count>;
|
||||
}
|
||||
|
||||
export class DefaultCustomHasManyRepository<TEntity extends Entity, TID, TRepository extends EntityCrudRepository<TEntity, TID>> extends DefaultHasManyRepository<TEntity, TID, TRepository> implements CustomHasManyRepository<TEntity> {
|
||||
async count(where?: Where<TEntity>, options?: Options) {
|
||||
const targetRepository = await this.getTargetRepository();
|
||||
return targetRepository.count(constrainWhere(where, this.constraint), options);
|
||||
}
|
||||
}
|
|
@ -1,21 +1,27 @@
|
|||
import { inject, Getter } from '@loopback/core';
|
||||
import { DefaultCrudRepository, repository, HasManyRepositoryFactory } from '@loopback/repository';
|
||||
import { Getter, inject } from '@loopback/core';
|
||||
import { DataObject, DefaultCrudRepository, repository } from '@loopback/repository';
|
||||
import { DatabaseDataSource } from '../datasources';
|
||||
import { Subject, SubjectRelations, Course } from '../models';
|
||||
import { Course, Subject, SubjectRelations } from '../models';
|
||||
import { UserRepository } from './user.repository';
|
||||
import { CourseRepository } from './course.repository';
|
||||
import { CustomHasManyRepositoryFactory, DefaultCustomHasManyRepository } from './CustomHasManyRepository';
|
||||
|
||||
export class SubjectRepository extends DefaultCrudRepository<Subject,
|
||||
typeof Subject.prototype.id,
|
||||
SubjectRelations> {
|
||||
|
||||
public readonly courses: HasManyRepositoryFactory<Course, typeof Subject.prototype.id>;
|
||||
public readonly courses: CustomHasManyRepositoryFactory<Course, typeof Subject.prototype.id>;
|
||||
|
||||
constructor(
|
||||
@inject('datasources.database') dataSource: DatabaseDataSource, @repository.getter('UserRepository') protected userRepositoryGetter: Getter<UserRepository>, @repository.getter('CourseRepository') protected courseRepositoryGetter: Getter<CourseRepository>,
|
||||
) {
|
||||
super(Subject, dataSource);
|
||||
this.courses = this.createHasManyRepositoryFactoryFor('courses', courseRepositoryGetter,);
|
||||
this.registerInclusionResolver('courses', this.courses.inclusionResolver);
|
||||
const origCourses = this.createHasManyRepositoryFactoryFor('courses', courseRepositoryGetter,);
|
||||
this.registerInclusionResolver('courses', origCourses.inclusionResolver);
|
||||
const courses = function(fkValue: number | undefined) {
|
||||
return new DefaultCustomHasManyRepository(courseRepositoryGetter, {subject_id: fkValue} as DataObject<Course>);
|
||||
};
|
||||
courses.inclusionResolver = origCourses.inclusionResolver;
|
||||
this.courses = courses;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,11 +59,10 @@ export class SzakdolgozatUserService implements UserService<User, Credentials> {
|
|||
|
||||
//function to find user by id
|
||||
async findUserById(id: number): Promise<User & UserWithRelations> {
|
||||
const userNotfound = 'invalid user';
|
||||
const foundUser = await this.userRepository.findById(id);
|
||||
|
||||
if (!foundUser) {
|
||||
throw new HttpErrors.Unauthorized(userNotfound);
|
||||
throw new HttpErrors.Unauthorized('invalid user');
|
||||
}
|
||||
return foundUser;
|
||||
}
|
||||
|
|
|
@ -1,14 +1,24 @@
|
|||
# Szakdolgozat
|
||||
|
||||
Egy webalkalmazás, amely nyomonköveti egy-egy kurzus követelményeinek teljesitését oktatók és hallgatók számára.
|
||||
|
||||
## Adatok
|
||||
|
||||
### Kurzus
|
||||
|
||||
Egy kurzus egy adott tárgy egy adott félévben egy adott csoporttal.
|
||||
|
||||
## Szerepkörök
|
||||
|
||||
Csak bejelentkezett felhasználók férhetnek hozzá bármilyen adathoz. A saját adataikat mindig tudják módositani.
|
||||
|
||||
### Admin
|
||||
|
||||
* Teljes jogosultsága van az adatokhoz, kivéve a felhasználók adatait
|
||||
* Hozzá tud rendelni más felhasználókat szerepkörökhöz egy-egy kurzus kapcsán
|
||||
|
||||
### Hallgató
|
||||
|
||||
* Az adott kurzushoz tartozó adatokat csak megtekinteni tudja
|
||||
|
||||
### Oktató
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
{
|
||||
"firestore": {
|
||||
"rules": "firestore.rules",
|
||||
"indexes": "firestore.indexes.json"
|
||||
},
|
||||
"hosting": {
|
||||
"public": "dist/Szakdolgozat",
|
||||
"ignore": [
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"indexes": [],
|
||||
"fieldOverrides": []
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
rules_version = '2';
|
||||
service cloud.firestore {
|
||||
match /databases/{database}/documents {
|
||||
function sameUser(user) {
|
||||
return request.auth != null && request.auth.uid == user;
|
||||
}
|
||||
function getUserData() {
|
||||
return get(/databases/$(database)/documents/users/$(request.auth.uid)).data;
|
||||
}
|
||||
|
||||
//Felhasználói adatok kezelése
|
||||
match /users/{user} {
|
||||
allow read, write: if sameUser(user) && request.auth.uid == request.resource.data.author_uid;
|
||||
}
|
||||
|
||||
//Adminisztrátoroknak mindent lehet
|
||||
match /data/{document=**} {
|
||||
allow get, list, create, update, delete: if auth.token.admin;
|
||||
}
|
||||
//Diákok megnézhetik a tárgy adatait
|
||||
match /data/subjects/{subject=**} {
|
||||
allow get, list: if request.auth.uid in resource.data.students;
|
||||
}
|
||||
//Az oktatók módosithatják a követelményeket
|
||||
match /data/subjects/{subject}/requirements/{requirement=**} {
|
||||
allow read, write: if request.auth.uid in resource.data.teachers;
|
||||
}
|
||||
}
|
||||
}
|
6
frontend/src/app/model/course.model.ts
Normal file
6
frontend/src/app/model/course.model.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { Model } from './model';
|
||||
|
||||
export class Course extends Model {
|
||||
semester: string;
|
||||
subjectId: number;
|
||||
}
|
|
@ -18,6 +18,10 @@ export class EditComponent<T extends Model> implements OnInit {
|
|||
@Input() apiPath: string;
|
||||
@Input() fields: { title: string, name: keyof T, readonly?: (item: T) => boolean }[];
|
||||
@Input() itemType: Type<T>;
|
||||
/**
|
||||
* Beküldés előtt extra adat hozzáadása
|
||||
*/
|
||||
@Input() beforeSubmit: (item: T) => Partial<T>;
|
||||
formGroup: FormGroup;
|
||||
|
||||
constructor(private api: ApiService, private router: Router, private fb: FormBuilder, private route: ActivatedRoute) {
|
||||
|
@ -48,13 +52,14 @@ export class EditComponent<T extends Model> implements OnInit {
|
|||
|
||||
async submit(): Promise<void> {
|
||||
this.isLoading = true;
|
||||
const value = Object.assign({}, this.formGroup.value, this.beforeSubmit(this.item) ?? {});
|
||||
try {
|
||||
if (this.item && !this.creating) {
|
||||
await this.api.request('patch', this.apiPath + '/' + this.item.id, this.formGroup.value);
|
||||
await this.api.request('patch', this.apiPath + '/' + this.item.id, value);
|
||||
} else {
|
||||
await this.api.request('post', this.apiPath, this.formGroup.value);
|
||||
await this.api.request('post', this.apiPath, value);
|
||||
}
|
||||
await this.router.navigate(this.route.parent.snapshot.url.map(segment => segment.path));
|
||||
await this.router.navigate(['..'], {relativeTo: this.route});
|
||||
} catch (e) {
|
||||
alert(e.message);
|
||||
}
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
<button mat-raised-button color="primary" (click)="newItem()">Hozzáadás</button>
|
||||
</div>
|
||||
<app-table [items]="items" (pageChange)="handlePageChange($event)" [paginationData]="paginationData" [columns]="columns"
|
||||
[loading]="loading" (editItem)="editItem($event)">
|
||||
[loading]="loading" (editItem)="editItem($event)" [customActions]="customActions"
|
||||
[allowEditing]="allowEditing">
|
||||
</app-table>
|
||||
|
|
|
@ -16,6 +16,8 @@ export class ListComponent<T extends Model> implements OnInit {
|
|||
@Input() itemType: Type<T>;
|
||||
@Input() columns: { title: string, prop: keyof T }[];
|
||||
@Input() allowNew = false;
|
||||
@Input() customActions: { icon: string, label: string, action: (model: T) => void }[] = [];
|
||||
@Input() allowEditing = true;
|
||||
|
||||
paginationData: PaginationData = {};
|
||||
items: T[] = [];
|
||||
|
|
|
@ -12,6 +12,7 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
|
||||
|
||||
@NgModule({
|
||||
|
@ -31,7 +32,8 @@ import { MatCheckboxModule } from '@angular/material/checkbox';
|
|||
MatProgressSpinnerModule,
|
||||
ReactiveFormsModule,
|
||||
MatInputModule,
|
||||
MatCheckboxModule
|
||||
MatCheckboxModule,
|
||||
MatTooltipModule
|
||||
]
|
||||
})
|
||||
export class SharedComponentsModule {
|
||||
|
|
|
@ -18,15 +18,18 @@
|
|||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions" stickyEnd>
|
||||
<th mat-header-cell *matHeaderCellDef style="width: 2rem"></th>
|
||||
<th mat-header-cell *matHeaderCellDef [style.width]="2.5 * (1 + customActions.length) + 'rem'"></th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<button mat-icon-button color="primary" (click)="editItem.emit(item)">
|
||||
<button *ngIf="allowEditing" mat-icon-button color="primary" (click)="editItem.emit(item)">
|
||||
<mat-icon>edit</mat-icon>
|
||||
</button>
|
||||
<button *ngFor="let action of customActions" mat-icon-button color="primary" (click)="action.action(item)">
|
||||
<mat-icon [matTooltip]="action.label">{{ action.icon }}</mat-icon>
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
<tr mat-header-row *matHeaderRowDef="getPropNames()"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: getPropNames()"></tr>
|
||||
</ng-container>
|
||||
</table>
|
||||
</div>
|
||||
<mat-paginator
|
||||
|
|
|
@ -14,6 +14,8 @@ export class TableComponent<T> implements OnInit {
|
|||
@Input() loading = false;
|
||||
@Input() columns: { title: string, prop: string }[] = [];
|
||||
@Input() paginationData: PaginationData = {page: 1, limit: 10};
|
||||
@Input() customActions: { icon: string, label: string, action: (model: T) => void }[] = [];
|
||||
@Input() allowEditing = true;
|
||||
|
||||
@Output() pageChange = new EventEmitter<PageEvent>();
|
||||
@Output() editItem = new EventEmitter<T>();
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<app-edit #edit [itemType]="itemType" apiPath="/courses" [beforeSubmit]="beforeSubmit" [fields]="[
|
||||
{title: 'Félév', name: 'semester'}
|
||||
]"></app-edit>
|
|
@ -0,0 +1,25 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CourseEditComponent } from './course-edit.component';
|
||||
|
||||
describe('CourseEditComponent', () => {
|
||||
let component: CourseEditComponent;
|
||||
let fixture: ComponentFixture<CourseEditComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [CourseEditComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CourseEditComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,20 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Course } from '../../../../model/course.model';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-course-edit',
|
||||
templateUrl: './course-edit.component.html',
|
||||
styleUrls: ['./course-edit.component.css']
|
||||
})
|
||||
export class CourseEditComponent implements OnInit {
|
||||
itemType = Course;
|
||||
beforeSubmit = () => ({subjectId: +this.route.snapshot.params.subjectId});
|
||||
|
||||
constructor(private route: ActivatedRoute) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
<app-list [apiPath]="'/subjects/'+subjectId+'/courses'" [itemType]="itemType" allowNew="true" [columns]="[
|
||||
{prop: 'semester', title: 'Félév'}
|
||||
]"></app-list>
|
|
@ -0,0 +1,25 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CourseListComponent } from './course-list.component';
|
||||
|
||||
describe('CoursesComponent', () => {
|
||||
let component: CourseListComponent;
|
||||
let fixture: ComponentFixture<CourseListComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [CourseListComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CourseListComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,21 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Course } from '../../../../model/course.model';
|
||||
|
||||
@Component({
|
||||
selector: 'app-courses',
|
||||
templateUrl: './course-list.component.html',
|
||||
styleUrls: ['./course-list.component.css']
|
||||
})
|
||||
export class CourseListComponent implements OnInit {
|
||||
subjectId: string;
|
||||
itemType = Course;
|
||||
|
||||
constructor(route: ActivatedRoute) {
|
||||
this.subjectId = route.snapshot.params.subjectId;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
<app-list apiPath="/subjects" [itemType]="itemType" allowNew="true" [columns]="[
|
||||
{title: 'Név', prop: 'name'},
|
||||
{title: 'Leirás', prop: 'description'}
|
||||
]" [customActions]="[
|
||||
{icon: 'chevron_right', label: 'Kurzusok', action: listCourses}
|
||||
]"></app-list>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Subject } from '../../model/subject.model';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-subject-list',
|
||||
|
@ -9,9 +10,14 @@ import { Subject } from '../../model/subject.model';
|
|||
export class SubjectListComponent implements OnInit {
|
||||
itemType = Subject;
|
||||
|
||||
constructor() { }
|
||||
constructor(private route: ActivatedRoute, private router: Router) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
listCourses = (subject: Subject): void => {
|
||||
this.router.navigate([subject.id, 'courses'], {relativeTo: this.route});
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -5,14 +5,22 @@ import { SubjectEditComponent } from './subject-edit/subject-edit.component';
|
|||
import { SharedComponentsModule } from '../shared-components/shared-components.module';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { RouteData } from '../app-routing.module';
|
||||
import { CourseListComponent } from './subject-edit/courses/course-list/course-list.component';
|
||||
import { CourseEditComponent } from './subject-edit/courses/course-edit/course-edit.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{path: '', component: SubjectListComponent, data: {title: 'Tárgyak'} as RouteData},
|
||||
{path: ':id', component: SubjectEditComponent, data: {title: 'Szerkesztés'}}
|
||||
{path: ':id', component: SubjectEditComponent, data: {title: 'Szerkesztés'}},
|
||||
{
|
||||
path: ':subjectId/courses', children: [
|
||||
{path: ':id', component: CourseEditComponent, data: {title: 'Szerkesztés'} as RouteData},
|
||||
{path: '', component: CourseListComponent, data: {title: 'Kurzusok'}}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
declarations: [SubjectListComponent, SubjectEditComponent],
|
||||
declarations: [SubjectListComponent, SubjectEditComponent, CourseListComponent, CourseEditComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
SharedComponentsModule,
|
||||
|
|
Loading…
Reference in a new issue