NativeScript / angular

NativeScript for Angular
https://docs.nativescript.org/tutorials/build-a-master-detail-app-with-angular
41 stars 12 forks source link

Issues with NativeScript 8 and Angular 12 concerning modals #17

Closed jessorlisa closed 3 years ago

jessorlisa commented 3 years ago

Environment

Describe the bug

Since uprading to Angular 12 the following issues occur:

  1. ScrollView within a modal is no longer working
  2. Opening a second modal from a first modal throws the following error:

    ERROR TypeError: options.parentView.showModal is not a function

To Reproduce

  1. Clone the demo repository: https://github.com/jessorlisa/issues-n8-angular12-modals
  2. Run the project ns run android (or ns run ios)
  3. Tap any list item to open first modal -> scroll does not work (1st issue)
  4. Tap on "Open 2nd modal" -> check console output for error (2nd issue)

Expected behavior

  1. Scrolling works
  2. No error, 2nd modal opens

Additional context Both scenarios worked totally fine before upgrading to Angular 12. To demonstrate it, I created a branch downgrade-to-angular-11 https://github.com/jessorlisa/issues-n8-angular12-modals/tree/downgrade-to-angular-11. Check out the branch, run ns clean and run the project again -> everything is working as expected.

I could not find any changes regading modal handling, did I miss anything? Any hint in the right direction would be welcomed.

Thanks!

edusperoni commented 3 years ago

@jessorlisa

There were very minor changes to "legacy" dialogs, mainly a couple of refactors. I'll take a look at it later today.

You could try using the new Dialog service and see if that solves it:

import NativeDialogModule on whatever module you need dialogs and use NativeDialogService to create the dialogs. The API is based off the material dialog (https://material.angular.io/components/dialog/api).

jessorlisa commented 3 years ago

@edusperoni

Thanks for looking into this 👍🏻.

Aren't dialogs something different then modals?

Hint: Both are {N}7 documentation links as sadly both ui components are not yet documented for {N}8.

edusperoni commented 3 years ago

Dialogs and modals are essentially the same thing, we just brought the implementation closer to the material spec, which is much more flexible

rob4226 commented 3 years ago

@edusperoni I am having similar issues with NativeScript 8 and Angular 12, no matter what I put in the ActionBar of a component used as a modal, only a default ActionBar is displayed, meaning only the name of the app in the ActionBar. Even the title attribute doesn't have any effect. I also tried the new NativeDialogService you mentioned, but that has the same problem regarding the ActionBar (and it displays the modal like a dialog, not full screen, which is not what I need. I want a full screen).

Any ideas? Do you need a sample repo? Thank you.

edusperoni commented 3 years ago

@Rob4226 try putting this in your component:

<Frame>
  <Page>
  <!-- your component content, including actionbar -->
  </Page>
</Frame>

By default modals don't have actionbars, I believe, and in NativeScript's design, only a Page can have an actionbar.

For full screen modals you need to specifiy the nativescript options on the second paramenter of the DialogService/ModalService function

rob4226 commented 3 years ago

Hi @edusperoni, thank you for your response. Does NS Angular even have a <Page>? I thought they were hidden under the NS Angular implementation by using <page-router-outlet>. Just FYI it was working in NS 7/ NG 11 but did something change in the newest versions?

I am using a <page-router-outlet> as the root of the modal, so I would think a Frame/Page would be created:

Open new modal:

import { ModalDialogOptions, ModalDialogService } from '@nativescript/angular';
// ...
  async openModal() {
    const options: ModalDialogOptions = {
      fullscreen: true,
      viewContainerRef: this._viewContainerRef,
    };

    return await this._modalService.showModal(TestModalRootComponent, options);
  }

Modal root:

@Component({
  selector: 'app-test-modal-root',
  template: '<page-router-outlet ></page-router-outlet>',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TestModalRootComponent implements OnInit {
  constructor(
    private _routerExtensions: RouterExtensions,
    private _activeRoute: ActivatedRoute
  ) {}

  ngOnInit(): void {
    // route is:   { path: 'test-modal', component: TestModalComponent },
    this._routerExtensions.navigate(['test-modal'], {
      relativeTo: this._activeRoute,
    });
  }
}

Modal component:

import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

import { isAndroid, isIOS } from '@nativescript/core';
import { ModalDialogParams, RouterExtensions } from '@nativescript/angular';

@Component({
  selector: 'app-test-modal',
  templateUrl: './test-modal.component.html',
  styleUrls: ['./test-modal.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TestModalComponent {
  constructor(
    private _params: ModalDialogParams,
  ) {}

  onCloseTap() {
    this._params.closeCallback('closed');
  }

  get isAndroid() {
    return isAndroid;
  }

  get isIOS() {
    return isIOS;
  }
}
<ActionBar title="Test Modal">
  <NavigationButton *ngIf="isAndroid" android.systemIcon="ic_menu_close_clear_cancel" (tap)="onCloseTap()"></NavigationButton>
  <ActionItem *ngIf="isIOS" text="Done" (tap)="onCloseTap()" ios.position="left"></ActionItem>
</ActionBar>

<ScrollView>
  <GridLayout rows="auto, auto, *" columns="*" class="test-grid">

    <Label row="0" col="0" class="test-text" textWrap="true"
      text="This is a test modal"></Label>

    <Button row="1" text="This is a button" class="-primary"></Button>

    </GridLayout>
</ScrollView>
edusperoni commented 3 years ago

@Rob4226 Nothing should have been changed around that.

page-router-outlet creates a Frame and a Page internally, so it's weird that you're having issues. I'll try to take a look into it

rob4226 commented 3 years ago

@edusperoni Ok don't worry about it then. I will keep trying to mess around with it.

jessorlisa commented 3 years ago

@edusperoni Do you have any ETA when the fix will be merged and released? Or is there anyway I can verify the fix before any release? :pray:

edusperoni commented 3 years ago

@jessorlisa if you use the new NativeDialogService, the problem doesn't occur, so you can migrate to that already.

The old modal service is deprecated and will be removed in a future release. We only kept it for backwards compatibility (as many options changed)

jessorlisa commented 3 years ago

@edusperoni Is there by any chance a sample implementation using NativeDialogService? I'm struggling with the following error:

 NullInjectorError: R3InjectorError(HomeModule)[NativeDialogService -> NativeDialogService -> NativeDialogService -> NativeDialogService]: 
   NullInjectorError: No provider for NativeDialogService!
     at NullInjector.get (file: src/webpack:/myproject/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.11077:0)
     at R3Injector.get (file: src/webpack:/myproject/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.11243:0)
     at R3Injector.get (file: src/webpack:/myproject/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.11243:0)
     at R3Injector.get (file: src/webpack:/myproject/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.11243:0)
     at NgModuleRef$1.get (file: src/webpack:/myproject/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.25339:0)
     at R3Injector.get (file: src/webpack:/myproject/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.11243:0)
     at NgModuleRef$1.get (file: src/webpack:/myproject/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.25339:0)
     at Object.get (file: src/webpack:/myproject/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.25053:0)
     at lookupTokenUsingModuleInjector (file: src/webpack:/myproject/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.3342:0)
     at getOrCreateInjectable (file: src/webpack:/myproject/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.3454:0)

I simply replaced import { ModalDialogOptions, ModalDialogService } from '@nativescript/angular'; with import { NativeDialogConfig, NativeDialogService } from '@nativescript/angular';

and

const options: ModalDialogOptions = {
    viewContainerRef: this.viewContainerRef,
    fullscreen: true, 
    context: {}
};
this.modalService.showModal(MyModalComponent, options);

with

const options: NativeDialogConfig = {
    viewContainerRef: this.viewContainerRef,
    //fullscreen: true,
    data: {}
};
this.nativeDialogService.open(MyModalComponent, options);

What am I missing? Thanks in advance for any help here.

edusperoni commented 3 years ago

You need to import the new module. On where you want to use it and you don't need to pass a viewcontainerref. You can check the NativeDialogConfig, everything should be documented and self explanatory from there.

jessorlisa commented 3 years ago

@edusperoni Aargh... Thanks, I knew I was missing something 🤷🏻‍♀️. I refactored the demo project and indeed issue 2 (opening 2nd modal) is solved. I will apply the changes to my main project.

However ScrollView within a modal is still not working - I couldn't find any solution studying the new NativeDialogService. Any ideas?

The updated demo source can be found in this branch.

edusperoni commented 3 years ago

Until that PR merges and releases you can wrap that scrollview in a Gridlayout and it should work.