Farkas Viktor
Farkas Viktor

Reputation: 13

Calling a function at random times in Angular

I am building my first Angular application (a task manager), and I need to call the addItem() function at random time intervals. Do I need to use setTimeOut in this case? And where do I need to put this function call in the component TypeScript file exactly? It seems like no matter where I put it, the compiler gives an error.

Here is my tasks.component.ts file:

import { Component, OnInit } from '@angular/core';

export interface Task {
  id: number;
  title: string;
  description: string;
  priority: string;
  dueDate: Date;
  resolvedAt: string;
}

const defaultTaskList: Task[] = [
  {
    id: 1,
    title: 'Get groceries',
    description: 'Milk, Eggs, Bread, Salt',
    priority: 'medium',
    dueDate: new Date(2022, 5, 9),
    resolvedAt: new Date(2022, 5, 9).toDateString(),
  },
  {
    id: 2,
    title: 'Send important emails',
    description: 'Send email to tax office, include reference number: 372983.',
    priority: 'high',
    dueDate: new Date(2022, 5, 2),
    resolvedAt: '',
  },
  {
    id: 3,
    title: 'Take Randy the dog to the vet',
    description: 'Price of visit: 30 Euros. Withdraw cash.',
    priority: 'medium',
    dueDate: new Date(2022, 5, 13),
    resolvedAt: new Date(2022, 5, 9).toDateString(),
  },
  {
    id: 4,
    title: 'Water Jane\'s plants',
    description: 'Let the soil get fully soaked with water.',
    priority: 'high',
    dueDate: new Date(2022, 7, 11),
    resolvedAt: '',
  },
  {
    id: 5,
    title: 'Do coding homework',
    description: 'Details in email.',
    priority: 'high',
    dueDate: new Date(2021, 2, 5),
    resolvedAt: '',
  },
];

let tasks: Task[] = [];
let resolvedTasks: Task[] = [];

@Component({
  selector: 'app-tasks',
  templateUrl: './tasks.component.html',
  styleUrls: ['./tasks.component.scss'],
})

export class TasksComponent implements OnInit {
  displayedColumns: string[] = ['id', 'title', 'description', 'priority', 'dueDate', 'resolvedAt'];
  dataSource = tasks;
  resolvedDataSource =  resolvedTasks;

  addItem(): void {
    let i = Math.floor(Math.random() * defaultTaskList.length);
    let currentTask: Task = defaultTaskList[i];
    let newData = [ ...this.dataSource ];
    let newResolvedData = [... this.resolvedDataSource];

    if (currentTask.resolvedAt) {
      newResolvedData.push(currentTask)
    } else {
      newData.push(currentTask);
    }

    newData = newData.sort((a, b) => {
      return a.dueDate.getTime() - b.dueDate.getTime();
    });
    newResolvedData = newResolvedData.sort((a, b) => {
      return a.dueDate.getTime() - b.dueDate.getTime();
    });

    newData.map((obj) => {
      return { ...obj, dueDate: obj.dueDate.toDateString() };
    });
    newResolvedData.map((obj) => {
      return { ...obj, dueDate: obj.dueDate.toDateString() };
    });

    this.dataSource = newData;
    this.resolvedDataSource = newResolvedData;
  }

  constructor() { }

  ngOnInit(): void {
  }
}

and my tasks.component.html file:

<table mat-table [dataSource]="dataSource">
  <ng-container matColumnDef="id">
    <th mat-header-cell *matHeaderCellDef>ID</th>
    <td mat-cell *matCellDef="let task">{{task.id}}</td>
  </ng-container>
  <ng-container matColumnDef="title">
    <th mat-header-cell *matHeaderCellDef>Title</th>
    <td mat-cell *matCellDef="let task">{{task.title}}</td>
  </ng-container>
  <ng-container matColumnDef="description">
    <th mat-header-cell *matHeaderCellDef>Description</th>
    <td mat-cell *matCellDef="let task">{{task.description}}</td>
  </ng-container>
  <ng-container matColumnDef="priority">
    <th mat-header-cell *matHeaderCellDef>Priority</th>
    <td mat-cell *matCellDef="let task">{{task.priority}}</td>
  </ng-container>
  <ng-container matColumnDef="dueDate">
    <th mat-header-cell *matHeaderCellDef>Due date</th>
    <td mat-cell *matCellDef="let task">{{task.dueDate | date:'longDate'}}</td>
  </ng-container>
  <ng-container matColumnDef="resolvedAt">
    <th mat-header-cell *matHeaderCellDef>Resolved at</th>
    <td mat-cell *matCellDef="let task">{{task.resolvedAt | date:'longDate'}}</td>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
  <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>

<h2>Resolved</h2>
<table mat-table [dataSource]="resolvedDataSource">
  <ng-container matColumnDef="id">
    <th mat-header-cell *matHeaderCellDef>ID</th>
    <td mat-cell *matCellDef="let task">{{task.id}}</td>
  </ng-container>
  <ng-container matColumnDef="title">
    <th mat-header-cell *matHeaderCellDef>Title</th>
    <td mat-cell *matCellDef="let task">{{task.title}}</td>
  </ng-container>
  <ng-container matColumnDef="description">
    <th mat-header-cell *matHeaderCellDef>Description</th>
    <td mat-cell *matCellDef="let task">{{task.description}}</td>
  </ng-container>
  <ng-container matColumnDef="priority">
    <th mat-header-cell *matHeaderCellDef>Priority</th>
    <td mat-cell *matCellDef="let task">{{task.priority}}</td>
  </ng-container>
  <ng-container matColumnDef="dueDate">
    <th mat-header-cell *matHeaderCellDef>Due date</th>
    <td mat-cell *matCellDef="let task">{{task.dueDate | date:'longDate'}}</td>
  </ng-container>
  <ng-container matColumnDef="resolvedAt">
    <th mat-header-cell *matHeaderCellDef>Resolved at</th>
    <td mat-cell *matCellDef="let task">{{task.resolvedAt | date:'longDate'}}</td>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
  <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>

<button mat-button (click)="addItem()">Add new item</button>

Also, I take any suggestions regarding Angular and TS best practices, or how to make the code more simple and readable.

Thanks!

Upvotes: 0

Views: 302

Answers (1)

Get Off My Lawn
Get Off My Lawn

Reputation: 36309

You can use an interval to call your function at a minimum speed and filter out the value to randomize the rate that your function is called.

  ngOnInit() {
    // 250 is the minimum speed at which the function will be called
    this.sub = interval(250)
      .pipe(
        // Generate a random number
        map(() => Math.round(Math.random() * 10)),
        // Use the random number to filter, it should be between 0 and 3
        // A bigger range will call the function more often
        // A smaller range will call the function less often
        filter((i) => i > 0 && i < 3),
        // If the number gets this far call your function
        tap(() => this.myFunc())
      )
      // Don't forget to unsubscribe when your done,
      // otherwise the function will keep getting called.
      .subscribe();
  }

You can see a working example here

Upvotes: 1

Related Questions