added templates component
This commit is contained in:
@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ArrayInputHelperService } from './array-input-helper.service';
|
||||
|
||||
describe('ArrayInputHelperService', () => {
|
||||
let service: ArrayInputHelperService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(ArrayInputHelperService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,26 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import {Observable, Subject} from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ArrayInputHelperService {
|
||||
|
||||
com: Subject<{ id: string, index: number, value: any }> = new Subject();
|
||||
|
||||
constructor() { }
|
||||
|
||||
values(id: string) {
|
||||
return new Observable<{index: number, value: any}>(observer => {
|
||||
this.com.subscribe(data => {
|
||||
if (data.id === id) {
|
||||
observer.next({index: data.index, value: data.value});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
newValue(id: string, index: number, value: any) {
|
||||
this.com.next({id, index, value});
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
<ng-container *ngFor="let ignore of [].constructor(values.length); index as i">
|
||||
<ng-container *ngTemplateOutlet="item.templateRef; context: {$implicit: {i: i, value: values[i]}}"></ng-container>
|
||||
</ng-container>
|
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RbArrayInputComponent } from './rb-array-input.component';
|
||||
|
||||
describe('RbArrayInputComponent', () => {
|
||||
let component: RbArrayInputComponent;
|
||||
let fixture: ComponentFixture<RbArrayInputComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ RbArrayInputComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(RbArrayInputComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,107 @@
|
||||
import {
|
||||
AfterViewInit,
|
||||
Component,
|
||||
ContentChild,
|
||||
Directive,
|
||||
forwardRef,
|
||||
HostListener,
|
||||
Input,
|
||||
OnInit,
|
||||
TemplateRef
|
||||
} from '@angular/core';
|
||||
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
|
||||
import _ from 'lodash';
|
||||
import {ArrayInputHelperService} from './array-input-helper.service';
|
||||
|
||||
// TODO: implement everywhere
|
||||
|
||||
@Directive({ // directive for template and input values
|
||||
// tslint:disable-next-line:directive-selector
|
||||
selector: '[rbArrayInputItem]'
|
||||
})
|
||||
export class RbArrayInputItemDirective {
|
||||
constructor(public templateRef: TemplateRef<any>) {
|
||||
}
|
||||
}
|
||||
|
||||
@Directive({ // directive for change detection
|
||||
// tslint:disable-next-line:directive-selector
|
||||
selector: '[rbArrayInputListener]'
|
||||
})
|
||||
export class RbArrayInputListenerDirective {
|
||||
|
||||
@Input() rbArrayInputListener: string;
|
||||
@Input() index: number;
|
||||
|
||||
constructor(
|
||||
private helperService: ArrayInputHelperService
|
||||
) { }
|
||||
|
||||
@HostListener('ngModelChange', ['$event'])
|
||||
onChange(event) {
|
||||
console.log(event);
|
||||
this.helperService.newValue(this.rbArrayInputListener, this.index, event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Component({
|
||||
// tslint:disable-next-line:component-selector
|
||||
selector: 'rb-array-input',
|
||||
templateUrl: './rb-array-input.component.html',
|
||||
styleUrls: ['./rb-array-input.component.scss'],
|
||||
providers: [{provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => RbArrayInputComponent), multi: true}]
|
||||
})
|
||||
export class RbArrayInputComponent implements ControlValueAccessor, OnInit, AfterViewInit {
|
||||
|
||||
@Input() pushTemplate: any;
|
||||
@Input() pushPath: string;
|
||||
|
||||
@ContentChild(RbArrayInputItemDirective) item: RbArrayInputItemDirective;
|
||||
@ContentChild(RbArrayInputListenerDirective) item2: RbArrayInputListenerDirective;
|
||||
|
||||
values = []; // main array to display
|
||||
|
||||
onChange = (ignore?: any): void => {};
|
||||
onTouched = (ignore?: any): void => {};
|
||||
|
||||
|
||||
constructor(
|
||||
private helperService: ArrayInputHelperService
|
||||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => { // needed to find reference
|
||||
this.helperService.values(this.item2.rbArrayInputListener).subscribe(data => { // action on value change
|
||||
this.values[data.index][this.pushPath] = data.value;
|
||||
console.log(this.values);
|
||||
if (this.values[this.values.length - 1][this.pushPath] === '' && this.values[this.values.length - 2][this.pushPath] === '') { // remove last element if last two are empty
|
||||
this.values.pop();
|
||||
}
|
||||
else if (this.values[this.values.length - 1][this.pushPath] !== '') { // add element if last one is filled
|
||||
this.values.push(_.cloneDeep(this.pushTemplate));
|
||||
}
|
||||
this.onChange(this.values.filter(e => e !== '')); // trigger ngModel with filled elements
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
|
||||
writeValue(obj: any) { // add empty value on init
|
||||
this.values = obj ? obj : [];
|
||||
if (this.values.length === 0 || this.values[0] !== '') {
|
||||
console.log(this.values);
|
||||
this.values.push(_.cloneDeep(this.pushTemplate));
|
||||
}
|
||||
}
|
||||
|
||||
registerOnChange(fn: any) {
|
||||
this.onChange = fn;
|
||||
}
|
||||
|
||||
registerOnTouched(fn: any) {
|
||||
this.onTouched = fn;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user