File

src/app/blog-editor/tags/tags.component.ts

Description

Handles the creation of tags for blog posts
TODO Refactor behavior so it takes in an async post instead of making its own calls to the server

Metadata

selector app-tags
styleUrls tags.component.scss
templateUrl tags.component.html

Inputs

id

Type: string

tagsInput

Type: string[]

Constructor

constructor(afs: AngularFirestore)

Methods

add
add(event: MatChipInputEvent)

Add a new chiop

Parameters :
  • event

    MatChipInputEvent

Returns: void
remove
remove(tag: string)

Removes tags from the list

Parameters :
  • tag

    text of tag

Returns: void
selected
selected(event: MatAutocompleteSelectedEvent)

Handles selection of autocomplete tag

Parameters :
  • event

    Event when autocomplete option is selected

Returns: void
Private _filter
_filter(value: string)

Method to filter tags and make sure they're usable

Returns: string[]
Public getColor
getColor(tag: string)
Returns: string

Properties

addOnBlur
addOnBlur: boolean
Default value: true
alltags
alltags: string[]
filteredTags
filteredTags: Observable<string[]>
matAutocomplete
matAutocomplete: MatAutocomplete
Private postDoc
postDoc: any
removable
removable: boolean
Default value: true
selectable
selectable: boolean
Default value: true
separatorKeysCodes
separatorKeysCodes: number[]
tagCtrl
tagCtrl: FormControl
tagInput
tagInput: any
tags
tags: string[]
visible
visible: boolean
Default value: true
import {COMMA, ENTER} from '@angular/cdk/keycodes';
import {Component, ElementRef, ViewChild, Input, OnInit} from '@angular/core';
import {FormControl} from '@angular/forms';
import {MatAutocompleteSelectedEvent, MatAutocomplete} from '@angular/material/autocomplete';
import {MatChipInputEvent} from '@angular/material/chips';
import {Observable} from 'rxjs';
import {map, startWith} from 'rxjs/operators';
import { AngularFirestore, AngularFirestoreDocument } from '@angular/fire/firestore';
import { Post } from 'src/app/_models/post.model';

/**
 * Handles the creation of tags for blog posts
 * TODO Refactor behavior so it takes in an async post instead of making its own calls to the server
 */
@Component({
  selector: 'app-tags',
  templateUrl: './tags.component.html',
  styleUrls: ['./tags.component.scss']
})
export class TagsComponent implements OnInit {

  private postDoc: AngularFirestoreDocument<Post>; // Reference to post
  visible = true;
  selectable = true;
  removable = true;
  addOnBlur = true;
  separatorKeysCodes: number[] = [ENTER, COMMA]; // Seperators for the tags
  tagCtrl = new FormControl(); // Form CTRL for tags
  filteredTags: Observable<string[]>;
  tags: string[] = ['Machine Learning'];
  // List of all the possible tags for autofill
  alltags: string[] = ['Machine Learning', 'AI', 'Deep Racer', 'Jetson Car', 'R.A.C.E.', 'News', 'Press'];

  @Input() id: string; // ID of the blog
  @Input() tagsInput: string[];
  @ViewChild('tagInput', {static: false}) tagInput: ElementRef<HTMLInputElement>;
  @ViewChild('auto', {static: false}) matAutocomplete: MatAutocomplete;

  constructor(
    private afs: AngularFirestore
  ) {
    this.filteredTags = this.tagCtrl.valueChanges.pipe(
        startWith(null),
        map((tag: string | null) => tag ? this._filter(tag) : this.alltags.slice()));
  }

  async ngOnInit() {
    // TODO Refactor this, this is messy because it's a double subscription to postDoc for no reason, just can't figure out async
    this.postDoc = this.afs.doc('posts/' + this.id);
    this.postDoc.valueChanges().subscribe(v => {
      this.tags = v.tags;
    });  }

  /**
   * Add a new chiop
   * @param event MatChipInputEvent
   */
  add(event: MatChipInputEvent): void {
    // Add tag only when MatAutocomplete is not open
    // To make sure this does not conflict with OptionSelected Event
    if (!this.matAutocomplete.isOpen && event.value) {
      const input = event.input;
      const value = event.value;

      // Add our tag
      if ((value || '').trim()) {
        this.tags.push(value.trim());
      }

      // Reset the input value
      if (input) {
        input.value = '';
      }

      // Reset form ctrl
      this.tagCtrl.setValue(null);
    }
    // Updates post with new tags
    this.postDoc.update({
      tags: this.tags
    });
  }

  /**
   * Removes tags from the list
   * @param tag text of tag
   */
  remove(tag: string): void {
    const index = this.tags.indexOf(tag);

    if (index >= 0) {
      this.tags.splice(index, 1);
    }
    this.postDoc.update({
      tags: this.tags
    });
  }

  /**
   * Handles selection of autocomplete tag
   * @param event Event when autocomplete option is selected
   */
  selected(event: MatAutocompleteSelectedEvent): void {
    // Pushes the selected autocomplete to the tag list
    this.tags.push(event.option.viewValue);
    // Resets the input
    this.tagCtrl.setValue(null);
    // Updates the database
    this.postDoc.update({
      tags: this.tags
    });
  }

  /**
   * Method to filter tags and make sure they're usable
   */
  private _filter(value: string): string[] {
    const filterValue = value.toLowerCase();

    return this.alltags.filter(tag => tag.toLowerCase().indexOf(filterValue) === 0);
  }

  // TODO WET CODE
  public getColor(tag: string): string {
    switch (tag) {
      case 'Machine Learning':
        return '#e53935';
        break;
      case 'AI':
        return '#8e24aa';
        break;
      case 'Deep Racer':
        return '#43a047';
        break;
      case 'Jetson Car':
        return '#fb8c00';
        break;
      case 'News':
        return '#00897b';
        break;
      case 'Press':
        return '#1e88e5';
        break;
      default:
        return '#546e7a';
    }
  }
}

results matching ""

    No results matching ""