implemented sample references
This commit is contained in:
@ -10,7 +10,7 @@
|
||||
<ng-template rbFormValidationMessage="required">Cannot be empty</ng-template>
|
||||
<ng-template rbFormValidationMessage="failure">Unknown material, add properties for new material</ng-template>
|
||||
</rb-form-input>
|
||||
<button class="rb-btn rb-secondary" type="button" (click)="setNewMaterial(true)"><span class="rb-ic rb-ic-add"></span> New material</button>
|
||||
<button class="rb-btn rb-secondary" type="button" (click)="setNewMaterial(!newMaterial)"><span class="rb-ic rb-ic-add"></span> New material</button>
|
||||
</div>
|
||||
|
||||
<div class="material shaded-container" *ngIf="newMaterial" [@inOut]>
|
||||
@ -21,30 +21,16 @@
|
||||
<rb-form-input name="group" label="group" [rbFormInputAutocomplete]="autocomplete.bind(this, groups)" [rbDebounceTime]="0" [rbInitialOpen]="true" appValidate="string" required [(ngModel)]="material.group" #groupInput="ngModel">
|
||||
<ng-template rbFormValidationMessage="failure">{{groupInput.errors.failure}}</ng-template>
|
||||
</rb-form-input>
|
||||
<rb-form-input name="mineral" label="mineral" type="number" required rbNumberConverter rbMin="0" rbMax="100" [(ngModel)]="material.mineral" ngModel>
|
||||
<ng-template rbFormValidationMessage="required">Invalid value</ng-template>
|
||||
<ng-template rbFormValidationMessage="rbMin">Minimum value is 0</ng-template>
|
||||
<ng-template rbFormValidationMessage="rbMax">Maximum value is 100</ng-template>
|
||||
</rb-form-input>
|
||||
<rb-form-input name="glass_fiber" label="glass_fiber" type="number" required rbNumberConverter rbMin="0" rbMax="100" [(ngModel)]="material.glass_fiber" ngModel>
|
||||
<ng-template rbFormValidationMessage="required">Invalid value</ng-template>
|
||||
<ng-template rbFormValidationMessage="rbMin">Minimum value is 0</ng-template>
|
||||
<ng-template rbFormValidationMessage="rbMax">Maximum value is 100</ng-template>
|
||||
</rb-form-input>
|
||||
<rb-form-input name="carbon_fiber" label="carbon_fiber" type="number" required rbNumberConverter rbMin="0" rbMax="100" [(ngModel)]="material.carbon_fiber" ngModel>
|
||||
<ng-template rbFormValidationMessage="required">Invalid value</ng-template>
|
||||
<ng-template rbFormValidationMessage="rbMin">Minimum value is 0</ng-template>
|
||||
<ng-template rbFormValidationMessage="rbMax">Maximum value is 100</ng-template>
|
||||
</rb-form-input>
|
||||
|
||||
<div class="material-numbers">
|
||||
<div *ngFor="let number of material.numbers; index as i" class="two-col" [@inOut]>
|
||||
<rb-form-input label="color" appValidate="string" [required]="i < material.numbers.length - 1" (keyup)="handleMaterialNumbers()" [(ngModel)]="number.color" ngModel [ngModelOptions]="{standalone: true}">
|
||||
</rb-form-input>
|
||||
<rb-form-input label="material number" appValidate="string" [(ngModel)]="number.number" ngModel [ngModelOptions]="{standalone: true}">
|
||||
</rb-form-input>
|
||||
</div>
|
||||
<rb-form-input *ngFor="let ignore of [].constructor(material.numbers.length); index as i" label="material number" appValidate="string" [name]="'material.number-' + i" (keyup)="handleMaterialNumbers()" [(ngModel)]="material.numbers[i]" ngModel></rb-form-input>
|
||||
</div>
|
||||
<rb-form-select name="conditionSelect" label="Condition" (ngModelChange)="selectMaterialTemplate($event)" [ngModel]="material.properties.material_template">
|
||||
<option *ngFor="let m of materialTemplates" [value]="m._id">{{m.name}}</option>
|
||||
</rb-form-select>
|
||||
<rb-form-input *ngFor="let parameter of materialTemplate.parameters; index as i" [name]="'materialParameter' + i" [label]="parameter.name" appValidate="string" required [(ngModel)]="material.properties[parameter.name]" #parameterInput="ngModel">
|
||||
<ng-template rbFormValidationMessage="failure">{{parameterInput.errors.failure}}</ng-template>
|
||||
<ng-template rbFormValidationMessage="required">Cannot be empty</ng-template>
|
||||
</rb-form-input>
|
||||
</div>
|
||||
|
||||
|
||||
@ -54,7 +40,7 @@
|
||||
<ng-template rbFormValidationMessage="failure">{{typeInput.errors.failure}}</ng-template>
|
||||
<ng-template rbFormValidationMessage="required">Cannot be empty</ng-template>
|
||||
</rb-form-input>
|
||||
<rb-form-input name="color" label="color" [rbFormInputAutocomplete]="autocomplete.bind(this, getColors(material))" [rbDebounceTime]="0" [rbInitialOpen]="true" appValidate="stringOf" [appValidateArgs]="[getColors(material)]" required [(ngModel)]="sample.color" #colorInput="ngModel">
|
||||
<rb-form-input name="color" label="color" appValidate="string" required [(ngModel)]="sample.color" #colorInput="ngModel">
|
||||
<ng-template rbFormValidationMessage="failure">{{colorInput.errors.failure}}</ng-template>
|
||||
<ng-template rbFormValidationMessage="required">Cannot be empty</ng-template>
|
||||
</rb-form-input>
|
||||
@ -68,6 +54,17 @@
|
||||
<rb-form-input name="comment" label="comment" appValidate="stringLength" [appValidateArgs]="[512]" [(ngModel)]="sample.notes.comment" #commentInput="ngModel">
|
||||
<ng-template rbFormValidationMessage="failure">{{commentInput.errors.failure}}</ng-template>
|
||||
</rb-form-input>
|
||||
<h5>Sample references</h5>
|
||||
<div *ngFor="let reference of sampleReferences; index as i" class="two-col" [@inOut]>
|
||||
<div>
|
||||
<rb-form-input [name]="'sr-id' + i" label="sample number" [rbFormInputAutocomplete]="sampleReferenceListBind()" [rbDebounceTime]="300" appValidate="stringOf" [appValidateArgs]="[sampleReferenceAutocomplete[i]]" (ngModelChange)="checkSampleReference($event, i)" [ngModel]="reference[0]" #idInput="ngModel">
|
||||
<ng-template rbFormValidationMessage="failure">Unknown sample number</ng-template>
|
||||
</rb-form-input>
|
||||
</div>
|
||||
<rb-form-input [name]="'sr-relation' + i" label="relation" appValidate="string" [required]="reference[0] !== ''" [(ngModel)]="reference[1]">
|
||||
<ng-template rbFormValidationMessage="required">Cannot be empty</ng-template>
|
||||
</rb-form-input>
|
||||
</div>
|
||||
<h5>Additional properties</h5>
|
||||
<div *ngFor="let field of customFields; index as i" class="two-col" [@inOut]>
|
||||
<div>
|
||||
@ -79,7 +76,6 @@
|
||||
<ng-template rbFormValidationMessage="required">Cannot be empty</ng-template>
|
||||
</rb-form-input>
|
||||
</div>
|
||||
<!-- TODO: Sample reference-->
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -16,6 +16,7 @@ import {TemplateModel} from '../models/template.model';
|
||||
import {MeasurementModel} from '../models/measurement.model';
|
||||
import { ChartOptions } from 'chart.js';
|
||||
import {animate, style, transition, trigger} from '@angular/animations';
|
||||
import {Observable} from 'rxjs';
|
||||
|
||||
// TODO: tests
|
||||
// TODO: confirmation for new group/supplier
|
||||
@ -24,6 +25,9 @@ import {animate, style, transition, trigger} from '@angular/animations';
|
||||
// TODO: multiple spectra
|
||||
// TODO: multiple samples for base data, extend multiple measurements, conditions
|
||||
|
||||
// TODO: material properties, color (in material and sample (not required))
|
||||
|
||||
// TODO: API $in Regex
|
||||
|
||||
@Component({
|
||||
selector: 'app-sample',
|
||||
@ -55,11 +59,17 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
groups: string[] = []; // all groups
|
||||
conditionTemplates: TemplateModel[]; // all conditions
|
||||
condition: TemplateModel | null = null; // selected condition
|
||||
materialTemplates: TemplateModel[]; // all material templates
|
||||
materialTemplate: TemplateModel | null = null; // selected material template
|
||||
materialNames = []; // names of all materials
|
||||
material = new MaterialModel(); // object of current selected material
|
||||
sample = new SampleModel();
|
||||
customFields: [string, string][] = [['', '']];
|
||||
sampleReferences: [string, string, string][] = [['', '', '']];
|
||||
sampleReferenceFinds: {_id: string, number: string}[] = []; // raw sample reference data from db
|
||||
currentSRIndex = 0; // index of last entered sample reference
|
||||
availableCustomFields: string[] = [];
|
||||
sampleReferenceAutocomplete: string[][] = [[]];
|
||||
responseData: SampleModel; // gets filled with response data after saving the sample
|
||||
measurementTemplates: TemplateModel[];
|
||||
loading = 0; // number of currently loading instances
|
||||
@ -96,7 +106,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
|
||||
ngOnInit(): void {
|
||||
this.new = this.router.url === '/samples/new';
|
||||
this.loading = 6;
|
||||
this.loading = 7;
|
||||
this.api.get<MaterialModel[]>('/materials?status=all', (data: any) => {
|
||||
this.materials = data.map(e => new MaterialModel().deserialize(e));
|
||||
this.materialNames = data.map(e => e.name);
|
||||
@ -114,41 +124,63 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
this.conditionTemplates = data.map(e => new TemplateModel().deserialize(e));
|
||||
this.loading--;
|
||||
});
|
||||
this.api.get<TemplateModel[]>('/template/materials', data => {
|
||||
this.materialTemplates = data.map(e => new TemplateModel().deserialize(e));
|
||||
this.selectMaterialTemplate(this.materialTemplates[0]._id);
|
||||
this.loading--;
|
||||
});
|
||||
this.api.get<TemplateModel[]>('/template/measurements', data => {
|
||||
this.measurementTemplates = data.map(e => new TemplateModel().deserialize(e));
|
||||
if (!this.new) {
|
||||
this.loading++;
|
||||
this.api.get<SampleModel>('/sample/' + this.route.snapshot.paramMap.get('id'), sData => {
|
||||
this.sample.deserialize(sData);
|
||||
this.charts = [];
|
||||
const spectrumTemplate = this.measurementTemplates.find(e => e.name === 'spectrum')._id;
|
||||
let spectrumCounter = 0;
|
||||
this.sample.measurements.forEach((measurement, i) => {
|
||||
this.charts.push(_.cloneDeep(this.chartInit));
|
||||
if (measurement.measurement_template === spectrumTemplate) {
|
||||
setTimeout(() => {
|
||||
this.generateChart(measurement.values.dpt, i);
|
||||
console.log(this.charts);
|
||||
}, spectrumCounter * 20);
|
||||
spectrumCounter ++;
|
||||
}
|
||||
});
|
||||
this.material = sData.material;
|
||||
this.customFields = this.sample.notes.custom_fields && this.sample.notes.custom_fields !== {} ? Object.keys(this.sample.notes.custom_fields).map(e => [e, this.sample.notes.custom_fields[e]]) : [['', '']];
|
||||
if (this.sample.notes.sample_references.length) {
|
||||
this.sampleReferences = [];
|
||||
this.sampleReferenceAutocomplete = [];
|
||||
let loadCounter = this.sample.notes.sample_references.length;
|
||||
this.sample.notes.sample_references.forEach(reference => {
|
||||
this.api.get<SampleModel>('/sample/' + reference.sample_id, srData => {
|
||||
this.sampleReferences.push([srData.number, reference.relation, reference.sample_id]);
|
||||
this.sampleReferenceAutocomplete.push([srData.number]);
|
||||
if (!--loadCounter) {
|
||||
this.sampleReferences.push(['', '', '']);
|
||||
this.sampleReferenceAutocomplete.push([]);
|
||||
console.log(this.sampleReferences);
|
||||
console.log(this.sampleReferenceAutocomplete);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
if ('condition_template' in this.sample.condition) {
|
||||
this.selectCondition(this.sample.condition.condition_template);
|
||||
}
|
||||
console.log('data loaded');
|
||||
this.loading--;
|
||||
this.checkFormAfterInit = true;
|
||||
});
|
||||
}
|
||||
this.loading--;
|
||||
});
|
||||
this.api.get<TemplateModel[]>('/sample/notes/fields', data => {
|
||||
this.availableCustomFields = data.map(e => e.name);
|
||||
this.loading--;
|
||||
});
|
||||
if (!this.new) {
|
||||
this.loading++;
|
||||
this.api.get<SampleModel>('/sample/' + this.route.snapshot.paramMap.get('id'), sData => {
|
||||
this.sample.deserialize(sData);
|
||||
this.charts = [];
|
||||
const spectrumTemplate = this.measurementTemplates.find(e => e.name === 'spectrum')._id;
|
||||
let spectrumCounter = 0;
|
||||
this.sample.measurements.forEach((measurement, i) => {
|
||||
this.charts.push(_.cloneDeep(this.chartInit));
|
||||
if (measurement.measurement_template === spectrumTemplate) {
|
||||
setTimeout(() => {
|
||||
this.generateChart(measurement.values.dpt, i);
|
||||
console.log(this.charts);
|
||||
}, spectrumCounter * 20);
|
||||
spectrumCounter ++;
|
||||
}
|
||||
});
|
||||
this.material = sData.material;
|
||||
this.customFields = this.sample.notes.custom_fields && this.sample.notes.custom_fields !== {} ? Object.keys(this.sample.notes.custom_fields).map(e => [e, this.sample.notes.custom_fields[e]]) : [['', '']];
|
||||
if ('condition_template' in this.sample.condition) {
|
||||
this.selectCondition(this.sample.condition.condition_template);
|
||||
}
|
||||
console.log('data loaded');
|
||||
this.loading--;
|
||||
this.checkFormAfterInit = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterContentChecked() {
|
||||
@ -161,6 +193,15 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
}
|
||||
}
|
||||
|
||||
// attach validators to dynamic material fields when all values are available and template was fully created
|
||||
if (this.materialTemplate && this.materialTemplate.hasOwnProperty('parameters') && this.materialTemplate.parameters.length > 0 && this.materialTemplate.parameters[0].hasOwnProperty('range') && this.sampleForm && this.sampleForm.form.get('materialParameter0')) {
|
||||
for (const i in this.materialTemplate.parameters) {
|
||||
if (this.materialTemplate.parameters[i]) {
|
||||
this.attachValidator('materialParameter' + i, this.materialTemplate.parameters[i].range, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.sampleForm && this.sampleForm.form.get('measurementParameter0-0')) {
|
||||
this.sample.measurements.forEach((measurement, mIndex) => {
|
||||
const template = this.getMeasurementTemplate(measurement.measurement_template);
|
||||
@ -209,11 +250,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
saveSample() {
|
||||
new Promise<void>(resolve => {
|
||||
if (this.newMaterial) { // save material first if new one exists
|
||||
for (const i in this.material.numbers) { // remove empty numbers fields
|
||||
if (this.material.numbers[i].color === '') {
|
||||
this.material.numbers.splice(i as any as number, 1);
|
||||
}
|
||||
}
|
||||
this.material.numbers = this.material.numbers.filter(e => e !== '');
|
||||
this.api.post<MaterialModel>('/material/new', this.material.sendFormat(), data => {
|
||||
this.materials.push(data); // add material to data
|
||||
this.material = data;
|
||||
@ -231,6 +268,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
this.sample.notes.custom_fields[element[0]] = element[1];
|
||||
}
|
||||
});
|
||||
this.sample.notes.sample_references = this.sampleReferences.filter(e => e[0] && e[1] && e[2]).map(e => ({sample_id: e[2], relation: e[1]}));
|
||||
new Promise<SampleModel>(resolve => {
|
||||
if (this.new) {
|
||||
this.api.post<SampleModel>('/sample/new', this.sample.sendFormat(), resolve);
|
||||
@ -269,6 +307,9 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
this.sample.material_id = this.material._id;
|
||||
}
|
||||
else {
|
||||
if (this.sample.material_id !== null) { // reset previous match
|
||||
this.material = new MaterialModel();
|
||||
}
|
||||
this.sample.material_id = null;
|
||||
}
|
||||
this.setNewMaterial();
|
||||
@ -280,16 +321,12 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
}
|
||||
}
|
||||
|
||||
getColors(material) {
|
||||
return material ? material.numbers.map(e => e.color) : [];
|
||||
}
|
||||
|
||||
// TODO: rework later
|
||||
setNewMaterial(value = null) {
|
||||
if (value === null) {
|
||||
this.newMaterial = !this.sample.material_id;
|
||||
}
|
||||
else {
|
||||
else if (value || (!value && this.sample.material_id !== null )) { // set to false only if material already exists
|
||||
this.newMaterial = value;
|
||||
}
|
||||
if (this.newMaterial) {
|
||||
@ -303,19 +340,14 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
|
||||
handleMaterialNumbers() {
|
||||
const fieldNo = this.material.numbers.length;
|
||||
let filledFields = 0;
|
||||
this.material.numbers.forEach(mNumber => {
|
||||
if (mNumber.color !== '') {
|
||||
filledFields ++;
|
||||
}
|
||||
});
|
||||
const filledFields = this.material.numbers.filter(e => e !== '').length;
|
||||
// append new field
|
||||
if (filledFields === fieldNo) {
|
||||
this.material.addNumber();
|
||||
this.material.numbers.push('');
|
||||
}
|
||||
// remove if two end fields are empty
|
||||
if (fieldNo > 1 && this.material.numbers[fieldNo - 1].color === '' && this.material.numbers[fieldNo - 2].color === '') {
|
||||
this.material.popNumber();
|
||||
if (fieldNo > 1 && this.material.numbers[fieldNo - 1] === '' && this.material.numbers[fieldNo - 2] === '') {
|
||||
this.material.numbers.pop();
|
||||
}
|
||||
}
|
||||
|
||||
@ -328,6 +360,13 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
}
|
||||
}
|
||||
|
||||
selectMaterialTemplate(id) {
|
||||
this.materialTemplate = this.materialTemplates.find(e => e._id === id);
|
||||
if ('material_template' in this.material.properties) {
|
||||
this.material.properties.material_template = id;
|
||||
}
|
||||
}
|
||||
|
||||
getMeasurementTemplate(id): TemplateModel {
|
||||
return this.measurementTemplates && id ? this.measurementTemplates.find(e => e._id === id) : new TemplateModel();
|
||||
}
|
||||
@ -391,6 +430,58 @@ export class SampleComponent implements OnInit, AfterContentChecked {
|
||||
}
|
||||
}
|
||||
|
||||
checkSampleReference(value, index) {
|
||||
if (value) {
|
||||
this.sampleReferences[index][0] = value;
|
||||
}
|
||||
this.currentSRIndex = index;
|
||||
const fieldNo = this.sampleReferences.length;
|
||||
let filledFields = 0;
|
||||
this.sampleReferences.forEach(field => {
|
||||
if (field[0] !== '') {
|
||||
filledFields ++;
|
||||
}
|
||||
});
|
||||
// append new field
|
||||
if (filledFields === fieldNo) {
|
||||
this.sampleReferences.push(['', '', '']);
|
||||
this.sampleReferenceAutocomplete.push([]);
|
||||
}
|
||||
// remove if two end fields are empty
|
||||
if (fieldNo > 1 && this.sampleReferences[fieldNo - 1][0] === '' && this.sampleReferences[fieldNo - 2][0] === '') {
|
||||
this.sampleReferences.pop();
|
||||
this.sampleReferenceAutocomplete.pop();
|
||||
}
|
||||
this.sampleReferenceIdFind(value);
|
||||
}
|
||||
|
||||
sampleReferenceList(value) {
|
||||
return new Observable(observer => {
|
||||
this.api.get<{_id: string, number: string}[]>('/samples?status=all&page-size=25&sort=number-asc&fields[]=number&fields[]=_id&filters[]=%7B%22mode%22%3A%22stringin%22%2C%22field%22%3A%22number%22%2C%22values%22%3A%5B%22' + value + '%22%5D%7D', data => {
|
||||
console.log(data);
|
||||
this.sampleReferenceAutocomplete[this.currentSRIndex] = data.map(e => e.number);
|
||||
this.sampleReferenceFinds = data;
|
||||
observer.next(data.map(e => e.number));
|
||||
observer.complete();
|
||||
this.sampleReferenceIdFind(value);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
sampleReferenceIdFind(value) {
|
||||
const idFind = this.sampleReferenceFinds.find(e => e.number === value);
|
||||
if (idFind) {
|
||||
this.sampleReferences[this.currentSRIndex][2] = idFind._id;
|
||||
}
|
||||
else {
|
||||
this.sampleReferences[this.currentSRIndex][2] = '';
|
||||
}
|
||||
}
|
||||
|
||||
sampleReferenceListBind() {
|
||||
return this.sampleReferenceList.bind(this);
|
||||
}
|
||||
|
||||
uniqueCfValues(index) { // returns all names until index for unique check
|
||||
return this.customFields.slice(0, index).map(e => e[0]);
|
||||
}
|
||||
|
Reference in New Issue
Block a user