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) { } } @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; } }