User interaction results in error on ModalController

Hi there, I’m working on an Angular 7 project that utilizes Ionic v4 and there’s one page navigation from home page that has been throwing out the following error for a long time:


This navigation from home page to live newsletter page (aka the one that’s spewing out this error) is fairly straightforward.

liveNewsletter() {
	this.router.navigate(['live-newsletter']);     
}

And in the lve newsletter page ts there are a few methods that take care of modal creation, one of them, for example, looks like this:

  // 新增分配整改措施
  async addCorrectiveAction() {
    // 设置标题
    document.getElementsByTagName('title').item(0).innerText = '添加隐患';
    if (dd.env.platform !== 'notInDingTalk') {
      dd.biz.navigation.setTitle({
        title: '添加隐患', // 钉钉设置导航栏标题
      });
    }

    if (!this.form.value.physical_structure_id) { // 如果没有选择被检查工厂则不允许分配整改措施,并提示
      this.appService.toastTip('select_physical_first', true);
      return;
    }
    const modal = await this.modalCtrl.create({
      component: TaskchkAssignModalComponent,
      componentProps: {
        deviation_id: Number(this.form.controls.physical_structure_id.value),
        isLiveNewsLetter: true,
        findId: this.isTaskCenter ? this.findingDataId : null,
      },
      showBackdrop: true,
      backdropDismiss: true
    });
    modal.onDidDismiss().then(res => {
      // 设置标题
      document.getElementsByTagName('title').item(0).innerText = '隐患上报';
      if (dd.env.platform !== 'notInDingTalk') {
        dd.biz.navigation.setTitle({
          title: '隐患上报', // 钉钉设置导航栏标题
        });
      }

      if (res.data && res.data !== 'cancel' && res.data !== 'delete') {
        this.actions.push(res.data);
      }
    });
    return await modal.present();
  }

Everything looks fine and indeed it was fine for some time, and then one day it broke out of nowhere. What confuses me the most, besides the error message, is that it seems to be an issue with how ModalController is configured but I have compared this configuration of this page to another page in which opens fine and modals in that page is also working. Besides that, on another page that also utilizes ModalController when I click a button on that page that has nothing to do with modals, it also throws out this error. I have spent a whole day trying out different solutions on the Internet and nothing worked for me, so I’m hoping someone could provide some insights on how to properly solve this issue.

On a side note, if I serve or build the project with --aot parameter, upon launching it throws an error complaining about not being able to find ‘@angular/core’ module and it halts on a blank page forever. Not sure how helpful this info is but figure I should mention it in case it helps.

Does a build with —prod flag give you more meaningful errors? That is what I sometimes do to ease the search

Unfortunately no, build with --prod will result in the same state as build with --aot, with the following error:

Also here’s the error message for live build (non local build) with no --prod or --aot parameter:

Hi

I am inclined to believe, mostly from the first error message that the page calling/using the modalcontroller is not properly part of a module, likely leads to the place where modalcontroller is injected. Maybe add this page (and the modal one) to app.module.ts and see if that works, and then gradually place it in the module where you like to have it?

At least, that is what I would try. You seem to be breaking the injection mechanism.

Tom

Thanks for the reply. This page is part of its own module and I have added it into app-routing.module.ts which is imported into app.module.ts. Here’s the code snippet:

const routes: Routes = [
  { path: '', redirectTo: 'login', pathMatch: 'full' },
  { path: 'login', loadChildren: './login/login.module#LoginPageModule' },
  ...
  { path: 'live-newsletter', loadChildren: './live-newsletter/live-newsletter.module#LiveNewsletterModule' }, // 现场快报
  ...
];

I’ve omitted most of the rest of routes as they follow the exact same format as this one.
And here’s what inside live-newsletter.module.ts:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { Routes, RouterModule } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';

import { IonicModule } from '@ionic/angular';

import { LiveNewsletterPage } from './live-newsletter.page';
import { SharedModule } from '../shared';

const routes: Routes = [
  {
    path: '',
    component: LiveNewsletterPage
  }
];

@NgModule({
  declarations: [LiveNewsletterPage],
  imports: [
    CommonModule,
    FormsModule,
    IonicModule,
    SharedModule,
    TranslateModule,
    ReactiveFormsModule,
    RouterModule.forChild(routes)
  ]
})
export class LiveNewsletterModule { }

Is the modal itself included in the same module as the calling page?

It might not be the router part that invokes the error, but initialisation of the modal component even before it is opened - the modal component also needs the modalcontroller to close itself

No, because multiple modules are using these same modals so in order to avoid duplicate error from Angular they are included in app.module.ts. Here’s code snippet for app.module.ts:

import { NgModule } from '@angular/core';
import { environment } from 'src/environments/environment';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { ReactiveFormsModule } from '@angular/forms';

import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { JPush } from '@jiguang-ionic/jpush/ngx';
import { TranslateLoader, TranslateModule } from "@ngx-translate/core";
import { TranslateHttpLoader } from "@ngx-translate/http-loader";
import { HttpClient, HTTP_INTERCEPTORS, HttpClientModule } from "@angular/common/http";
import { SharedModule } from './shared';
import { CoreModule } from './core';
import { PipesModule } from './pipes/pipes.module';
import { Device } from '@ionic-native/device/ngx';
import { InAppBrowser } from '@ionic-native/in-app-browser/ngx';

import { NativeService } from './providers/NativeService';
import { DataService, AppService, LocalStorageService } from './service';
import { Diagnostic } from '@ionic-native/diagnostic/ngx';
import { Camera } from '@ionic-native/camera/ngx';
import { File } from '@ionic-native/file/ngx';
import { ImagePicker } from '@ionic-native/image-picker/ngx';
import { FileTransfer } from '@ionic-native/file-transfer/ngx';
import { PreviewPictureComponent } from './shared/components/preview-picture/preview-picture.component';
import { TaskchkAssignModalComponent } from './taskchk-assign-modal/taskchk-assign-modal.component';
import { LiveNewsletterCopyComponent } from './live-newsletter-copy/live-newsletter-copy.component';
import { PerformValidationHistoryComponent } from './perform-validation-history/perform-validation-history.component';
import { TaskAssignModalComponent } from './task-assign-modal/task-assign-modal.component';
import { CorpSelectComponent } from './shared/components/corp-select/corp-select.component';
import { CorpSelectReportComponent } from './shared/components/corp-select-report/corp-select-report.component';
import { JWTInterceptor } from './service/interceptor.service';

export function HttpLoaderFactory(http: HttpClient) {
	// 改成从environment中拿i18n文件路径
	return new TranslateHttpLoader(http, environment.i18Path, '.json');
	// return new TranslateHttpLoader(http, '../../../assets/i18n/', '.json');
	// 生产环境需要使用带app的路径
	// return new TranslateHttpLoader(http, environment.production ? '' : '../../../assets/i18n/', '.json');
}
@NgModule({
	declarations: [
		AppComponent,
		PreviewPictureComponent,     // Modal 1
		LiveNewsletterCopyComponent,
		TaskchkAssignModalComponent, // Modal 2
		PerformValidationHistoryComponent,
		TaskAssignModalComponent,
		CorpSelectComponent,         // Modal 3
		CorpSelectReportComponent
	],
	entryComponents: [
		PreviewPictureComponent,     // Modal 1
		LiveNewsletterCopyComponent,
		TaskchkAssignModalComponent, // Modal 2
		PerformValidationHistoryComponent,
		TaskAssignModalComponent,
		CorpSelectComponent,         // Modal 3
		CorpSelectReportComponent
	],
	imports: [
		BrowserModule,
		IonicModule.forRoot({
			backButtonText: '',
			// tabsHideOnSubPages: 'true',
			// iconMode: 'ios',
			animated: true,
			hardwareBackButton: true,
			swipeBackEnabled: true,
			mode: 'ios',
			// preloadModules: true
		}),
		AppRoutingModule,
		HttpClientModule,
		ReactiveFormsModule,
		SharedModule,
		CoreModule,
		TranslateModule.forRoot({
			loader: {
				provide: TranslateLoader,
				useFactory: HttpLoaderFactory,
				deps: [HttpClient]
			}
		}),
		PipesModule
	],
	providers: [
		StatusBar,
		SplashScreen,
		Device,
		DataService,
		AppService,
		LocalStorageService,
		// AppVersion,
		NativeService,
		Camera,
		Diagnostic,
		ImagePicker,
		File,
		FileTransfer,
		InAppBrowser,
		{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
		JPush,
		{
			provide: HTTP_INTERCEPTORS,
			useClass: JWTInterceptor,
			multi: true
		}
	],
	bootstrap: [AppComponent]
})
export class AppModule { }

I should also add that even after commenting out all instances of modals as well as ModalController in the calling page (including import statements and dependency injection in constructor), it’s still giving me the exact same error when I’m trying to navigate to this page. This makes me suspect that it’s not really related to ModalController but the error message thinks it’s related somehow.

Hi
Thx for trying. I am out of recommendations other then say what I do in these cases: build the app up from scratch and test if things still work.

Btw, i give my modals their own module to allow other components to use them. But I reckon putting them at app level gives the same purpose

1 Like

No worries, thanks for your suggestion. I am indeed trying to recreate this page and see at which point it breaks. So far from what I can tell is that even if I only copied and pasted HTML content into the new page, it gives the same error; whereas if I leave the HTML part blank and copied and pasted all content in ts the page opens just fine. Bizarre indeed.

1 Like

I have located the source of issue. It’s all because I’m using this component in my HTML:

<ionic-selectable #empSelect [formControl]="form.controls.accompanying_person" [isMultiple]="true"
	[items]="inspectAttendEmps" itemValueField="id" itemTextField="name" [canSearch]="true"
	searchPlaceholder="请输入" closeButtonText="{{'alert_cancel_key' | translate}}"
	[searchFailText]="'没有符合的结果'" [hasInfiniteScroll]="true" (onSearch)="searchEmp($event)"
	(onInfiniteScroll)="getMoreEmp($event)">
	<ng-template ionicSelectableFooterTemplate>
		<ion-footer class="ionic-selectable-dialog-footer">
			<ion-toolbar>
				<ion-row>
					<ion-col>
						<button ion-button full (click)="cancelSelectDialog(empSelect)">
							{{'alert_cancel_key' | translate}}
						</button>
					</ion-col>
					<ion-col>
						<button ion-button full (click)="confirm(empSelect)">
							{{'alert_confirm_key' | translate}}
						</button>
					</ion-col>
				</ion-row>
			</ion-toolbar>
		</ion-footer>
	</ng-template>
</ionic-selectable>

For whatever reason is causing all those issues all of the sudden even though I was following their instructions. Some people say it fixes the issue by updating the project to Angular 9 so I’m trying that right now.

Ok. Good luck!

(you know update.angular.io, right - to help with some of the breaking stuff)

Yes, and indeed upgrading it from 7 to 9 fixed the issue. Thanks for your help!

1 Like