Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(positioning): angular 2.2 modal.show is throwing issue #986

Closed
escarabin opened this issue Sep 15, 2016 · 65 comments
Closed

fix(positioning): angular 2.2 modal.show is throwing issue #986

escarabin opened this issue Sep 15, 2016 · 65 comments
Assignees
Labels

Comments

@escarabin
Copy link

escarabin commented Sep 15, 2016

Angular v2.2 broke our get root view component ref hack
temporary workaround:

  1. Add ComponentsHelper to AppModule (root module)
import {ComponentsHelper} from 'ng2-bootstrap/ng2-bootstrap'
// ...
providers: [{provide: ComponentsHelper, useClass: ComponentsHelper}],
  1. Set root view component ref explicitly in AppComponent (root component)
  public constructor(componentsHelper:ComponentsHelper, vcr:ViewContainerRef) {
    componentsHelper.setRootViewContainerRef(vcr);
  }

I am facing an issue with my ng2-bootstrap modals. For some reason, I am not able to show them.

Here is my HTML :

<button (click)="testModal.show()">Show this modal</button>

<div bsModal
     #testModal="bs-modal"
     class="modal fade"
     tabindex="-1"
     role="dialog"
     aria-hidden="true">
    <div class="modal-dialog modal-md">
        <div class="modal-content">
            <div class="modal-body">
                TEST
            </div>
        </div>
    </div>
</div>

Here is my NgModule:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { MODAL_DIRECTIVES } from 'ng2-bootstrap/ng2-bootstrap';

@NgModule({
    declarations: [ MODAL_DIRECTIVES],
    exports:      [ MODAL_DIRECTIVES],
    imports:      [ BrowserModule,
                    FormsModule,
                    HttpModule ],
})
export class SharedModule {}

I see this error in the log console :
Error: Uncaught (in promise): Token must be defined!
and the modal does not show up

I am running Angular 2 RC5.
Is there something I am missing here?

@valorkin
Copy link
Member

Forget about directives, use exported modules

@valorkin
Copy link
Member

We need to update docs... fast ;(

@escarabin escarabin reopened this Sep 22, 2016
@escarabin
Copy link
Author

escarabin commented Sep 22, 2016

Thanks for your help, I am now running ng2-bootstrap@1.1.0.

So I now have a shared module which contains all of the bootstrap modules I am using in the app.
Here is my shared.module.ts:

mport { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { RouterModule } from '@angular/router';

// Bootstrap modules
import { ButtonsModule, ModalModule, CollapseModule, AccordionModule } from 'ng2-bootstrap/ng2-bootstrap';

@NgModule({
    exports:      [ ButtonsModule,
                    CollapseModule,
                    AccordionModule,
                    ModalModule ],
    imports:      [ BrowserModule,
                    FormsModule,
                    HttpModule,
                    RouterModule,
                    ButtonsModule,
                    CollapseModule,
                    AccordionModule,
                    ModalModule ],
})

export class SharedModule {}

Here is my app.module.ts:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { RouterModule } from '@angular/router';
import { routing } from './app.routes';
import { SharedModule } from './shared/shared.module';

@NgModule({
    imports:      [ BrowserModule,
                    RouterModule,
                    FormsModule,
                    HttpModule,
                    SharedModule,
                    routing ],
    bootstrap:    [ AppComponent ],
})
export class AppModule {}

For some reason, the error "Token must be defined" still shows up when trying to show a modal and I am not using directives anymore.

@Martin-Luft
Copy link
Contributor

@escarabin is this still an issue in v1.1.5?

@Martin-Luft
Copy link
Contributor

No reaction -> close...

@escarabin
Copy link
Author

escarabin commented Sep 30, 2016

Really sorry about that. I just updated to v1.1.5 and the error has changed to "Cannot read property 'instance' of undefined"

Here is a full screenshot of the log:
screen shot 2016-09-30 at 11 39 19

I hope it is not too late to request some help on this...

@Martin-Luft Martin-Luft reopened this Oct 4, 2016
@Martin-Luft
Copy link
Contributor

Can you please provide the current HTML-Template, the related component and your ngModule code?

@valorkin
Copy link
Member

valorkin commented Oct 4, 2016

http://bit.ly/ng2-bootstrap-plnkr
Here is plunkr, use it to reproduce issue

@escarabin
Copy link
Author

I don't get it. It is working in my Plunkr... https://plnkr.co/edit/qFzk0ysRQwbg7vvrkN44?p=preview I am going to investigate more into my code and get back to you if I find any solution.

@escarabin
Copy link
Author

I updated to v1.1.6 tough. The error has now changed to "applicationRef instance not found" when I try to open a modal.

@valorkin
Copy link
Member

valorkin commented Oct 4, 2016

How do you bootstrap your application?

@escarabin
Copy link
Author

escarabin commented Oct 4, 2016

I have a boot.ts file that looks like this:

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

platformBrowserDynamic().bootstrapModule(AppModule);

And it is loaded by systemJS inside my HTML head tag :

<script src="systemjs.config.js"></script>
    <script>
        System.config({
            "defaultJSExtensions": true,
            packages: {
                app: {
                    format: 'register',
                    defaultExtension: 'js'
                }
            }
        });


        System.import('js/typescript/boot')
                .then(null, console.error.bind(console));
    </script>

@valorkin
Copy link
Member

valorkin commented Oct 4, 2016

can you try to import ng2 bs like this: https://github.com/valor-software/angular2-quickstart/blob/master/index.html#L16

and compare your system.js config to sample one?

@escarabin
Copy link
Author

escarabin commented Oct 4, 2016

I just tried what you suggest and and got same result.

Actually I also tried to show up a modal inside components of my app.module.ts and it worked. The issue seems to happen only inside component of child modules. In all of my child modules.

@valorkin
Copy link
Member

valorkin commented Oct 4, 2016

sorry, but without reproduce sample, I will not be able to help you :(

@Martin-Luft
Copy link
Contributor

In other systemjs issues the problem was: format: 'register',can you try to remove it?

@Martin-Luft
Copy link
Contributor

@escarabin is your problem solved? Can I close this issue?

@escarabin
Copy link
Author

Sorry but it is not solved actually. I will be working on a fix today and will let you know if I find something, it might be useful for others.

@JFMueller
Copy link

JFMueller commented Oct 10, 2016

Just wanted to verify https://github.com/escarabin. Facing a similar error message with ng2-bootstrap version 1.1.12 the moment I try to invoke:
someModal.show();

Error in some.component.html caused by: ApplicationRef instance not found

export class SomeComponent {
    @ViewChild('someModal') public someModal: ModalDirective;

    public show():void { this.someModal.show(); }

    public hide():void { this.someModal.hide(); }
}

Works fine when loaded in the browser, but fails when executed in a test run by karma. The interesting thing is: Running the following while testing does not lead to any errors:
someModal.hide();
I'm sure I miss something for karma.conf.js or karma.shim.js but I do not have any idea what it could be.

@escarabin
Copy link
Author

escarabin commented Oct 11, 2016

Hey @JFMueller!
Feels good not be alone on that ship. Actually I am facing this error on both Safari, Chrome & Firefox browsers. I am using someModal.show(); in my HTML though

But I also confirm that I am not encountering any issues with using someModal.hide();.

I will try to include someModal.show(); in a typescript function to see if it could be a solution for me but this would still be a workaround.

EDIT : I am using v1.1.6 though. I don't think you should be using ModalDirective anymore.

EDIT : After some testing, I am getting the same error when launching this.someModal.show(); inside a typescript function of my component

@valorkin valorkin changed the title Error: Token must be defined! fix(testing): modal.show is throwing issue Oct 13, 2016
@tushar-chauhan
Copy link

@JFMueller I am using v1.1.14 and getting the same error(ApplicationRef instance not found) as you are getting, while testing. Everything works fine in browser though. Where you able to find out a solution?

@conor-mac-aoidh
Copy link

conor-mac-aoidh commented Nov 4, 2016

Hi,

I am also seeing the same issue. It seems to be a timing issue. When I do the following:

import { Component, ViewContainerRef, AfterViewInit, ViewChild } from '@angular/core';
import { LoginModalComponent } from './login-modal/login-modal.component';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements AfterViewInit {
  private viewContainerRef: ViewContainerRef;

  @ViewChild(LoginModalComponent)
  public loginModal: LoginModalComponent;

  title = 'Hello World!';

  public constructor(viewContainerRef: ViewContainerRef) {
    this.viewContainerRef = viewContainerRef;
  }

  public ngAfterViewInit() {
    this.loginModal.modal.show();
  }
}

Then I get the below error:

error_handler.js:53 Error: ApplicationRef instance not found
    at ComponentsHelper.getRootViewContainerRef (components-helper.service.js:50)
    at ComponentsHelper.appendNextToRoot (components-helper.service.js:94)
    at ModalDirective.showBackdrop (modal.component.js:191)
    at ModalDirective.show (modal.component.js:108)
    at AppComponent.ngAfterViewInit (app.component.ts:22)
    at _View_AppComponent_Host0.detectChangesInternal (host.ngfactory.js:36)
    at _View_AppComponent_Host0.AppView.detectChanges (view.js:219)
    at _View_AppComponent_Host0.DebugAppView.detectChanges (view.js:324)
    at ViewRef_.detectChanges (view_ref.js:130)
    at application_ref.js:437

It seems that there are no components registered in this.applicationRef.components at this stage, which is why the above error occurs.. Moving the this.loginModal.modal.show(); into a click directive, then it works fine..

@lucienimmink
Copy link

I have the above issue (applicationref instance not found); but mine is triggered from a click function.
seesm like angular 2.2.0 is doing something different from 2.1.2.

@valorkin
Copy link
Member

ng2 v2.2 added a breaking change to internals working on it

@valorkin valorkin self-assigned this Dec 9, 2016
@valorkin valorkin added WIP and removed blocked labels Dec 9, 2016
@rafalkasa
Copy link
Contributor

@valorkin It will be very appreciated

@zackarychapple
Copy link
Contributor

Looking forward to this!

@zackarychapple
Copy link
Contributor

So after talking to @valorkin he let me know that the answer (for now) is at the very top of this thread. I just failed at reading the entire thing lol.
For anyone not wanting to read through the whole post you need to do two things.

Add the following to your constructor.

constructor(private componentsHelper: ComponentsHelper, private vcr: ViewContainerRef) {
    componentsHelper.setRootViewContainerRef(vcr);
  }

And add the following to your imports

import { ViewContainerRef } from '@angular/core';
import { ComponentsHelper } from 'ng2-bootstrap';

#986 (comment)

@valorkin
Copy link
Member

valorkin commented Dec 9, 2016

import { ComponentsHelper } from 'ng2-bootstrap';
works starting from v1.1.16-3

and if your had import ... from 'ng2-bootstrap/componets/alert'
now it is just ng2-bootstrap/alert

@valorkin
Copy link
Member

valorkin commented Dec 9, 2016

ok, guys new injection service is working ;)
so I will be updating components to use new service
most probably I will do release with next tag,
on Monday when QA will approve this version it will marked as latest

@born2net
Copy link

ya same issue, can't get modal to work...

@valorkin
Copy link
Member

https://github.com/valor-software/ng2-bootstrap/pull/1318/files#diff-47917cb7752d9ff4c3eddfa99fba920c

working on it, in a while you can check how popovers look like inside ;)

@thucnguyen77
Copy link

thucnguyen77 commented Dec 19, 2016

While the given workaround did not fix the issue, here is the version that works for me.

import { Component, ViewContainerRef } from '@angular/core';
import { ComponentsHelper } from 'ng2-bootstrap/ng2-bootstrap';

ComponentsHelper.prototype.getRootViewContainerRef = function () {
    // https://github.com/angular/angular/issues/9293
    if (this.root) {
        return this.root;
    }
    var comps = this.applicationRef.components;
    if (!comps.length) {
        throw new Error("ApplicationRef instance not found");
    }
    try {
        /* one more ugly hack, read issue above for details */
        var rootComponent = this.applicationRef._rootComponents[0];
        //this.root = rootComponent._hostElement.vcRef;
        this.root = rootComponent._component.viewContainerRef;
        return this.root;
    }
    catch (e) {
        throw new Error("ApplicationRef instance not found");
    }
};

@Component({
  selector: '......',
  template: "......"
})
export class AppComponent {
  // As instructed at http://valor-software.com/ng2-bootstrap/#/modals
  private viewContainerRef: ViewContainerRef;
  public constructor(viewContainerRef: ViewContainerRef) {
    // You need this small hack in order to catch application root view container ref
    this.viewContainerRef = viewContainerRef;
  }
}

@smnbbrv
Copy link

smnbbrv commented Dec 19, 2016

@valorkin will you add some comments on #986 (comment) please? This injection is really weird, especially if one wants to ship the modals within another module; I need to force people to make this injection in their project just because... Because what?

@valorkin
Copy link
Member

There are v1.1.16-7
Component helper removed completely, works with 2.3 too
New docs preview available here
http://valorkin.github.io/ng2-bootstrap/

@valorkin
Copy link
Member

Pay attention to forRoot

@stripathix
Copy link

Works with v1.1.16-7 :-)

@quiringk
Copy link

quiringk commented Dec 20, 2016

@valorkin I tried installing v1.1.16-7 and am getting 404's for component-loader.js and positioning.js. I am using systemjs. Does this work with systemjs or do I need to switch to webpack/CLI?

@quiringk
Copy link

NVM I got it working. Had to add .forRoot() to every imported ng2-bootstrap module. And then had to change systemjs like so:

from
'ng2-bootstrap':'npm:ng2-bootstrap',
to
'ng2-bootstrap/ng2-bootstrap':'npm:ng2-bootstrap/bundles/ng2-bootstrap.umd.js',

@valorkin
Copy link
Member

valorkin commented Dec 20, 2016

@crh225 you know that such words can harm? please don't write such things
I am investing huge amount of time in this project

@valorkin
Copy link
Member

ng4 will be released in march
until that time this project will be renamed
to ngx or ng

@conor-mac-aoidh
Copy link

@valorkin Thanks for your time on this project it is very helpful to have this module! Keep up the good work!

@valorkin
Copy link
Member

@conor-mac-aoidh thank you! ;)
reworking docs at the moment, this is how I want to see them at the end
only alert samples are deployed at the moment
http://valorkin.github.io/ng2-bootstrap/#/alerts

@smnbbrv
Copy link

smnbbrv commented Dec 20, 2016

@valorkin @conor-mac-aoidh usually +1 is not the best thing to do but I cannot avoid it. Thank you for your contribution to the development of angular2 and its community 👍 ! I believe this project helps lots of people and makes angular2 closer to the not experienced users. Don't listen to the ugly people, listen to the good ones :)

@born2net
Copy link

same here, amazing job and THANKS for the effort, sure is appreciated!!
Sean

@valorkin
Copy link
Member

Thanks you so much ;)

@RomaDotDev
Copy link

@valorkin This issue still persists during runtime of AoT build when I add bsModal div and use shared module to include 'ng2-bootstrap' modules.

EXCEPTION: Uncaught (in promise): Error: Token must be defined!
Error: Token must be defined!

I use Angular 2.4.1, ng2-bootstrap 1.1.16-11

Here is a repo with steps to reproduce:
https://github.com/irsick/ng2-bootstrap-bsModals-issue

Not sure if it's systemjs-specific issue. Apologize in advance if so =)

@TyGp
Copy link

TyGp commented Jan 14, 2017

I use the workaround as described at the top and it worked wel using angular 2.4.3 and ng2-bootstrap v1.1.16. After upgrade to ng2-bootstrap V1.2.1 it breaks and complains that the componentshelper is not exported anymore. The ng2-bootstrap document states that this component is removed.

@sweeneyrobb
Copy link

@TyGp we had this very same issue yesterday. i cloned our repo on another machine and ran npm install we had our package.json set to take major versions of ng2-bootstrap (ala "ng2-bootstrap": "^1.1.16"). Seems like the workaround mentioned here is no longer needed. We removed workaround code mentioned here.

However, we ran quickly into two other breaking changes.

  1. systemjs.config.js needed some tweaking. You can see that from the ng2-bootstrap Sample Repository https://github.com/valor-software/angular2-quickstart
  2. Looks like ng2-bootstrap has modules for each of the features. as you can see from the demo/doc site http://valor-software.com/ng2-bootstrap/#/modals. So, we removed reference to Ng2BootstrapModule and added reference to each feature module. you'll want to make sure you note the .forRoot() on the imports array

Most of this stuff is mentioned on the project page. It was our mistake to leave ourselves open to breaking changes via the ^ notation in our package.json. We updated this to ~ to make our updates a bit more intentional. Hope this helps.

@dessalines
Copy link

dessalines commented Apr 22, 2017

This is broken in angular 4 again, and now ComponentsHelper has been removed. I'm unable to show modals from typescript.

EDIT: nm, figured it out, I need to add <script>window.__theme = 'bs4';</script> to the index.html. This should be more prominent on the bootstrap 4 page though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests