# Add Bootstrap to an Angular application

Source: https://tpiros.dev/blog/add-bootstrap-to-an-angular-application

Back when CSS was less tangled (think the 1990s), styling a page was relatively painless. Now there's a lot more to wrangle. A few frameworks have emerged to solve the design problem. In this first article, we'll cover how to bolt Bootstrap onto an Angular application. The second, follow-up article examines [how to use Material Design](https://fullstack-developer.academy/add-material-design-to-an-angular-application/).

No need to use both frameworks. Either one works, but their integration paths differ.

# Bootstrap

[Bootstrap](https://getbootstrap.com), now on its fourth version, is one of the most widely used front-end component libraries. It gives developers a grid system, dropdowns, modals, navigation bars, progress bars and more.

To use Bootstrap in an Angular project, first scaffold an Angular application via the CLI: `ng new [app-name]`.

Then install Bootstrap via npm: `npm i bootstrap`.

> Bootstrap depends on Popper.js and jQuery. Install both: `npm i jquery popper.js`.

> We could have pulled Bootstrap in via a CDN in `index.html`, but here we're wiring it into the Angular project properly.

## Setup

After installation, we need to edit the `angular.json` file at the project root. This JSON file holds application settings: TypeScript linter config, test settings, and (crucially) which external JavaScript and CSS files to load.

Find the path to styles and scripts (`projects - project-name - architect - build`) and drop in the following values:

```json
"styles": [
  "src/styles.css",
  "node_modules/bootstrap/dist/css/bootstrap.min.css"
],
"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"
]
```

Order matters here. Bootstrap depends on jQuery and Popper.js, so those must come first.

One gotcha: if `ng serve` is already running, we need to kill it and restart. Changes to `angular.json` don't propagate into a running dev server.

## Example

Quick test: open `index.html` and drop in this HTML for a Bootstrap alert panel:

```html
<div class="alert alert-success" role="alert">Bootstrap in action!</div>
```

![](https://res.cloudinary.com/tamas/image/upload/w_600,f_auto,q_auto/v1543056053/fullstack-developer-academy/bootstrap-native.png)

## A dependency issue

So far so good. But there's a jQuery dependency dragging along, which adds weight to the project. It'd be better to strip that out.

Some actions also throw errors. Say we want to fire a callback when a modal closes:

```javascript
$('#myModal').on('hidden.bs.modal', (event) => {
  console.log('closed', event);
});
```

This throws:

```
Cannot find name '$'. Do you need to install type definitions for jQuery? Try `npm i @types/jquery`
```

Fine. Install the type definition for jQuery. But the same error persists.

One workaround (not ideal): declare `$` with the `any` datatype in TypeScript: `declare var $: any;`

Even then, the event listener won't fire because we need a `document.ready()` event too:

```javascript
$(document).on('hidden.bs.modal', '#exampleModal', (event) => {
  console.log('closed', event);
});
```

Only then does this simple piece of code actually work. There's a better approach, and it strips out the dependencies at the same time.

# ng-bootstrap and ngx-bootstrap

Both of these component libraries do the same thing: they give us Bootstrap components without jQuery, Popper.js, or the actual bootstrap.js. (A Bootstrap CSS file is **still** required.)

> To confirm jQuery and Popper.js aren't lurking around, uninstall them: `npm uninstall jquery popper.js`, and remove the script entries from `angular.json`.

## ng-bootstrap

Install [ng-bootstrap](https://ng-bootstrap.github.io/): `npm i @ng-bootstrap/ng-bootstrap`. After installation, we can either import the entire module or cherry-pick only the components we need:

```typescript

// or:
// import { NgbAlertModule, NgbModalModule } from '@ng-bootstrap/ng-bootstrap';
@NgModule({
  ...
  imports: [ NgbModule ],
  // or:
  //   imports: [ NgbAlertModule,  NgbModalModule],
  ...
})

}
```

> Importing only the modules the application needs will trim the overall bundle size.

## Examples

That's it. No more setup required. Drop this into `app.component.html` (or any other component template, but not `index.html`):

```html
<ngb-alert [dismissible]="false"> ng-boostrap in the house! </ngb-alert>
```

That shows an alert panel.

![](https://res.cloudinary.com/tamas/image/upload/w_600,q_auto,f_auto/v1543056054/fullstack-developer-academy/ng-bootstrap.png)

What about a modal with an event listener? Drop this into a component:

```html
<ng-template #content let-modal>
  <div class="modal-header">
    <h4 class="modal-title" id="modal-basic-title">Profile update</h4>
    <button
      type="button"
      class="close"
      aria-label="Close"
      (click)="modal.dismiss('Cross click')"
    >
      <span aria-hidden="true">&times;</span>
    </button>
  </div>
  <div class="modal-body">
    <p>Hello modal, looking good!</p>
  </div>
  <div class="modal-footer">
    <button
      type="button"
      class="btn btn-outline-dark"
      (click)="modal.close('Save click')"
    >
      Save
    </button>
  </div>
</ng-template>

<button class="btn btn-lg btn-outline-primary" (click)="open(content)">
  Launch demo modal
</button>

<hr />

<pre>{{ closeResult }}</pre>
```

And the component definition:

```typescript
`import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

  title = 'css-angular';
  closeResult: string;
  constructor(private modalService: NgbModal) { }

  open(content) {
    this.modalService.open(content, {ariaLabelledBy: 'modal-basic-title'}).result.then((result) => {
      this.closeResult = `Closed with: ${result}`;
    }, (reason) => {
      this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
    });
  }

  private getDismissReason(reason: any): string {
    if (reason === ModalDismissReasons.ESC) {
      return 'by pressing ESC';
    } else if (reason === ModalDismissReasons.BACKDROP_CLICK) {
      return 'by clicking on a backdrop';
    } else {
      return  `with: ${reason}`;
    }
  }
}
```

We can capture the close event and print the reason why the modal was closed, all without a single jQuery or Bootstrap.js dependency.

> Code sample taken from the ng-bootstrap documentation, slightly modified.

## ngx-bootstrap

Like ng-bootstrap, [ngx-bootstrap](https://valor-software.com/ngx-bootstrap/) gives us Bootstrap components the Angular-native way, with no external JavaScript dependencies.

Install it: `npm install ngx-bootstrap`. Alternatively, ngx-bootstrap supports the `ng add` command: `ng add ngx-bootstrap`. The second approach also wires up the CSS in `angular.json` automatically, so there's no need to manually point to Bootstrap's stylesheet.

Next, drop the import statements into `app.module.ts`:

```typescript
// specific import

// generic import to import further modules:
// import { AlertModule, ModalModule } from 'ngx-bootstrap';
@NgModule({
  // ...
  imports: [AlertModule.forRoot(), ...]
  // ...
})
```

Again, importing only the required modules helps trim the application's size.

## Examples

Test it by dropping an alert panel into a component template:

```html
<alert type="success">
  <p>Hello from ngx-bootstrap</p>
</alert>
```

If everything's wired up correctly, a green alert should appear.

![](https://res.cloudinary.com/tamas/image/upload/w_600,q_auto,f_auto/v1543056052/fullstack-developer-academy/ngx-bootstrap.png)

For completeness, here's a modal with an event listener on the hide event:

```typescript
<button type="button" class="btn btn-primary" (click)="openModal(template)">Create template modal</button>

<ng-template #template>
  <div class="modal-header">
    <h4 class="modal-title pull-left">Modal</h4>
    <button type="button" class="close pull-right" aria-label="Close" (click)="modalRef.hide()">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>
  <div class="modal-body">
    This is a modal.
  </div>
</ng-template>

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

  title = 'css-angular';
  modalRef: BsModalRef;
  constructor(private modalService: BsModalService) {}

  openModal(template: TemplateRef<any>) {
    this.modalRef = this.modalService.show(template);
    this.modalService.onHide.subscribe((reason: string) => {
      console.log(`onHide event has been fired`);
    });
  }
}
```

Same result, no external JavaScript library in sight.

# Conclusion

Three ways to wire Bootstrap into an Angular application: natively, via ng-bootstrap, and via ngx-bootstrap. Each gets the job done; the ng-bootstrap and ngx-bootstrap routes strip out the jQuery dependency.
