Skip to content
This repository was archived by the owner on Apr 16, 2024. It is now read-only.

Creating new unit types

Torsten Schlett edited this page May 24, 2018 · 9 revisions

The following steps must be taken to correctly implement a new type of unit:

Step 1 - Base interface

Create a new interface in /shared/models/units extending the unit base interface IUnit. Assuming your unit would be called example this could look like this:

import {IUnit} from './IUnit';

export interface IExampleUnit extends IUnit {
  unitData1: string;
  unitData2: number;
}

Step 2 - API schema and interface

Create a file for the mongoose schema and the document model interface for your unit in /api/src/models/units. The interface extends your previous interface from step 1 and mongoose.Document. The mongoose schema in your file contains the additional data you defined in your interface from step 1. Your defined schema gets attached to the unit schema using a discriminator after definition.

Following the example from before your file would look like this:

import * as mongoose from 'mongoose';
import {Unit} from './Unit';
import {IExampleUnit} from '../../../../shared/models/units/IExampleUnit';

interface IExampleUnitModel extends IExampleUnit, mongoose.Document {
}

const exampleUnitSchema = new mongoose.Schema({
  unitData1: {
    type: String,
  },
  unitData2: {
    type: number
  }
});

const ExampleUnit = Unit.discriminator('example', exampleUnitSchema);

export {ExampleUnit, IExampleUnitModel}

Step 3 - API controller

Step 4 - Frontend interface implementation

Implement your interface in the angular frontend. Create the implementation file in /app/webFrontend/src/app/models. Here you have to decide if your unit will be progressable, which means that your unit is able to provide a challenge for students. For the example unit this implementation would look something like this:

import {ICourse} from '../../../../../shared/models/ICourse';
import {IExampleUnit} from '../../../../../shared/models/units/IExampleUnit';

export class ExampleUnit implements IExampleUnit {
  name: string;
  description: string;
  updatedAt: string;
  createdAt: string;
  _course: any;
  _id: any;
  type: string;
  progressable: boolean;
  weight: number;

  unitData1: string;
  unitData2: number;

  constructor(_course: ICourse) {
    this._course = _course;
    this.progressable = false; // this.progressable = true; if this unit is progressable
    this.weight = 0;
  }
}

Step 5 - Using the unit in the frontend

Creating new Unit-Form type

  1. Create your-type component in the unit-form directory for the teachers' editor and another your-type component for the students' view in the unit directory above.
    1. Inject UnitFormService and FormBuilder in constructor.
    2. Use unitFormService.headline to set the headline and unitFormService.unitInfoText for info text, both displayed by the unit-general-info-form component.
  2. Add new type to createNewUnit in unit-factory.service.ts.
  3. (Optional) IF you want to add extra buttons (e.g. fullscreen for the 'free-text' type) include your-type in unit-form.component.ts as ViewChild (see the existing components).
    1. Add Button (important: type="button", ng-if to your type) below in app-button-save-cancel your desired position.
    2. Connect your button action with ViewChild. E.g.: (click)="freeTextUnitFormComponent.openFullscreen()
  4. Include your-type in the unit-form.component.html (ng-if type) and pass any parameters you need.
  5. Register your-type controls in your-type.ts (e.g. this.unitForm.addControl('my_control_name', new FormControl(this.model.MYFIELD)); (this.model is your type model) and pass model.field as default value. (Think about form-validation, and read Angular Reactive Forms.)
  6. In your-type.component.html write your form within an element with [formGroup]="unitForm", e.g.: <ng-container [formGroup]="unitForm">...</ng-container>
  7. Write your form-html, form fields: formControlName="my_control_name"
  8. (Optional) If you want actions (e.g validation) before submit, use an async function unitFormService.beforeSubmit = async () => {/*my checks here*/}. By returning false, the submit will canceled.

Architecture:

<unit-form> <!-- holds the unitForm -->
    <general-info-form/> <!-- for headline, name, description, visibility -->
    <type-specific-form/> <!-- place everything type specific here -->
    <buttons> <!-- create custom buttons on bottom of form -->
        <left>  <!-- left position from save/cancel --> </left>
        <right> <!-- right from save/cancel --> </right>
    </buttons>
</unit-form>

Note that this is pseudo-html, see existing components for concrete examples.

Additional steps for progressable units

Clone this wiki locally