5

I'm new to Bootstrap and trying to activate the .collapse() function from Javascript in an Angular controller when a user clicks on a link. This should close the collapsible navbar when one of the links is clicked (because the routing is controlled by Angular and doesn't cause a page refresh).

The following error shows:

ERROR TypeError: $(...).collapse is not a function
    at HTMLAnchorElement.<anonymous> (header.component.ts:18)
    at HTMLAnchorElement.dispatch (jquery.js:5183)
    at HTMLAnchorElement.elemData.handle (jquery.js:4991)
    at ZoneDelegate.webpackJsonp../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421)
    at Object.onInvokeTask (core.js:4740)
    at ZoneDelegate.webpackJsonp../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:420)
    at Zone.webpackJsonp../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:188)
    at ZoneTask.webpackJsonp../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask [as invoke] (zone.js:496)
    at invokeTask (zone.js:1540)
    at HTMLAnchorElement.globalZoneAwareCallback (zone.js:1577)

Relevant part of HTML template:

<div class='collapse navbar-collapse' id='mainNavbar'>
  <div class='navbar-nav'>
    <div [ngClass]='{ "nav-item": true, active: pageTitle === "Home" }'>
      <a class='nav-link' routerLink='/'>Home</a>
    </div>
    <div [ngClass]='{ "nav-item": true, active: pageTitle === "Request" }'>
      <a class='nav-link' routerLink='/request'>Request</a>
    </div>
    <div [ngClass]='{ "nav-item": true, active: pageTitle === "Volunteer" }'>
      <a class='nav-link' routerLink='/volunteer'>Volunteer</a>
    </div>
    <div [ngClass]='{ "nav-item": true, active: pageTitle === "About" }'>
      <a class='nav-link' routerLink='/about'>About</a>
    </div>
  </div>
</div>

Relevant part of controller:

// importing jquery from npm module
import * as $ from 'jquery';

// inside the controller class
ngOnInit() {
  $('.nav-link').click(() => $('.collapse').collapse('toggle'));
}

Included scripts (in .angular-cli.json):

"scripts": [
  "../node_modules/jquery/dist/jquery.min.js",
  "../node_modules/popper.js/dist/umd/popper.min.js",
  "../node_modules/bootstrap/dist/js/bootstrap.min.js"
]

I've seen multiple questions just like this, but almost always the answers say to make sure jQuery is included before Bootstrap, and that Bootstrap is not included twice. Neither is the case here.

Other jQuery functionality (normal collapse functionality) is working properly. And the same error comes up if I try to do use the .dropdown() function on dropdowns.

What is the issue here?


If you need: Angular 5, Bootstrap v4.0.0 (npm module), jQuery v3.3.1 (npm module)

8
  • Hmmm. Why was this immediately downvoted? Was I not thorough? Commented Apr 13, 2018 at 16:23
  • Did you restart ng serve after adding the js files? Commented Apr 13, 2018 at 16:47
  • @David yes, I did. Commented Apr 13, 2018 at 16:48
  • 1
    What if, instead of your import, you try declare let $: any ? Commented Apr 13, 2018 at 16:52
  • 2
    I assume that if you import jquery as $, it means that $ will only contain the code defiend in the jquery package, and not the additional plugins declared by bootstrap. If you use declare let ..., then $ represents the normal jQuery function PLUS the additional plugins Commented Apr 13, 2018 at 16:55

5 Answers 5

9

You need to use declare let $ : any; instead of your import

I assume that if you use

import jquery as $ from 'jquery';

then it means that $ will only contain the code defined in the jquery package, and not the additional plugins declared by bootstrap (or by any other jquery plugins).

If you use

declare let $ : any;

then $ represents the normal jQuery function PLUS the additional plugins (collapse, dropdown, ...) added by other libraries

If you don't want to use any, and you need to explicitely call some plugin methods, you need to extend jQuery's interface

interface JQuery 
{
    carousel(options : any);
}

declare let $: JQuery;

Note if you can avoid it, you should avoid using jquery or jquery plugins when a native angular approach is available

For boostrap, like ConnorsFan mentionned, you can use ng-bootstrap as a replacement. It requires bootstrap's CSS file, but dynamic components have been rewritten in native angular, without the need of jQuery

Sign up to request clarification or add additional context in comments.

1 Comment

Perfect explanation. Worked flawlessly.
2

After more research, I found this Stack Overflow answer that suggested adding the following line (replacing the import * as $ from 'jquery'):

declare let $: any;

Unfortunately, I don't understand what this means or how it works, but it fixed the problem for me. Hope this helps someone.

3 Comments

you answer to yourself to quickly, i have prepare this sample for you, if you want to add it to your own answer. stackblitz.com/edit/angular-hhf14h?file=app%2Fapp.component.ts
@Yanis-git Thanks for the example!
Unfortunately i am not able, on the second button in my sample, i activate real toggle, is just opening dropdown then nothing.
1

Use:

declare let $ : any;

Instead of:

import * as $ from 'jquery';

As a workaround you can use:

$('#yourId').removeClass('show');

(for others users)

Assure that you have the settings on angular.json like on the question:

"scripts": [
    "node_modules/jquery/dist/jquery.min.js",
    "node_modules/popper.js/dist/umd/popper.min.js",
    "node_modules/bootstrap/dist/js/bootstrap.min.js"
 ]

Comments

1

This worked for me

import * as $ from 'jquery';
declare var $:any;

In angular.json

"styles": [
          "src/styles.css",
          "node_modules/bootstrap3/dist/css/bootstrap.min.css",
          "node_modules/ngx-toastr/toastr.css"
        ],
"scripts": [
          "node_modules/jquery/dist/jquery.min.js",
          "node_modules/bootstrap3/dist/js/bootstrap.js"
        ]

Now you can use collapse in angular 7

 $(".panel-collapse").collapse("hide");

Comments

0

When you are inside an Angular application there is no need for jQuery. You can use local variables instead. There is actually a very good example of how to do this in this stackblitz

4 Comments

I know it's not necessary to use jQuery, but Bootstrap already requires jQuery to be loaded. I thought I might as well use the jQuery convenience functions instead of implementing it myself in Angular.
When pulling bootstrap into an Angular application it would be better to use ngx-bootstrap or ng-bootstrap rather than the native jQuery functionality. Using jQuery will cause issues for you in the long term as it takes you outside of the visibility of Angular and has the potential to cause unintended side effects.
I use bootstrap with all of my Angular projects, I pull the styles in via SCSS in the main stylesheet of the application, from there I use ngx-bootstrap to provide the functionality of my bootstrap components.
Ok, thanks. I'll keep that in consideration in the future.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.