Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bootstrap w/ Angular "Error: $(...).collapse() is not a function"

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)

like image 281
Jonathan Lam Avatar asked Apr 13 '18 16:04

Jonathan Lam


1 Answers

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

like image 50
David Avatar answered Oct 14 '22 22:10

David