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