Is there a way to ensure that the onChange event of ionic-selectable is triggered twice?

I've been working with an ionic app that utilizes the ionic-selectable plugin, and for the most part, it's been running smoothly. However, I encountered a rare scenario where if a user on a slow device quickly clicks on a selection twice in succession, an error occurs.

Error: Uncaught (in promise): IonicSelectable is disabled or already closed

I suspect this happens because the component IonicSelectableComponent is being called twice. Therefore, I am looking to ensure that the onChange event is triggered only once and cannot be activated again by a rapid subsequent click.

Is there a way to achieve this?

HTML

<form #NameFour="ngForm">
  <ion-item>
    <ion-label class="ion-text-wrap" position="stacked">{{ 'NEW.countrycode' | translate }} <span style="color:red">*</span></ion-label>
    <ionic-selectable 
      name="countrycode" 
      *ngIf="loadValue(i,p)" 
      placeholder="Please select country"
      class="form-control" 
      required 
      [(ngModel)]="CountryInput"
      [items]="countryCodesService.countryCodeArray" 
      itemValueField="code" 
      itemTextField="name"
      [canSearch]="true" 
      (onChange)="changeCountryCode($event,i,p)">
      <ng-template ionicSelectableItemTemplate let-CountryInput="item">
        {{CountryInput.name}} [+{{CountryInput.code}}]
      </ng-template>
      <ng-template ionicSelectableValueTemplate let-CountryInput="value">
        {{CountryInput.name}} [+{{CountryInput.code}}]
      </ng-template>
    </ionic-selectable>
  </ion-item>
</form>

.ts

changeCountryCode(event: { component: IonicSelectableComponent, value: any },i: string | 
number, p: string | number){
  this.CountryISO = this.CountryInput.acronym;
  this.CountryCode = this.CountryInput.code;
}

Answer №1

This issue is documented in the official documentation (seemingly a frequently encountered issue): https://github.com/eakoriakin/ionic-selectable/wiki#ionicselectable-is-disabled-or-already-closed

...

The error arises when the close() method is called while the component is disabled or already closed.

Important: Ionic will only display the error during development mode when running the application with ionic serve.

Solution

Although this error won't occur in production mode, you can still prevent it by utilizing catch.

this.portComponent.close().catch(() => { });

Alternatively, you can check the isEnabled and isOpened fields.

if (this.portComponent.isEnabled && this.portComponent.isOpened) {
 this.portComponent.close();
}

It appears that clicking twice triggers the first click to attempt closing the modal followed by the second click also attempting to close it even though it was already closed by the initial click.

You can observe this behavior by examining the source code of the component (https://github.com/eakoriakin/ionic-selectable/blob/master/src/app/components/ionic-selectable/ionic-selectable.component.ts#L1574):

 close(): Promise<void> {
    const self = this;

    return new Promise(function (resolve, reject) {
      if (!self._isEnabled || !self._isOpened) {
        reject('IonicSelectable is disabled or already closed.');
        return;
      }

      self.propagateOnTouched();
      self._isOpened = false;
      self._itemToAdd = null;
      self._modal.dismiss().then(() => {
        self._setIonItemHasFocus(false);
        self.hideAddItemTemplate();
        resolve();
      });
    });
  }

The first click sets self._isOpened = false;, and upon the second click, the promise is rejected because _isOpened is already false, leading to this unhandled rejection within the component's internal operations.

If you wish to prevent this error, you could modify the plugin by adding a catch(e => { }); whenever the close() method is invoked:

_close() {
    this.close()
      .then(() => {
        this.onClose.emit({
          component: this
        });
      })
      .catch(e => { }); // <--- here!

    if (!this._hasOnSearch()) {
      this._searchText = '';
      this._setHasSearchText();
    }
  }

Similarly, add the catch statement here as well:

_clear() {
    const selectedItems = this._selectedItems;

    this.clear();
    this._emitValueChange();
    this._emitOnClear(selectedItems);

    this.close()
      .then(() => {
        this.onClose.emit({
          component: this
        });
      })
      .catch(e => {}); // <--- here!

  }

By implementing these changes, the second click will be disregarded silently without triggering any errors.

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

Http' does not have the 'update' property

I recently implemented Angular 2 Release and utilized 'Http' from '@angular/http' for my project. However, I encountered an error when I invoked the method 'update', which resulted in the following message: "Evidently, th ...

Extending the declaration of JavaScript native methods is not possible when using TypeScript

When attempting to enhance the JS native String class by adding a new method, I encounter error TS2339. interface String { transl(): string; } String.prototype.transl = function() { // TS2339: Property 'transl' does not exist on type 'St ...

Create an alternate name for a specific type of key within a nested record

There are three simple types available: const structureTypes = z.enum(["atom","molecule"]) const atomTypes = z.enum(["oxygen","hydrogen"]) const moleculeTypes = z.enum(["water","ammonia"]) The goal is to define a type for a cache where the keys correspond ...

Exploring the World of ESLint, Prettier, Typescript, and VScode Configuration

There is a common belief that Prettier is the preferred tool for formatting, while ESlint is recommended for highlighting linting errors, even though ESlint also has formatting capabilities. However, it should be noted that Prettier lacks certain advanced ...

The partial template is not functioning as anticipated

Introducing an interface designed to accept two templates, with the resulting function being a partial of one of them (similar to React-Redux): export type IState<TState, TOwnProps> = { connect: (mapStateToProps: MapStateToProps<TState, Parti ...

Kendo's comboBox for local virtualization

Looking to implement virtualization for local data using the kendo object ComboBox. I've tried different methods, but only the current page (first 40 elements) is displayed. I followed a code structure similar to the kendo virtualization tutorial an ...

Despite being listed in the entry components, HelloComponent is not actually included in the NgModule

Check out my StackBlitz demo where I am experimenting with dynamically instantiating the HelloComponent using the ReflexiveInjector. The HelloComponent is added to the app modules entryComponents array. Despite this setup, I am still encountering the foll ...

Issue: The 'typeOf' function is not exported by the index.js file in the node_modules eact-is folder, which is causing an import error in the styled-components.browser.esm.js file in the node_modulesstyled

Every time I attempt to start running, there are issues with breaks in npm start (microbundle-crl --no-compress --format modern,cjs) I have attempted deleting node_modules and package-lock.json, then running npm i again but it hasn't resolved the pro ...

Leverage the power of react-redux useSelector with the precision of TypeScript

When attempting to utilize the new useSelector hook (shown in the example below) from react-redux in TypeScript, an error is encountered indicating that the function does not exist: Module '"../../../node_modules/@types/react-redux"' has no expo ...

Getting the perfect typings installed from DefinitelyTyped

In my current attempt to install typings (version 1.3.2) for the malihu-custom-scrollbar-plugin, I am facing an issue with some wrong type identification error (Error TS1110: Type expected). This error is caused by the use of string literal types syntax li ...

Angular 8: Syncing Component Values with Service Updates

My Angular 8 project features two sibling components that utilize a service to manage restaurant data. One component displays a list of restaurants fetched from an api, while the other component filters the displayed restaurants based on user input. Despit ...

How can I successfully transmit the entire event during the (change) event binding with ng-select in Angular 14?

I'm working on Front end Code <ng-select formControlName="constituencyId" placeholder="Select Constituency" (change)='onContituencyChanged($event)'> > &l ...

Using Two Unique Typeface Options in Material UI for ReactJS

Currently, in my React App, I am utilizing the Material UI library with Typescript instead of regular Javascript. I've encountered a small hurdle that I can't seem to overcome. The two typefaces I want to incorporate into my app are: Circular-S ...

Prevent methods from being called in a Typescript class after they have already

I encountered a scenario where I need to exclude certain methods from the return type of a class method once they have been called. Consider a class named Setup with methods step1, step2, and step3. class Setup { step1() { return this; } ...

TypeScript is throwing an error because a value has been declared but never actually used in the

private tree_widget: ITreeWidget; private $ghost: JQuery | null; private drag_element: DragElement | null; private previous_ghost: IDropHint | null; private open_folder_timer: number | null; constructor(tree_widget: ITreeWidget) { this.tree_widget = t ...

Customizable TypeScript interface with built-in default key value types that can be easily extended

One common pattern that arises frequently in my projects involves fetching values and updating the UI based on the 'requestStatus' and other associated values. type RequestStatus = | 'pending' | 'requesting' | 'succ ...

Determining if an item is empty, undefined, or null in Angular: a guide

I received a .json file structured as data [0 ... n]. Each position in the data array contains an object with various attributes, such as: {photo1, photo2, photo3 ... photoN} For a visual representation of how the json file is formatted, you can check ...

I am unable to utilize the Web Share API for sharing a file within my React app written in TypeScript

Trying to launch a WebApp for sharing files has been quite a challenge. After some thorough research, I stumbled upon the Web Share API which seemed like the perfect solution based on standard practices. The documentation provided a clear outline of how it ...

"Optimizing Performance: Discovering Effective Data Caching

As a developer, I have created two functions - one called Get to fetch data by id from the database and cache it, and another called POST to update data in the database. However, I am facing an issue where I need to cache after both the get and update oper ...

Function that yields promise result

I need help figuring out how to make this recursive function return a promise value. I've attempted various approaches, but they all resulted in the search variable ending up as undefined. public search(message: Message) { let searchResult: strin ...