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

Can you explain the concept of "Import trace for requested module" and provide instructions on how to resolve any issues that

Hello everyone, I am new to this site so please forgive me if my question is not perfect. My app was working fine without any issues until today when I tried to run npm run dev. I didn't make any changes, just ran the command and received a strange er ...

Tips for extracting data from an Angular object using the *ngFor directive

https://i.stack.imgur.com/ai7g1.png The JSON structure displayed in the image above is what I am working with. My goal is to extract the value associated with the key name. This is the approach I have taken so far: <span *ngFor="let outlet of pr ...

What is the best way to guarantee that an object contains certain fields using Partial<>?

I am dealing with a function that accepts a parameter as shown below: const handleAccount = ( account: Partial<IAccountDocument>, ... ) => { ... } It is crucial that the interface for IAccountDocument cannot be modified to avoid requiring cer ...

How can a nullable variable be converted into an interface in TypeScript?

Encountered an issue while working on a vue3.x typescript project. The vue file structure is as follows: <template> <Comp ref="compRef" /> </template> <script lang="ts" setup> import {ref} from "vue& ...

Angular - Implementing validation for maximum character length in ngx-intl-tel-input

Utilizing the ngx-intl-tel-input package in my Angular-12 project multistep has been quite promising. Below is a snippet of the code: Component: import { SearchCountryField, CountryISO, PhoneNumberFormat } from 'ngx-intl-tel-input'; expor ...

Refreshing Page and Clearing History on Login/Logout with Ionic Framework

My journey into mobile application development with Ionic has just begun. I have encountered an issue where on login and logout, the page needs to be reloaded in order to refresh the data properly. However, using $state.go('mainPage') simply take ...

Steps for incorporating a type declaration for an array of objects in a React application with TypeScript

How can I specify the type for an array of objects in React using TypeScript? Here is the code snippet: const SomeComponent = (item: string, children: any) => { //some logic } In this code, you can see that I am currently using 'any' as ...

Transforming named functions in const or class constructors with Eslint and Typescript: a guide

Lately, I've been relying heavily on the code snippet from an answer that I requested: function sameValuesAsKeys<K extends string>(...values: K[]): {readonly [P in K]: P} { const ret = {} as {[P in K]: P} values.forEach(k => ret[k] = k); ...

What is the best way to create a Typescript type consisting of only the public members of a different type?

Inside the realm of Typescript 4.3.5 In what manner can I establish a type that consists solely of the public members and properties of another type? Take into account: class Thing { public name: string private secret: string public greet(): string ...

Determine the type of a function to assign to the parent object's property

Consider the following scenario: class SomeClass { public someProperty; public someMethodA(): void { this.someProperty = this.someMethodB() } public someMethodB() { ...some code... } } I need the type of somePropert ...

A function in Typescript is created to handle diverse input types in a generic manner

My goal is to create a function that can handle various input types for abstraction purposes. type ContentA = string type ContentB = number type InputA = { name: 'method_a' content: ContentA } type InputB = { name: 'method_b' con ...

Using Angular: Binding Angular variables to HTML for display

I have a component with a ts file that contains HTML content as a variable. Let's say para1= <a href="www.google.com">sitename</a> more content I want to bind this paragraph in HTML as if it were actual HTML tags. sitename What is the ...

Step-by-step guide on how to stop CDK Drop depending on a certain condition

I'm trying to figure out how to disable dropping using CDK based on certain conditions. Specifically, I want the drop functionality to be disabled if the list I'm attempting to drop into is empty. I haven't been able to find a solution withi ...

``There is an issue with Cross-Origin Resource Sharing (CORS) in a Node.js application utilizing TypeScript

I've encountered some issues with my application, specifically regarding CORS. I suspect it may be due to a misconfiguration on my server. The problem arises when I attempt to create a user in my PostgreeSQL database via the frontend. I have a tsx com ...

Unexpected token @ while using Angular2 with jspm and gulp for typescript compilation

Recently, I've delved into learning about Angular 2 and its accompanying technologies. In an attempt to create minified and "compiled" versions of my .ts files, I started using gulp-jspm-build. However, I encountered an error that has left me stumped. ...

Encountering problems during the installation of Ionic - Error code 'EPROTO'

After attempting to install Ionic on my system, I encountered the following error message: npm ERR! code EPROTO npm ERR! errno EPROTO npm ERR! request to https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz failed, reason: write EPROTO 0:er ...

Tips and tricks for accessing the state tree within effects in @ngrx/effects 2.x

I am currently in the process of migrating my code from version 1.x to 2.x of @ngrx/effects. Previously, in version 1.x, I was able to access the state tree directly within an effect: constructor(private updates$: StateUpdates<AppState>) {} @E ...

How to easily upload zip files in Angular 8

Currently, I am working on integrating zip file upload feature into my Angular 8 application. There are 3 specific requirements that need to be met: 1. Only allow uploading of zip files; display an error message for other file types 2. Restrict the file s ...

After updating to ionic-native 2.5.1, encountering TypeScript Error TS1005 in Ionic 2

After updating to the latest version of ionic-native (2.5.1) in my ionic 2 project, I am encountering Typescript errors when running "ionic serve" in my terminal. I have attempted to update the typescript version to 2.x but to no avail. Any assistance woul ...

Issue with setting context.cookies in Deno oak v10.5.1 not resolved

When I try to set cookies in oak, the cookies property of the context doesn't seem to update and always returns undefined. This happens even when following the example provided in their documentation. app.use(async ctx => { try { const ...