Angular: Display time in template with mask using a pipe

579 Views Asked by At

I have this pipe, secondsToHms, to convert from seconds to hours, minutes and seconds:

transform(seconds: number): string {
  const minutes = Math.floor(seconds / 60); //minutes
  const secs = seconds % 60; //seconds
  const hours = Math.floor(minutes / 60); //hours
  const mins = minutes % 60; //minutes

  return (
    '' +
    (hours < 10 ? hours.toString().padStart(2, '0') : hours.toString()) +
    mins.toString().padStart(2, '0') +
    secs.toString().padStart(2, '0')
  );
}

In my HTML, I'm trying to display the value like this, but the time doesn't display as I want (HH:mm:ss) and I don't know why. I'm using ngx-mask inside the input.

<ng-template [ngIf]="control.value.type === 'TYPE1'">
   <div class="input-group mb-2">
     <input
       (ngModelChange)="setDirty(true)"
       formControlName="quantity"
       type="text"
       class="form-control text-center"
       placeholder="00:00:00"
       mask="00:m0:s0"
      [value]="control.value.quantity | secondsToHms"
     />
  </div>
</ng-template>

The control variable is accessing in the template via this loop:

<ng-container *ngFor="let control of dataArr.controls; 
  let i = index">

And this is the dataArr function:

get dataArr() {
  return this.myForm.get('allData') as FormArray;
}

I need to do the conversion in the template since the pipe only applies when type is equal to TYPE1 which only happens here [ngIf]="control.value.type === 'TYPE1'".

I'm using this function to create form controls, don't know if it's relevant to this case.

addDataFormGroup(data: DataModel) {
  this.dataArr.push(
    this.fb.group({
      data: data.data,
      dataType: data.dataType,
      quantity: data.quantity,
    })
  );
}
1

There are 1 best solutions below

5
Eliseo On

there're several errors in your code.

  1. The mask that use ngx-mask should be: 00:00:00

  2. When you use ReactiveForms (formControlName) you should not use value. You need give value to the formControl -using patchValue or setValue-, so to give value you use a simple function, not a pipe

  3. You can make more compact your function

    transform(seconds: number):string {   
        const minutes = Math.floor(seconds / 60); //minutes  
        const secs = seconds % 60; //seconds   const hours =
        Math.floor(minutes / 60); //hours   const mins = minutes % 60;
        //minutes
    
          return ('00'+hours).slice(-2)+":"+
                 ('00'+mins).slice(-2)+":"+
                 ('00'+secs).slice(-2) }
    
    //and you use addDataFormGroup(data: DataModel) {
         this.dataArr.push(
            this.fb.group({
              data: data.data,
              dataType: data.dataType,
              quantity: this.transform(data.quantity), //<--here
            })   
          ); }
    

Update As the trasnformations depend from a variable we can take another appoach that is use [ngModel] and (ngModelChange) to mannage a formControl.

Imagine a functions like:

  transform(seconds: number|string): string {
    if (typeof(seconds)=="string")
      return seconds;
    const minutes = Math.floor(seconds / 60); //minutes
    const secs = seconds % 60; //seconds
    const hours = Math.floor(minutes / 60); //hours
    const mins = minutes % 60; //minutes
  
    return ('00'+hours).slice(-2)+":"+
           ('00'+mins).slice(-2)+":"+
           ('00'+secs).slice(-2)
  }
  parse(value:string)
  {
    const match=value.match(/\d\d/g)
    if (match && match.length==3)
      return (+match[0])*3600+(+match[1]*60)+(+match[2])
    return value
  }

We can use some like

<form [formGroup]="form">
  <div formArrayName="dataArray">
    <div *ngFor="let group of dataArray.controls;let i=index" [formGroupName]="i">
    <input [ngModel]="transform(form.get('dataArray.'+i+'.quantity').value)"
           (ngModelChange)="form.get('dataArray.'+i+'.quantity')
                                .setValue(parse($event))"

           [ngModelOptions]="{standalone:true}"
    />
    </div>
  </div>
</form>

See that we use [ngModel] to show the value of the formControl and ngModelChange to change the value of the formControl. Perhafs it's necesary some ajust when (blur) the input

You have a litle stackblitz here