Main component's ngOnInit fires twice on startup


#1

Any ideas why when running tns run android the main component’s ngOnInit function runs twice?

Here are relevant bootstrap files from my project.

main.ts

import { platformNativeScriptDynamic } from 'nativescript-angular/platform';
import { AppModule } from './app.module';

platformNativeScriptDynamic({startPageActionBarHidden: true}).bootstrapModule(AppModule);

main.aot.ts

import { platformNativeScript } from "nativescript-angular/platform-static";
import { AppModuleNgFactory } from "./app.module.ngfactory";

platformNativeScript({startPageActionBarHidden: true}).bootstrapModuleFactory(AppModuleNgFactory);

app.module.ts

import { NativeScriptModule } from 'nativescript-angular/nativescript.module';
.... many more imports...

import * as frescoModule from "nativescript-fresco";
import * as applicationModule from "application";
import {TKIfAndroidDirective, TKIfIOSDirective} from "./shared/platform.directive";
import {PickerSearchPipe} from "./pages/modals/picker-search.pipe";
import {SyncStatusObservationPipe} from "./pages/sync/syncStatusObservation.pipe";
import {SiteVisitDetailsReminderModal} from "./pages/observe/modals/site-visit-details-reminder-modal";
import {ToolTipModal} from "./pages/observe/modals/tooltip";

if (applicationModule.android) {
    applicationModule.on("launch", () => {
        frescoModule.initialize();
    });
}

// registerElement("CheckBox", () => require("nativescript-checkbox").CheckBox);
// registerElement("RadListView", () => require("nativescript-telerik-ui/listview").RadListView);
// registerElement("MaterialDropdownList", () => require("nativescript-materialdropdownlist").MaterialDropdo nList);
// registerElement("DropDown", () => require("nativescript-drop-down/drop-down").DropDown);
@NgModule({
    schemas: [NO_ERRORS_SCHEMA],
    providers: [
        AbundanceCategoriesService,
        AbundanceValuesService,
        AbundanceCategoriesAbundanceValuesService,
        DatabaseService,
        SyncService,
        NetworkMonitorService,
        OauthService,
        SitesService,
        IndividualsService,
        PeopleService,
        PhenophasesService,
        PhenophaseDefinitionsService,
        ProtocolPhenophasesService,
        SpeciesService,
        SpeciesProtocolsService,
        SpeciesSpecificPhenophaseInformationService,
        SpeciesTypesService,
        SpeciesSpeciesTypesService,
        AccountService,
        NetworksService,
        NetworkPeopleService,
        SettingsService,
        ObservationsService,
        ObservationGroupsService,
        ModalDialogService,
        ObserveService
    ],
    declarations: [
        AppComponent,
        LoginComponent,
        GroupsComponent,
        SitesComponent,
        NewSiteComponent,
        IndividualsComponent,
        ObserveComponent,
        SiteVisitDetailsComponent,
        PlantsComponent,
        AccountsComponent,
        SyncComponent,
        SyncingComponent,
        SettingsComponent,
        DebugComponent,
        SiteCreationModal,
        SiteInfoModal,
        PickerModal,
        DateTimePickerModal,
        PhenophaseInfoModal,
        IndividualInfoModal,
        NewIndividualModal,
        SiteVisitDetailsReminderModal,
        ToolTipModal,
        JoinGroupModal,
        AnimalsChecklistComponent,
        AnimalsComponent,
        SitesPipe,
        PlantsPipe,
        AnimalsPipe,
        SpeciesPipe,
        PickerSearchPipe,
        GroupsPipe,
        SyncStatusObservationPipe,
        TKIfAndroidDirective,
        TKIfIOSDirective
    ],
    entryComponents: [
        SiteCreationModal,
        SiteInfoModal,
        IndividualInfoModal,
        PickerModal,
        NewIndividualModal,
        JoinGroupModal,
        DateTimePickerModal,
        PhenophaseInfoModal,
        SiteVisitDetailsReminderModal,
        ToolTipModal
    ],
    bootstrap: [
        AppComponent
    ],
    imports: [
        NativeScriptModule,
        NativeScriptAnimationsModule,
        NativeScriptRouterModule,
        routing,
        NativeScriptHttpModule,
        NativeScriptFormsModule,
        FormsModule,
        TNSFrescoModule
    ]
})
export class AppModule {}

Here is a snippet of console output when running tns run android that shows logs of ngOnInit, ngAfterViewInit, and the constructor:

Successfully transferred app.component.js.
Refreshing application...
Successfully synced application org.nativescript.testapp on device ZY222W4LPP.
Executing before-watch hook from D:\npn\testapp\hooks\before-watch\nativescript-dev-sass.js
Found peer node-sass
Executing before-watch hook from D:\npn\testapp\hooks\before-watch\nativescript-dev-typescript.js
Found peer TypeScript 2.4.2
ActivityManager: Start proc 11671:org.nativescript.testapp/u0a982 for activity org.nativescript.testapp/com.tns.NativeScriptActivity
JS: in constructor  of app.component.ts------------------------------
JS: app.component.ts ngOnInit!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
JS: is ngAfterViewInit called twice????????????????
JS: Angular is running in the development mode. Call enableProdMode() to enable the production mode.
JS: in constructor  of app.component.ts------------------------------
JS: ANGULAR BOOTSTRAP DONE. 5495
JS: app.component.ts ngOnInit!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
JS: is ngAfterViewInit called twice????????????????
1:24:19 PM - Compilation complete. Watching for file changes.

As an aside I think this has been an issue in this project for months but only recently got my attention because inside ngOnInit I added a function registration to allow back navigation via the android back button and since ngOnInit was called twice function is registered twice and so the back function also get’s called twice:

// the below lines get called inside ngOnInit()
// app.android.removeEventListener(AndroidApplication.activityBackPressedEvent);
app.android.on(AndroidApplication.activityBackPressedEvent, (data: AndroidActivityBackPressedEventData) => {
                console.log('testing back intercept!!!!!!!!!!'); // i see this logged twice
                data.cancel = true; // prevents default back button behavior
                this._routerExtensions.back();
            });

I can fix the side effect by uncommenting the removeEventListener line above, but the root problem of ngOnInit getting called twice still exists.


#2

I also got this issue, do you found how to resolve?


#3

No, it is still an issue for me.


#4

Still an issue for me as well. Gonna check their github and make an Issue out of it. I can replicate on my real device.

Edit:
Took the component outside of bootstrap and my problem is gone. I have 2 roots for my app. One appcomponent only for Login and one maincomponent for everything else. Maybe you guys can implement that in the mean time?


#5

Interesting, trying to understand what you mean by breaking your app into two root components. If you do end up making a GitHub issue it’d be awesome if you link to it from here. Thanks!


#6

Sorry I never made any issue. The architecture of my app follows this here: https://stackoverflow.com/questions/41888873/how-to-use-separate-layout-for-login-component-in-angular-2

Some dev on my team bootstrapped the second component for some reason, so on start of the app, the second root component initiated without my consent.

I just removed it and it works as expected.