Ежеквартальный сборщик - PullRequest
       54

Ежеквартальный сборщик

0 голосов
/ 10 октября 2019

Я ищу ежеквартальный сборщик дат, использующий ng-bootstrap.

На данный момент у меня есть Месяц и Год, см. STACKBLITZ , но я бы хотел изменить Месяц на Квартал.

enter image description here

Возможно ли это с помощью ng-bootstrap?

Для информации:Вот предыдущий пример стекаблика с использованием Угловой материал

enter image description here

1 Ответ

1 голос
/ 11 октября 2019

"кратко" объясните о stackblitz

В основном у нас есть ng-dropDown, который показывает серию ngbDropdownItem

у нас есть в качестве переменных

year:number; //the year selected
quarter:string; //hte quarter selected

yearDefault=new Date().getFullYear() //the year by defect
quarterDefault="Q"+(1+Math.floor(new Date().getMonth()/3)) //the quarter by defect

showQuarter:boolean=true; //a boolean variable. 
         //if true, the ngbDropdownItems will be the quarter, 
         //else the years

year10:number; //auxliar for show the list of years

И вспомогательный массив для отображения квартала

options: any[] = [
    {value:'Q1',months:['Jan','Feb','Mar']},
    {value:'Q2',months:['Apr','May','Jun']},
    {value:'Q3',months:['Jul','Aug','Sep']},
    {value:'Q4',months:['Oct','Nov','Dec']}
  ];

Итак, в нашем ngbDropdownMenu мы можем показать

<ng-container *ngIf="showQuarter">
    <button [ngClass]="{'bg-primary':item.value==quarter}" ngbDropdownItem 
         *ngFor="let item of options" 
         (click)="click(item.value,drop)">
        <span class="col" *ngFor="let month of item.months" >
           {{month}}
        </span>
    </button>
</ng-container>

//or

<ng-container *ngIf="!showQuarter">
    <button [ngClass]="{'bg-primary':(year10+item)==year}" ngbDropdownItem 
          *ngFor="let item of [0,1,2,3,4,5,6,7,8,9]" 
          (click)="changeYear(year10+item);showQuarter=true">
        <span >{{year10+item}}</span>
    </button>
</ng-container>

Кроме того, мы показываем «заголовок» с двумя кнопками (стрелка влево и вправо) и интервал, показывающий год или десятилетие

<div class="selectYear">
    <div class="ngb-dp-arrow">
        <button  class="btn btn-link ngb-dp-arrow-btn" type="button"
            (click)="showQuarter?changeYear((year||yearDefault)-1):year10=year10-10">
           <span class="ngb-dp-navigation-chevron">
            </span>
        </button>
    </div>

    <button type="button" class="btn btn-link" (click)="changeShowQuarter()">
        {{showQuarter?year?year:yearDefault:(year10+' - '+(year10+9))}}
    </button>

    <div class="ngb-dp-arrow right">
        <button class="btn btn-link ngb-dp-arrow-btn" type="button" 
            (click)="showQuarter?changeYear((year||yearDefault)+1):year10=year10+10">
            <span class="ngb-dp-navigation-chevron">
            </span>
        </button>
    </div>
</div>

Посмотрите, как в зависимости от переменной "showQuarter" кнопки выполняют то или иное действие

ФункцииПроще говоря, опять же, мы учитываем, что сначала год и квартал могут не иметь значения, в этом случае мы используем yearDefault и QuarterDefault

changeYear(year)
  {
    this.year=year || this.yearDefault;
    this.quarter=this.quarter||this.quarterDefault
              this.control.setValue(this.quarter+" "+this.year || this.yearDefault,{emitEvent:false})
  }
  changeShowQuarter()
  {
    this.showQuarter=!this.showQuarter
    if (!this.showQuarter)
      this.year10=this.year?10*Math.floor(this.year/10):10*Math.floor(this.yearDefault/10)
  }
  click(quarter,drop)
  {
    this.quarter=quarter;
    this.year=this.year||this.yearDefault
              this.control.setValue(this.quarter+" "+this.year,{emitEvent:false})
    drop.close()
  }

И да, у нас есть FormControl, называемый control, потому что у нас естьinput

  <input style="text-transform: uppercase" [formControl]="control" placeholder="Qq yyyy" >

  control:FormControl= new FormControl()

Чтобы контролировать ввод квартала и года вручную, мы подписываемся на control.valueChanges, чтобы присвоить значение году и кварталу, только если длина строки больше или равна 6

this.control.valueChanges.pipe(
      takeWhile(()=>this.alive),
      startWith(this.quarter+" "+this.year),
      debounceTime(200))
    .subscribe((res:string)=>{
//      console.log(this.controlID.nativeElement.selectionStart)
       if (res)
       {
         res=res.toUpperCase()
         if (res[0]!="Q")
           res="Q"+res;
           let value=res.replace(/[^Q|0-9]/g, '');
           let quarter;
           let year;
           if (value.length>=2)
              quarter=value[0]+value[1]
           if (value.length>=6)
           {
              year=value.substr(2,4)
              this.year=+year
              this.quarter=quarter;
              this.control.setValue((this.quarter+" "+this.year),{emitEvent:false})
           }
           else
           {
             this.year=null;
             this.quarter=null;
           }
       }
    })

TODO: создать пользовательский элемент управления формы с компонентом, пересмотреть .css для улучшения и удаления ненужных стилей

Обновление преобразовать в CustomFormControl это просто, только реализует ControlValueAccessor

  disabled: boolean = false;
  onChange: (_: any) => void;
  onTouched: any;

  registerOnChange(fn: (_: any) => void): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }

  setDisabledState(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }
  writeValue(value: any): void {
    if (value) {
      this.year = value.year;
      this.quarter = value.quarter;
      if (this.year && this.quarter)
        this.control.setValue(this.quarter + " " + this.year,{emitEvent:false});
    }
  }

Я использую вспомогательную функцию

  setValue(data: any) {
      if (data && data.quarter && data.year) {
        this.control.setValue(data.quarter + " " + data.year, {
          emitEvent: false
        });
        this.onChange({ quarter: data.quarter, year: data.year });
      } else {
        this.control.setValue(data, { emitEvent: false });
        this.onChange(null);
      }
  }

Этот вызов в control.valueChanges подписывается и в функции щелчка

Я оставляю в этот стекблиц

ПРИМЕЧАНИЕ: подобно ng-bootstrap я выбираю, чтобы возвращаемое значение было объектом со свойствами год и квартал

...