File

src/app/shared/components/slices-input/slices-input.component.ts

Description

Component for entering data on block slices

Metadata

Index

Properties
Methods
Inputs
Outputs
HostBindings
Accessors

Constructor

constructor(ga: GoogleAnalyticsService)

Creates an instance of slices input component.

Parameters :
Name Type Optional Description
ga GoogleAnalyticsService No

Analytics service

Inputs

slicesConfig
Type : SlicesConfig
Default value : DEFAULT_SLICES_CONFIG

Values of block dimensions to be emitted

Outputs

slicesConfigChange
Type : EventEmitter

Emitter for slice data values

HostBindings

class
Type : "ccf-slices-input"
Default value : 'ccf-slices-input'

HTML class name

Methods

refreshSlices
refreshSlices()

Refreshes all slice data values to empty values

Returns : void
updateSlicesData
updateSlicesData(input: KeyboardEvent, key: string)

Limits the length of the input if needed and updates values when an input changes

Parameters :
Name Type Optional Description
input KeyboardEvent No

Event from the input element which contains the new value

key string No

Name of the dimension to be updated

Returns : void

Properties

Readonly clsName
Type : string
Default value : 'ccf-slices-input'
Decorators :
@HostBinding('class')

HTML class name

Accessors

hasThicknessValue
gethasThicknessValue()

Returns whether a valid thickness value has been entered.

Returns : boolean
import { ChangeDetectionStrategy, Component, EventEmitter, HostBinding, Input, Output } from '@angular/core';
import { GoogleAnalyticsService } from 'ngx-google-analytics';

/**
 * Interface containing slices data of the tissue block
 */
export interface SlicesConfig {
  /** Thickness of each tissue slice */
  thickness: number;
  /** Number of slices in the block */
  numSlices: number;
}

/** Default values for slices config. */
const DEFAULT_SLICES_CONFIG: SlicesConfig = {
  thickness: NaN,
  numSlices: NaN,
};

/**
 * Component for entering data on block slices
 */
@Component({
  selector: 'ccf-slices-input',
  templateUrl: './slices-input.component.html',
  styleUrls: ['./slices-input.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SlicesInputComponent {
  /** HTML class name */
  @HostBinding('class') readonly clsName = 'ccf-slices-input';

  /**
   * Values of block dimensions to be emitted
   */
  @Input() slicesConfig = DEFAULT_SLICES_CONFIG;

  /**
   * Emitter for slice data values
   */
  @Output() readonly slicesConfigChange = new EventEmitter<SlicesConfig>();

  /**
   * Returns whether a valid thickness value has been entered.
   */
  get hasThicknessValue(): boolean {
    return !isNaN(this.slicesConfig.thickness);
  }

  /**
   * Creates an instance of slices input component.
   *
   * @param ga Analytics service
   */
  constructor(private readonly ga: GoogleAnalyticsService) {}

  /**
   * Limits the length of the input if needed and updates values when an input changes
   *
   * @param input Event from the input element which contains the new value
   * @param key Name of the dimension to be updated
   */
  updateSlicesData(input: KeyboardEvent, key: string): void {
    const { value: strValue } = input.target as HTMLInputElement;
    this.slicesConfig = { ...this.slicesConfig, [key]: strValue !== '' ? +strValue : NaN };
    this.ga.event('slice_config_update', 'slice_input', key, this.slicesConfig[key as never]);
    this.slicesConfigChange.emit(this.slicesConfig);
  }

  /**
   * Refreshes all slice data values to empty values
   */
  refreshSlices(): void {
    this.slicesConfig = DEFAULT_SLICES_CONFIG;
    this.ga.event('slice_config_reset', 'slice_input');
    this.slicesConfigChange.emit(this.slicesConfig);
  }
}
<div class="header">
  <span class="text title" matTooltip="Add thickness of tissue sections and the total number of sections"
    >Tissue Sections</span
  >
  <div class="filler"></div>
  <mat-icon
    matRipple
    [matRippleCentered]="true"
    [matRippleUnbounded]="true"
    class="icon refresh"
    (click)="refreshSlices()"
  >
    refresh
  </mat-icon>
</div>

<div class="slices-inputs">
  <mat-form-field class="field">
    <mat-label class="text form-input-label">Thickness</mat-label>
    <input
      matInput
      ccfNumbersOnly
      class="input"
      type="number"
      [value]="slicesConfig.thickness"
      (keyup)="updateSlicesData($event, 'thickness')"
      matTooltip="Enter thickness of tissue sections"
    />
    <div matSuffix class="suffix" [class.show]="hasThicknessValue">μm</div>
  </mat-form-field>

  <mat-form-field class="field">
    <mat-label class="text form-input-label"># Sections</mat-label>
    <input
      matInput
      ccfNumbersOnly
      class="input"
      type="number"
      [value]="slicesConfig.numSlices"
      (keyup)="updateSlicesData($event, 'numSlices')"
      matTooltip="Enter total number of sections"
    />
  </mat-form-field>
</div>

./slices-input.component.scss

:host {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;

  input[type='number'] {
    -moz-appearance: textfield;
  }

  .header {
    display: flex;
    align-items: center;
    height: 1.5rem;
    padding: 0.5rem 0;

    .title {
      font-weight: 400;
    }

    .refresh {
      transform: scaleX(-1);
      cursor: pointer;
      transition: 0.6s;

      &:hover {
        border-radius: 2px;
      }
    }
  }

  .slices-inputs {
    display: flex;
    justify-content: space-between;
    width: 20rem;
    margin: 0 auto;

    .field {
      width: 9rem;

      &:not(:last-child) {
        padding-right: 0.75rem;
      }

      .input {
        text-align: center;
      }

      .suffix {
        display: none;
      }

      &.mat-focused .suffix,
      .suffix.show {
        display: initial;
      }

      ::ng-deep .mdc-text-field {
        padding: 0;

        .mat-mdc-form-field-infix {
          padding-bottom: 0;
          min-height: inherit;
        }

        .mat-mdc-form-field-icon-suffix {
          padding: 1.5rem 0 0 0;
        }
      }
    }
  }

  .filler {
    flex-grow: 1;
  }
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""