Find with user-friendly input/label removal function (Ionic 2)

I have embarked on creating a recipe application where users can search for recipes by ingredients. I want to enhance the functionality of the search feature so that when users press the spacebar to enter the next input, it appears as a label below with an option to deselect by clicking on an X.

Currently, my search feature looks like this: https://i.sstatic.net/Hxcus.jpg

However, I envision it looking like this with labels underneath: https://i.sstatic.net/deIlt.png

Since this is for an Ionic 2 app, I am wondering if anyone has come across a similar implementation or tutorial? Any guidance or assistance would be greatly appreciated.

UPDATE: I recently noticed that the "Tags" section at the bottom of Stack Overflow pages showcases the exact feature I am aiming for in my app

Answer №1

If you're searching for a solution similar to this, check out the plunker example here. Although there's room for enhancements and additional validations, the demo should meet your requirements.

The code is quite simple and focuses on these key sections:

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  ...
  ...
})
export class HomePage {

  public myForm: FormGroup;
  public tags: Array<string>;

  constructor(public formBuilder: FormBuilder) {
    this.tags = ['tag1', 'tag2', 'tag3'];
    this.myForm = this.formBuilder.group({
      tags: ['']
    });

    // Implementing async validation for username
    this.myForm.get('tags')
        .valueChanges
        .subscribe((value: string) => {
          if(value.indexOf(' ') > -1) {
            let newTag = value.split(' ')[0];
            console.log(newTag);
            if(newTag) {
              this.tags.push(newTag);
              this.myForm.get('tags').setValue('');
            }
          }
        });
  }

  public deleteTag(tagName: string) {
    // Find tag index
    let index = this.tags.indexOf(tagName);

    // Remove tag from list
    this.tags.splice(index, 1);
  }
}

In the view section:

<ion-header>
  <ion-navbar>
    <ion-title>HomePage</ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>      
  <form [formGroup]="myForm">
    <ion-item>
      <ion-input formControlName="tags" type="text"></ion-input>
    </ion-item>
  </form>

  <div class="tag-container">
    <span class="tag" *ngFor="let tag of tags">
      {{ tag }}
      <ion-icon name="close" (click)="deleteTag(tag)"></ion-icon>
    </span>
  </div>
</ion-content>

Lastly, don't forget about the CSS styling:

.tag-container {
  border: 1px solid #ccc;
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
  padding: 10px;
  margin: 10px;
}

.tag {
  display: inline-block;
  background-color: #5bc0de;
  color: #fff;
  margin: 5px 5px;
  padding: 2px 5px;
}

Answer №2

To tackle this issue, I recommend focusing on the data model perspective. The key is to break down your objective to its essence: for every input event in your search field,

  1. Convert the search term into an array of words
  2. Remove the last word from the array to create a list of labels
  3. Assign the last word as the value for your input field

Consider the following scenario with a component structured like:

@Component({
  .....
  template: `
    <input [formControl]="searchControl" (input)="onSearchInput(input.value)" />
    <label *ngFor="let label of labels">{{ label }} </label>
  `
})
export class SearchComponent {
  searchControl = new FormControl('');
  labels: string[] = [];

  onSearchInput(searchValue) {
    let newSearchValues: string[] = searchValue.split(' ');
    if (newSearchValues.length > 1) {
      this.labels.push(newSearchValues[0]);
      this.searchControl.setValue(newSearchValues[1]);
    }
  }
}

Utilize @angular/forms package's FormControl to bind your search input for dynamic value updates and leverage the FormsModule functionalities. Monitor input events on your search field to dynamically manage labels and input values.

This foundation can serve as a starting point. Additional logic may be necessary to handle special cases or implement debouncing for improved functionality. Stay adaptable and explore further enhancements as needed.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Angular 6: Issue TS2339 - The attribute 'value' is not recognized on the 'HTMLElement' type

I have a textarea on my website that allows users to submit comments. I want to automatically capture the date and time when the comment is submitted, and then save it in a JSON format along with the added comment: After a comment is submitted, I would li ...

Understanding how to retrieve the value count by comparing strings in JavaScript

In my array object, I am comparing each string and incrementing the value if one letter does not match. If three characters match with the string, then I increase the count value; otherwise, it remains 0. var obj = ["race", "sack", &qu ...

What is the best way to implement pipes and incorporate reusable action buttons in a Mat-table component for maximum reusability?

I am seeking assistance in creating a reusable component for the Angular Material Mat-table. I have made progress on loading data from the parent component to the child component, as can be seen in StackBlitz, but I now want to apply pipes to the data bef ...

The HTML component fails to acknowledge width settings

I seem to be having trouble identifying an issue or perhaps I am misunderstanding something (I am using daisyui + nx + tailwind css + angular). To simplify my problem, let's consider the following scenarios: In the first scenario, I have: <div cl ...

Designing a personalized Angular package for components

I am currently working on developing reusable components that can be utilized across multiple teams. After creating a new Angular project, I went ahead and published it to Azure DevOps artifacts. When attempting to use the component in another project, I ...

Convert the XML response from an API into JSON

Is there a way to convert my XML response into JSON using Angular? This is the response I am working with: <?xml version="1.0" encoding="utf-8"?> <string xmlns="http://tempuri.org/"><?xml version="1.0" encoding="utf-8"?&gt; &lt;Fer ...

What is the process for translating the aria-label to "Open calendar" in a different language for the angular md-datepicker icon?

Check out my latest demo on using the angular md-datepicker Looking to customize or translate the aria-label text for the icon in the angular md-datepicker, as shown in the image below. ...

Troubleshooting a navigation issue in Angular involving the mat-sidenav element of material UI while transitioning between components

I would greatly appreciate your assistance in resolving the issue I am facing. I have been trying to navigate from one view to another, but when I use an <a> tag nested within a <mat-sidenav>, I encounter the following error: "Uncaught (in prom ...

Tribal Code Typescript Compiler

Typescript is a great alternative to Javascript in my opinion, but it bothers me that it requires node.js as a dependency. Additionally, I find it frustrating that there seems to be only one compiler available for this language, and it's self-hosted. ...

Obtain the object literal string with additional decorative strings surrounding it

In my current Typescript code, I have an object literal structured like this: const MyNamesStrings = { a: { b: "hello", c: "bye" } d: { e: "qwerty" } } However, I am looking for a way to wrap these strings with add ...

Unlock the encrypted information in the blockchain

I've been working on encrypting and decrypting values using Node's built-in crypto module. I found a helpful tutorial that showed me how to encrypt the data, but it didn't provide any sample code for decryption. When I tried using code from ...

Filtering data in an antd table by searching

Just starting out with React hooks, specifically using TypeScript, and I'm struggling to implement a search filter with two parameters. Currently, the search filter is only working with one parameter which is 'receiver?.name?'. However, I wo ...

"Element of design focused on style and arrangement

After reviewing the material ui documentation located at https://material-ui.com/components/typography/ I attempted to utilize the Typography component in the following manner: <Typography variant="h1" component="h1"> Hello World </Typography& ...

Encountered a problem during the installation of the Ionic framework

Despite seeking solutions in other questions and answers, I am still unable to resolve my issue. Node.js has been successfully installed on my system. Node version: 0.12.7 NPM version: 2.11.3 When attempting to install Cordova, there are warnings but it ...

Step-by-step guide on invoking an asynchronous method in canActivate for Ionic and Angular

My objective is to acquire a token for authenticating users. I am utilizing the import { Storage } from '@ionic/storage-angular'; to store the data, but I am encountering an issue where the Storage methods only function in asynchronous mode. Her ...

Can we determine the type signature of useCallback for an event handler by inference?

Currently, I am working with TypeScript and React to implement a callback function using an arrow function on a Material UI <Select> component: import React from 'react'; import MenuItem from '@material-ui/core/MenuItem'; import ...

Struggling with TypeScript and JsObservable? Let us assist you!

Having previous experience with JSRender, JSViews, and JSObservables, I recently embarked on a new project using TypeScript. Unfortunately, I am struggling to understand how to properly utilize TypeScript in my project, especially when it comes to referenc ...

After I subscribe, why do the variables of my object become undefined?

Just starting out with Angular and using Angular9. I attempted to subscribe to an observable in the following code: I have a service that makes an HTTP request and returns an Observable. The subscription appears to be working fine. ngOnInit() { this.in ...

Looking to identify the type of a adorned class in Typescript?

Consider the following scenario: return function IsDefined(object: any, propertyName: string) { .... ] We then go ahead and decorate a property like this: class Test { @IsDefined() p1: String = ""; } Now, when we execute a test inside the ...

typescript - specifying the default value for a new class instance

Is there a way to set default values for properties in TypeScript? For example, let's say we have the following class: class Person { name: string age: number constructor(name, age){ this.name = name this.age = age } } We want to ens ...