File

src/app/task-web/task-view/task-view.component.ts

Implements

OnInit OnDestroy

Metadata

selector app-task-view
styleUrls ./task-view.component.css
templateUrl ./task-view.component.html

Index

Properties
Methods

Constructor

constructor(router: Router, route: ActivatedRoute, taskViewService: TaskViewService)
Parameters :
Name Type Optional
router Router No
route ActivatedRoute No
taskViewService TaskViewService No

Methods

getTask
getTask()

Get task data from task-view service.

Returns : void
getTaskStatus
getTaskStatus()
Returns : string
getTechName
getTechName()

Returns the tech name for the task's site's tech id.

Returns : string

One of: M-AT, FS, $T, etc.

haltTaskTimer
haltTaskTimer()
Returns : void
ngOnDestroy
ngOnDestroy()

Stop subscribing to router events.

this.destroyed emits to takeUntil thus ending the subscription to route events

Returns : void
ngOnInit
ngOnInit()
Returns : void
onTaskSelected
onTaskSelected(taskid: number)

Called by related tasks component to switch task viewed.

Parameters :
Name Type Optional
taskid number No
Returns : void
refreshTask
refreshTask()
Returns : void
setTaskStatus
setTaskStatus(val: number)
Parameters :
Name Type Optional
val number No
Returns : void
startTaskTimer
startTaskTimer()

Timer for determining when the task status badge needs to change color to indicate task "staleness."

This function makes use of these RxJS features:

Returns : void
taskStatusSubscr
taskStatusSubscr()

This function sets up a subscription for task status changes.

This code was adapted from: Angular: Refetch data on same URL navigation.
Note there's a slightly simpler solution here: Reloading current route in Angular 5 / Angular 6 / Angular 7.
It would be interesting to know if this simpler solution is equivalent to the first solution.

According to the article and my anecdotal experience, by default, the router doesn’t emit for events where we are trying to navigate to the same URL that is already activated.

Both of these solutions depend on:

  1. The Router Module's onSameUrlNavigation parameter being set to 'reload'
  2. Your route's runGuardsAndResolvers property being set to 'always'

The solution watches for NavigationEnd events then calls this.refreshTask() when one is found.

It stops watching when takeUntil is provided an observable emit from this.destroyed.

Returns : void

Properties

customerTextActive
Default value : true
destroyed
Default value : new Subject<any>()

Subject is a special type of observable. It's being used to detect when this, component is destroyed/exited to ensure that the Router events subscription is canceled when at that time.

dict
Type : any
inhouseTextActive
Default value : false
keywordsActive
Default value : false
relatedTasksActive
Default value : false
task
Type : any
taskID
Type : any
taskStatus
Type : string
taskTimerSubscription
Type : any
import { Component, OnInit, OnDestroy } from '@angular/core';
import {
  Router,
  ActivatedRoute,
  NavigationEnd,
  RouterEvent,
} from '@angular/router';
import { TaskViewService } from './task-view.service';
import { interval, Subject } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';

@Component({
  selector: 'app-task-view',
  templateUrl: './task-view.component.html',
  styleUrls: ['./task-view.component.css'],
})
export class TaskViewComponent implements OnInit, OnDestroy {
  task: any;
  dict: any;
  taskID: any;
  customerTextActive = true;
  inhouseTextActive = false;
  keywordsActive = false;
  relatedTasksActive = false;
  taskStatus: string;
  taskTimerSubscription: any;
  /**
   * [Subject]{@link https://rxjs-dev.firebaseapp.com/guide/subject} is a
   * special type of observable.  It's being used to detect when this, component
   * is destroyed/exited to ensure that the Router events subscription is 
   * canceled when at that time.
   */
  destroyed = new Subject<any>();

  /**
   */
  constructor(
    private router: Router,
    private route: ActivatedRoute,
    private taskViewService: TaskViewService
  ) { }

  ngOnInit(): void {
    // Subscribe to task refresh events.
    this.taskStatusSubscr();

    // Get parameters from task url.
    this.route.queryParams.subscribe((params) => (this.taskID = params.taskid));

    // Get task and dictionary data from task service.
    this.getTask();
    this.taskViewService.getDict().subscribe((dict) => (this.dict = dict));
  }

  /**
   * This function sets up a subscription for task status changes.
   * 
   * This code was adapted from:
   * [Angular: Refetch data on same URL navigation]{@link https://medium.com/angular-in-depth/refresh-current-route-in-angular-512a19d58f6e}.
   * <br>
   * Note there's a slightly simpler solution here:
   * [Reloading current route in Angular 5 / Angular 6 / Angular 7]{@link https://medium.com/engineering-on-the-incline/reloading-current-route-on-click-angular-5-1a1bfc740ab2}.
   * <br>
   * It would be interesting to know if this simpler solution is equivalent to
   * the first solution.
   * 
   * According to the article and my anecdotal experience, by default,
   *    the router doesn’t emit for events where we are trying to navigate to
   *    the same URL that is already activated.
   * 
   * Both of these solutions depend on:
   * <ol>
   *   <li>The Router Module's [onSameUrlNavigation]{@link https://angular.io/api/router/ExtraOptions#onSameUrlNavigation}
   *     parameter being set to 'reload'
   *   </li>
   *   <li>Your route's [runGuardsAndResolvers]{@link https://angular.io/api/router/Route#runGuardsAndResolvers}
   *     property being set to 'always'
   *   </li>
   * </ol>
   * 
   * The solution watches for
   * [NavigationEnd]{@link https://angular.io/api/router/NavigationEnd} events
   * then calls <code>this.refreshTask()</code> when one is found.
   * 
   * It stops watching when
   * [takeUntil]{@link https://www.learnrxjs.io/learn-rxjs/operators/filtering/takeuntil}
   * is provided an observable emit from <code>this.destroyed</code>.
   */
  taskStatusSubscr(): void {
    this.router.events
      .pipe(
        // filter out all router events except for 
        filter((event: RouterEvent) => event instanceof NavigationEnd),
        takeUntil(this.destroyed)
      )
      // fetch task data when a NavigationEnd event occurs
      .subscribe(() => {
        this.refreshTask();
      });
  }

  setTaskStatus(val: number) {
    if (val === 0) {
      this.taskStatus = 'pending';
    } else {
      this.taskStatus = 'expired';
    }
  }

  /**
   * Timer for determining when the task status badge needs to change color to
   * indicate task "staleness."
   * 
   * This function makes use of these RxJS features:
   * <ul>
   *  <li>[interval]{@link https://rxjs-dev.firebaseapp.com/api/index/function/interval} function</li>
   *  <li>[Subscription]{@link https://rxjs-dev.firebaseapp.com/api/index/class/Subscription} class</li>
   * </ul>
   */
  startTaskTimer(): void {
    const source = interval(60000);
    // when the time subscription emits (a number), the task status is updated
    this.taskTimerSubscription = source.subscribe((val: number) =>
      this.setTaskStatus(val)
    );
  }

  /**
   * Get task data from task-view service.
   */
  getTask(): void {
    this.taskStatus = 'active';
    this.taskViewService.getTask(this.taskID).subscribe((task) => {
      this.task = task;
      // timer to indicate whether or not the task should be refreshed
      this.startTaskTimer();
    });
  }

  /**
   * Returns the tech name for the task's site's tech id.
   * @returns One of: M-AT, FS, $T, etc.
   */
  getTechName(): string {
    return this.dict.DAmsTechnologies.filter(
      (tech: any) => tech.ID === this.task.AmsTaskMain.TechnologyID
    )[0].Name;
  }

  /**
   * Called by related tasks component to switch task viewed.
   */
  onTaskSelected(taskid: number): void {
    this.taskID = taskid;
    this.haltTaskTimer();
    this.getTask();
  }

  getTaskStatus(): string {
    return this.taskStatus;
  }

  haltTaskTimer(): void {
    this.taskTimerSubscription.next();
    this.taskTimerSubscription.complete();
  }

  refreshTask(): void {
    this.haltTaskTimer();
    this.getTask();
  }

  /**
   * Stop subscribing to router events.
   * 
   * <code>this.destroyed</code> emits to <code>takeUntil</code> thus ending the
   * subscription to route events
   */
  ngOnDestroy(): void {
    this.destroyed.next();
    this.destroyed.complete();
  }
}
<div id="overlay-task-num">
  <span id="task-label"> Task # </span>
  <span *ngIf="task" id="task-num">{{ task.AmsTaskMain[0].TaskID }}</span>
  <a *ngIf="task" [routerLink]="['/task-view']" [queryParams]="{ taskid: task.AmsTaskMain[0].TaskID }" role="tooltip"
    aria-haspopup="true">
    <span title="Click to refresh task view" class="badge" [ngClass]="{
                'badge-success': taskStatus === 'active',
                'badge-warning': taskStatus === 'pending',
                'badge-danger': taskStatus === 'expired'
            }" id="task-badge"></span>
  </a>
  <span id="task-spinner" *ngIf="!task" class="spinner spinner-sm"> Loading... </span>
</div>

<div class="content-area" style="height: 800px; overflow: hidden">
  <clr-tabs *ngIf="task">
    <div *ngIf="task.AmsTaskText && task.AmsTaskText.length > 0">
      <clr-tab *ngIf="task.AmsTaskText[0].CustomerText">
        <button clrTabLink>Customer Text</button>
        <ng-template [(clrIfActive)]="customerTextActive">
          <clr-tab-content>
            <div class="content-container">
              <div class="content-area" style="height:800px;overflow-y:scroll;">
                Customer Text
              </div>
            </div>
          </clr-tab-content>
        </ng-template>
      </clr-tab>
      <clr-tab *ngIf="task.AmsTaskText[0].InhouseText">
        <button clrTabLink>In-house Text</button>
        <ng-template [(clrIfActive)]="inhouseTextActive">
          <clr-tab-content>
            <div class="content-container">
              <div class="content-area" style="height:800px;overflow-y:scroll;">
                In-house Text
              </div>
            </div>
          </clr-tab-content>
        </ng-template>
      </clr-tab>
      <clr-tab *ngIf="task.AmsTaskText[0].KeywordText">
        <button clrTabLink>Keywords</button>
        <ng-template [(clrIfActive)]="keywordsActive">
          <clr-tab-content>
            <div class="content-container">
              <div class="content-area" style="height:800px;overflow-y:scroll;">
                Keywords
              </div>
            </div>
          </clr-tab-content>
        </ng-template>
      </clr-tab>
    </div>
    <clr-tab *ngIf="task.AmsTaskRelatedTasks && task.AmsTaskRelatedTasks.length > 0">
      <button clrTabLink>Related Tasks</button>
      <ng-template [(clrIfActive)]="relatedTasksActive">
        <clr-tab-content>
          <div class="content-container">
            <div class="content-area" style="height:800px;overflow-y:scroll;">
              Related Tasks
            </div>
          </div>
        </clr-tab-content>
      </ng-template>
    </clr-tab>
  </clr-tabs>
  <span *ngIf="!task" class="spinner spinner-sm">
    Loading...
  </span>
</div>

./task-view.component.css

#overlay-task-num {
  background-color: #304250;
  color: #fafafa;
  position: absolute;
  top: 54px;
  right: 150px;
  padding-left: 10px;
  min-width: 11em;
  width: 11em;
  z-index: 100;
}

#task-badge {
  position: relative;
  top: -2px;
  left: 8px;
  text-align: right;
}

#task-num {
  opacity: 0.65;
  text-align: left;
  width: 5em;
  min-width: 5em;
  font-family: Arial, monospace;
}

#task-label {
  color: white;
  opacity: 1;
  text-align: right;
}

#task-spinner {
  position: relative;
  top: 2px;
  left: 8px;
}
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""