mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-12 12:33:07 +00:00
added create-from functionality
This commit is contained in:
@@ -0,0 +1 @@
|
||||
<input type="hidden" value="true" name="boolean-value-{{index}}" id="boolean-value-{{index}}"/>
|
@@ -0,0 +1,32 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { BooleanValueInputComponent } from './boolean-value-input.component';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
|
||||
describe('BooleanValueInputComponent', () => {
|
||||
let component: BooleanValueInputComponent;
|
||||
let fixture: ComponentFixture<BooleanValueInputComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [BooleanValueInputComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(BooleanValueInputComponent);
|
||||
component = fixture.componentInstance;
|
||||
spyOn(component.updateValue, 'emit');
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should emit true onInit', () => {
|
||||
expect(component.updateValue.emit).toHaveBeenCalledWith(true);
|
||||
});
|
||||
});
|
@@ -0,0 +1,21 @@
|
||||
import { Component, OnInit, Optional } from '@angular/core';
|
||||
import { ValueInputComponent } from '../value-input.component';
|
||||
import { ControlContainer, NgForm } from '@angular/forms';
|
||||
import { controlContainerFactory } from '../../../process-form.component';
|
||||
|
||||
/**
|
||||
* Represents the value of a boolean parameter
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-boolean-value-input',
|
||||
templateUrl: './boolean-value-input.component.html',
|
||||
styleUrls: ['./boolean-value-input.component.scss'],
|
||||
viewProviders: [ { provide: ControlContainer,
|
||||
useFactory: controlContainerFactory,
|
||||
deps: [[new Optional(), NgForm]] } ]
|
||||
})
|
||||
export class BooleanValueInputComponent extends ValueInputComponent<boolean> implements OnInit {
|
||||
ngOnInit() {
|
||||
this.updateValue.emit(true)
|
||||
}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
<input required #string="ngModel" type="text" class="form-control" name="date-value-{{index}}" id="date-value-{{index}}" [ngModel]="value" (ngModelChange)="setValue($event)"/>
|
||||
<div *ngIf="string.invalid && (string.dirty || string.touched)"
|
||||
class="alert alert-danger validation-error">
|
||||
<div *ngIf="string.errors.required">
|
||||
{{'process.new.parameter.string.required' | translate}}
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,70 @@
|
||||
import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||
|
||||
import { DateValueInputComponent } from './date-value-input.component';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { TranslateLoaderMock } from '../../../../../shared/mocks/translate-loader.mock';
|
||||
|
||||
describe('DateValueInputComponent', () => {
|
||||
let component: DateValueInputComponent;
|
||||
let fixture: ComponentFixture<DateValueInputComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
FormsModule,
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useClass: TranslateLoaderMock
|
||||
}
|
||||
})],
|
||||
declarations: [DateValueInputComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(DateValueInputComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not show a validation error if the input field was left untouched but left empty', () => {
|
||||
const validationError = fixture.debugElement.query(By.css('.validation-error'));
|
||||
expect(validationError).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should show a validation error if the input field was touched but left empty', fakeAsync(() => {
|
||||
component.value = '';
|
||||
fixture.detectChanges();
|
||||
tick();
|
||||
|
||||
const input = fixture.debugElement.query(By.css('input'));
|
||||
input.triggerEventHandler('blur', null);
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const validationError = fixture.debugElement.query(By.css('.validation-error'));
|
||||
expect(validationError).toBeTruthy();
|
||||
}));
|
||||
|
||||
it('should not show a validation error if the input field was touched but not left empty', fakeAsync(() => {
|
||||
component.value = 'testValue';
|
||||
fixture.detectChanges();
|
||||
tick();
|
||||
|
||||
const input = fixture.debugElement.query(By.css('input'));
|
||||
input.triggerEventHandler('blur', null);
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const validationError = fixture.debugElement.query(By.css('.validation-error'));
|
||||
expect(validationError).toBeFalsy();
|
||||
}));
|
||||
});
|
@@ -0,0 +1,32 @@
|
||||
import { Component, OnInit, Optional, Input } from '@angular/core';
|
||||
import { ValueInputComponent } from '../value-input.component';
|
||||
import { ControlContainer, NgForm } from '@angular/forms';
|
||||
import { controlContainerFactory } from '../../../process-form.component';
|
||||
|
||||
/**
|
||||
* Represents the user inputted value of a date parameter
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-date-value-input',
|
||||
templateUrl: './date-value-input.component.html',
|
||||
styleUrls: ['./date-value-input.component.scss'],
|
||||
viewProviders: [ { provide: ControlContainer,
|
||||
useFactory: controlContainerFactory,
|
||||
deps: [[new Optional(), NgForm]] } ]
|
||||
})
|
||||
export class DateValueInputComponent extends ValueInputComponent<string> {
|
||||
/**
|
||||
* The current value of the date string
|
||||
*/
|
||||
value: string;
|
||||
@Input() initialValue;
|
||||
|
||||
ngOnInit() {
|
||||
this.value = this.initialValue;
|
||||
}
|
||||
|
||||
setValue(value) {
|
||||
this.value = value;
|
||||
this.updateValue.emit(value)
|
||||
}
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
<label for="file-upload-{{index}}" class="d-flex align-items-center m-0">
|
||||
<span class="btn btn-light">
|
||||
{{'process.new.parameter.file.upload-button' | translate}}
|
||||
</span>
|
||||
<span class="file-name ml-1">{{fileObject?.name}}</span>
|
||||
</label>
|
||||
<input requireFile #file="ngModel" type="file" name="file-upload-{{index}}" id="file-upload-{{index}}" class="form-control-file d-none" [ngModel]="fileObject" (ngModelChange)="setFile($event)"/>
|
||||
<div *ngIf="file.invalid && (file.dirty || file.touched)"
|
||||
class="alert alert-danger validation-error">
|
||||
<div *ngIf="file.errors.required">
|
||||
{{'process.new.parameter.file.required' | translate}}
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,6 @@
|
||||
.file-name {
|
||||
flex: 1;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||
|
||||
import { FormsModule, NgForm, ReactiveFormsModule } from '@angular/forms';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { FileValueInputComponent } from './file-value-input.component';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { FileValueAccessorDirective } from '../../../../../shared/utils/file-value-accessor.directive';
|
||||
import { FileValidator } from '../../../../../shared/utils/require-file.validator';
|
||||
import { TranslateLoaderMock } from '../../../../../shared/mocks/translate-loader.mock';
|
||||
|
||||
describe('FileValueInputComponent', () => {
|
||||
let component: FileValueInputComponent;
|
||||
let fixture: ComponentFixture<FileValueInputComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
FormsModule,
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useClass: TranslateLoaderMock
|
||||
}
|
||||
})],
|
||||
declarations: [FileValueInputComponent, FileValueAccessorDirective, FileValidator],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FileValueInputComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not show a validation error if the input field was left untouched but left empty', () => {
|
||||
const validationError = fixture.debugElement.query(By.css('.validation-error'));
|
||||
expect(validationError).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should show a validation error if the input field was touched but left empty', () => {
|
||||
const input = fixture.debugElement.query(By.css('input'));
|
||||
input.triggerEventHandler('blur', null);
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const validationError = fixture.debugElement.query(By.css('.validation-error'));
|
||||
expect(validationError).toBeTruthy();
|
||||
});
|
||||
});
|
@@ -0,0 +1,26 @@
|
||||
import { Component, Optional } from '@angular/core';
|
||||
import { ValueInputComponent } from '../value-input.component';
|
||||
import { ControlContainer, NgForm } from '@angular/forms';
|
||||
import { controlContainerFactory } from '../../../process-form.component';
|
||||
|
||||
/**
|
||||
* Represents the user inputted value of a file parameter
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-file-value-input',
|
||||
templateUrl: './file-value-input.component.html',
|
||||
styleUrls: ['./file-value-input.component.scss'],
|
||||
viewProviders: [ { provide: ControlContainer,
|
||||
useFactory: controlContainerFactory,
|
||||
deps: [[new Optional(), NgForm]] } ]
|
||||
})
|
||||
export class FileValueInputComponent extends ValueInputComponent<File> {
|
||||
/**
|
||||
* The current value of the file
|
||||
*/
|
||||
fileObject: File;
|
||||
setFile(files) {
|
||||
this.fileObject = files.length > 0 ? files[0] : undefined;
|
||||
this.updateValue.emit(this.fileObject);
|
||||
}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
<div [ngSwitch]="parameter?.type">
|
||||
<ds-string-value-input *ngSwitchCase="parameterTypes.STRING" [initialValue]="initialValue" (updateValue)="updateValue.emit($event)" [index]="index"></ds-string-value-input>
|
||||
<ds-string-value-input *ngSwitchCase="parameterTypes.OUTPUT" [initialValue]="initialValue" (updateValue)="updateValue.emit($event)" [index]="index"></ds-string-value-input>
|
||||
<ds-date-value-input *ngSwitchCase="parameterTypes.DATE" [initialValue]="initialValue" (updateValue)="updateValue.emit($event)" [index]="index"></ds-date-value-input>
|
||||
<ds-file-value-input *ngSwitchCase="parameterTypes.FILE" (updateValue)="updateValue.emit($event)" [index]="index"></ds-file-value-input>
|
||||
<ds-boolean-value-input *ngSwitchCase="parameterTypes.BOOLEAN" (updateValue)="updateValue.emit($event)" [index]="index"></ds-boolean-value-input>
|
||||
</div>
|
@@ -0,0 +1,105 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ParameterValueInputComponent } from './parameter-value-input.component';
|
||||
import { ScriptParameter } from '../../../scripts/script-parameter.model';
|
||||
import { ScriptParameterType } from '../../../scripts/script-parameter-type.model';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { BooleanValueInputComponent } from './boolean-value-input/boolean-value-input.component';
|
||||
import { StringValueInputComponent } from './string-value-input/string-value-input.component';
|
||||
import { FileValueInputComponent } from './file-value-input/file-value-input.component';
|
||||
import { DateValueInputComponent } from './date-value-input/date-value-input.component';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { FileValueAccessorDirective } from '../../../../shared/utils/file-value-accessor.directive';
|
||||
import { FileValidator } from '../../../../shared/utils/require-file.validator';
|
||||
import { TranslateLoaderMock } from '../../../../shared/mocks/translate-loader.mock';
|
||||
|
||||
describe('ParameterValueInputComponent', () => {
|
||||
let component: ParameterValueInputComponent;
|
||||
let fixture: ComponentFixture<ParameterValueInputComponent>;
|
||||
let booleanParameter;
|
||||
let stringParameter;
|
||||
let fileParameter;
|
||||
let dateParameter;
|
||||
let outputParameter;
|
||||
|
||||
function init() {
|
||||
booleanParameter = Object.assign(new ScriptParameter(), { type: ScriptParameterType.BOOLEAN });
|
||||
stringParameter = Object.assign(new ScriptParameter(), { type: ScriptParameterType.STRING });
|
||||
fileParameter = Object.assign(new ScriptParameter(), { type: ScriptParameterType.FILE });
|
||||
dateParameter = Object.assign(new ScriptParameter(), { type: ScriptParameterType.DATE });
|
||||
outputParameter = Object.assign(new ScriptParameter(), { type: ScriptParameterType.OUTPUT });
|
||||
}
|
||||
|
||||
beforeEach(async(() => {
|
||||
init();
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
FormsModule,
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useClass: TranslateLoaderMock
|
||||
}
|
||||
})],
|
||||
declarations: [
|
||||
ParameterValueInputComponent,
|
||||
BooleanValueInputComponent,
|
||||
StringValueInputComponent,
|
||||
FileValueInputComponent,
|
||||
DateValueInputComponent,
|
||||
FileValueAccessorDirective,
|
||||
FileValidator
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ParameterValueInputComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.parameter = stringParameter;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should show a BooleanValueInputComponent when the parameter type is boolean', () => {
|
||||
component.parameter = booleanParameter;
|
||||
fixture.detectChanges();
|
||||
const valueInput = fixture.debugElement.query(By.directive(BooleanValueInputComponent));
|
||||
expect(valueInput).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should show a StringValueInputComponent when the parameter type is string', () => {
|
||||
component.parameter = stringParameter;
|
||||
fixture.detectChanges();
|
||||
const valueInput = fixture.debugElement.query(By.directive(StringValueInputComponent));
|
||||
expect(valueInput).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should show a FileValueInputComponent when the parameter type is file', () => {
|
||||
component.parameter = fileParameter;
|
||||
fixture.detectChanges();
|
||||
const valueInput = fixture.debugElement.query(By.directive(FileValueInputComponent));
|
||||
expect(valueInput).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should show a DateValueInputComponent when the parameter type is date', () => {
|
||||
component.parameter = dateParameter;
|
||||
fixture.detectChanges();
|
||||
const valueInput = fixture.debugElement.query(By.directive(DateValueInputComponent));
|
||||
expect(valueInput).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should show a StringValueInputComponent when the parameter type is output', () => {
|
||||
component.parameter = outputParameter;
|
||||
fixture.detectChanges();
|
||||
const valueInput = fixture.debugElement.query(By.directive(StringValueInputComponent));
|
||||
expect(valueInput).toBeTruthy();
|
||||
});
|
||||
});
|
@@ -0,0 +1,37 @@
|
||||
import { Component, EventEmitter, Input, OnChanges, OnInit, Optional, Output } from '@angular/core';
|
||||
import { ScriptParameterType } from '../../../scripts/script-parameter-type.model';
|
||||
import { ScriptParameter } from '../../../scripts/script-parameter.model';
|
||||
import { ControlContainer, NgForm } from '@angular/forms';
|
||||
import { controlContainerFactory } from '../../process-form.component';
|
||||
|
||||
/**
|
||||
* Component that renders the correct parameter value input based the script parameter's type
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-parameter-value-input',
|
||||
templateUrl: './parameter-value-input.component.html',
|
||||
styleUrls: ['./parameter-value-input.component.scss'],
|
||||
viewProviders: [ { provide: ControlContainer,
|
||||
useFactory: controlContainerFactory,
|
||||
deps: [[new Optional(), NgForm]] } ]
|
||||
})
|
||||
export class ParameterValueInputComponent {
|
||||
@Input() index: number;
|
||||
|
||||
/**
|
||||
* The current script parameter
|
||||
*/
|
||||
@Input() parameter: ScriptParameter;
|
||||
|
||||
|
||||
@Input() initialValue: any;
|
||||
/**
|
||||
* Emits the value of the input when its updated
|
||||
*/
|
||||
@Output() updateValue: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
/**
|
||||
* The available script parameter types
|
||||
*/
|
||||
parameterTypes = ScriptParameterType;
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
<input required #string="ngModel" type="text" name="string-value-{{index}}" class="form-control" id="string-value-{{index}}" [ngModel]="value" (ngModelChange)="setValue($event)"/>
|
||||
<div *ngIf="string.invalid && (string.dirty || string.touched)"
|
||||
class="alert alert-danger validation-error">
|
||||
<div *ngIf="string.errors.required">
|
||||
{{'process.new.parameter.string.required' | translate}}
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,72 @@
|
||||
import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||
|
||||
import { FormsModule, NgForm } from '@angular/forms';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { StringValueInputComponent } from './string-value-input.component';
|
||||
import { TranslateLoaderMock } from '../../../../../shared/mocks/translate-loader.mock';
|
||||
|
||||
describe('StringValueInputComponent', () => {
|
||||
let component: StringValueInputComponent;
|
||||
let fixture: ComponentFixture<StringValueInputComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
FormsModule,
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useClass: TranslateLoaderMock
|
||||
}
|
||||
})],
|
||||
declarations: [StringValueInputComponent],
|
||||
providers: [
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(StringValueInputComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not show a validation error if the input field was left untouched but left empty', () => {
|
||||
const validationError = fixture.debugElement.query(By.css('.validation-error'));
|
||||
expect(validationError).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should show a validation error if the input field was touched but left empty', fakeAsync(() => {
|
||||
component.value = '';
|
||||
fixture.detectChanges();
|
||||
tick();
|
||||
|
||||
const input = fixture.debugElement.query(By.css('input'));
|
||||
input.triggerEventHandler('blur', null);
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const validationError = fixture.debugElement.query(By.css('.validation-error'));
|
||||
expect(validationError).toBeTruthy();
|
||||
}));
|
||||
|
||||
it('should not show a validation error if the input field was touched but not left empty', fakeAsync(() => {
|
||||
component.value = 'testValue';
|
||||
fixture.detectChanges();
|
||||
tick();
|
||||
|
||||
const input = fixture.debugElement.query(By.css('input'));
|
||||
input.triggerEventHandler('blur', null);
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const validationError = fixture.debugElement.query(By.css('.validation-error'));
|
||||
expect(validationError).toBeFalsy();
|
||||
}));
|
||||
});
|
@@ -0,0 +1,32 @@
|
||||
import { Component, Optional, Input } from '@angular/core';
|
||||
import { ValueInputComponent } from '../value-input.component';
|
||||
import { ControlContainer, NgForm } from '@angular/forms';
|
||||
import { controlContainerFactory } from '../../../process-form.component';
|
||||
|
||||
/**
|
||||
* Represents the user inputted value of a string parameter
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-string-value-input',
|
||||
templateUrl: './string-value-input.component.html',
|
||||
styleUrls: ['./string-value-input.component.scss'],
|
||||
viewProviders: [ { provide: ControlContainer,
|
||||
useFactory: controlContainerFactory,
|
||||
deps: [[new Optional(), NgForm]] } ]
|
||||
})
|
||||
export class StringValueInputComponent extends ValueInputComponent<string> {
|
||||
/**
|
||||
* The current value of the string
|
||||
*/
|
||||
value: string;
|
||||
@Input() initialValue;
|
||||
|
||||
ngOnInit() {
|
||||
this.value = this.initialValue;
|
||||
}
|
||||
|
||||
setValue(value) {
|
||||
this.value = value;
|
||||
this.updateValue.emit(value)
|
||||
}
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
import { EventEmitter, Input, Output } from '@angular/core';
|
||||
|
||||
/**
|
||||
* Abstract class that represents value input components
|
||||
*/
|
||||
export abstract class ValueInputComponent<T> {
|
||||
@Input() index: number;
|
||||
/**
|
||||
* Used by the subclasses to emit the value when it's updated
|
||||
*/
|
||||
@Output() updateValue: EventEmitter<T> = new EventEmitter<T>()
|
||||
}
|
Reference in New Issue
Block a user