Ngx-bootstrap: feat(modal): Implement modal component

Created on 6 Nov 2015  Â·  95Comments  Â·  Source: valor-software/ngx-bootstrap

Hi,

The README says Modal (in progress...). Is it true, is sb working on that? Can we share some progress here (in a separate branch presumably)? I'd consider contributing as I need it for my project...

Thanks for providing more info.
Marcin

hard (weeks) enhancement

Most helpful comment

just to keep you updated
work in progress
https://github.com/valor-software/ng2-bootstrap/tree/feat-modal

All 95 comments

Hey, approach to modals implementation was more conceptual
next week I get back to ng2-bootstrap activity
and modal will be component oriented like routing

Any update on the Modal component?

in progress, stay tunned

+1 . No pressure though. Great work on the other components!

I'm currently on the verge of writing a modal component myself. If you're planning to release soon, that would be great to know (than I'll postpone my work a bit) ;)

+1
That's the only important piece that is missing.

+1

+1

Okay! :)

+1 :)

+1

+2 )

+1

Perhaps something from here can be used?
https://github.com/shlomiassaf/angular2-modal

I already had a brief look at the code. It's not that easy to understand, especially since the Angular API has changed so much since alpha 26 (and the DomRenderer can't do enough anymore).

I settled for a straightforward component that encapsulates a Modal, which I can show/hide at will. Disadvantage is that I need to insert this component in each template I need it (meaning there are multiple - hidden - dialogs all the time) and I'll probably have issues with the backdrop in some cases. But for now it's very uncomplicated and it works.

I can share the code If you like.

yes, please :-)

Here you go (very unpolished code):

The component:

import {Component, View, Input, Output, EventEmitter, OnInit} from 'angular2/angular2';

/**
 * Shows a bootstrap modal dialog.
 * Set the body of the dialog by adding content to the modal tag: <modal>content here</modal>.
 */
@Component({
  selector: 'modal'
})
@View({
  templateUrl: './components/modal/modal.html'
})
export class Modal implements OnInit {

  @Input('title') title: string;
  @Input('cancel-label') cancelLabel: string = 'Cancel';
  @Input('positive-label') positiveLabel: string = 'OK';

  /**
   * Fires an event when the modal is closed. The argument indicated how it was closed.
   * @type {EventEmitter<ModalResult>}
   */
  @Output('closed') closeEmitter: EventEmitter<ModalResult> = new EventEmitter<ModalResult>();
  /**
   * Fires an event when the modal is ready with a pointer to the modal.
   * @type {EventEmitter<Modal>}
   */
  @Output('loaded') loadedEmitter: EventEmitter<Modal> = new EventEmitter<Modal>();

  showModal: boolean = false;

  constructor() {
    console.log('showModal = ' + this.showModal);
  }

  onInit() {
    this.loadedEmitter.next(this);
    console.log('modal inited');
  }

  /**
   * Shows the modal. There is no method for hiding. This is done using actions of the modal itself.
   */
  show() {
    this.showModal = true;
  }

  positiveAction() {
    this.showModal = false;
    this.closeEmitter.next({
      action: ModalAction.POSITIVE
    });
    return false;
  }

  cancelAction() {
    console.log('sending close event');
    this.showModal = false;
    this.closeEmitter.next({
      action: ModalAction.CANCEL
    });
    return false;
  }
}

/**
 * The possible reasons a modal has been closed.
 */
export enum ModalAction { POSITIVE, CANCEL }
/**
 * Models the result of closing a modal dialog.
 */
export interface ModalResult {
  action: ModalAction;
}

The template:

<div class="modal-backdrop fade in"
     [style.display]="showModal ? 'block' : 'none'"></div>
<div class="modal"
     tabindex="-1"
     role="dialog"
     style="display: block"
     [style.display]="showModal ? 'block' : 'none'">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <!--
        <button type="button"
                class="close"
                aria-label="Close"
                (click)="cancelAction()">
          <span aria-hidden="true">&times;</span>
        </button>
        -->
        <h4 class="modal-title">
          {{title}}
        </h4>
      </div>
      <div class="modal-body">
        <ng-content></ng-content>
      </div>
      <div class="modal-footer">
        <button type="button"
                class="btn btn-default btn-sm"
                (click)="cancelAction()">
          {{cancelLabel}}
        </button>
        <button type="button"
                class="btn btn-primary btn-sm"
                (click)="positiveAction()">
          {{positiveLabel}}
        </button>
      </div>
    </div>
  </div>
</div>

Use in your own templates:

The trick here is the (loaded) event. This allows the parent component to get a direct reference to the modal.

<modal id="cancelConfirmation"
       [title]="'Are you sure?'"
       [cancel-label]="'cancel'"
       [positive-label]="'OK'"
       (loaded)="cancelConfirmationModalLoaded($event)"
       (closed)="onCancelConfirmation($event)">
  The body of your modal
</modal>
// inside your component:
cancelConfirmationModalLoaded(modal: Modal) {
    this.cancelConfirmationModal = modal; // Here you get a reference to the modal so you can control it programmatically
  }

This seems to work for me.
@bertvh thank you!

Merge it with main branch :+1:

@koodikindral Not ready for that. I see a few problems:

  • You need to include the modal in your templates, resulting in multiple (hidden) modals + you need to subscribe to the loaded even in order to control the modal from your own component, which is OK but not super great.
  • Many things you can't do such as: close with (x) button, only supports two buttons at the bottom, can't control size, animation, (much to do here).
  • Code is not super clean.
  • Not unit tested.

But hey, if everyone likes it, I can clean it up and do a pull request. Just need some more supporters ;)

+1

status update: have a working prototype, to represent bs4 logic and classes
debugging, planning to land it this week

+1 Very much looking forward to this landing. I'll be able to use ng2-bootstrap in my company's app once it does! :)

+1, also, when this lands with a little bit of tweaking I'll stop copy pasting components and actually install a package into a project.

Hi Guys,

Just found this repo, nice work.

You can take a look at my repo where I implemented a Modal window for bootstrap.
It was mentioned here before: https://github.com/shlomiassaf/angular2-modal

I updated it to work with ng2 beta, it also has a working npm package since some developers wanted it... tough I dont think its good 2 have 2 versions...

The main idea is to allow a modal to be any component which makes it completely customizable.
Of course, I supply some basic "Modal" components but the user can also add his own.

Personally, in the spirit of web components, I believe a complete solution for bootstrap is not the right approach, rather a set of separate components with a possible 1 light wight package for shared services... if needed, not sure.

This also complies with bootstrap builders where one can select the specific components (CSS/JS) he wants an omit the ones not in use...

Great, I will check tomorrow! @shlomiassaf

Just need this to start using ng2-bootstrap for my company's new project as well!
Eagerly waiting for this to be implemented! Thanks

+1 Any news?

While we are drooling for this, I can confirm that https://github.com/shlomiassaf/angular2-modal works great so far in my app. It's a little bit hard to wrap your head around it, but it works. Still hoping @valorkin and other will find time to implement it here.

yeap, actually we almost here
I have added several things guys was pushing me too
like, systemjs bundles and cdn stuff for plunkr
you can see here https://twitter.com/valorkin/status/692037650061115394

FWIW, I've got a simple version of a modal available at https://github.com/dougludlow/ng2-bs3-modal. I needed it for a project I was working on.

+1 I'd even love to know which branch this feature is semi-functional in.

+1

+1

+1

+1

Any progress?

+1

+1

@bertvh Why we need use loaded event for binding modal? How about local variable binding in template?

<modal #myModal
       [title]="'Are you sure?'"
       [cancel-label]="'cancel'"
       [positive-label]="'OK'"
       (closed)="onCancelConfirmation($event)">
  The body of your modal
</modal>

and then

<button (click)="showModal(myModal)">Show modal</button>

@Iverson I do like that better. Simply didn't think of that. Still finding my way in Angular 2 ;)

I did implement part of @bertvh code, but style.display is pure CSS so no smooth effect on show or close :cry: (except that it works great :+1: )

+1

+1

+1

Is there any code for this component already that could be committed into a separate branch? More than willing to help, but there's no need for multiple people to do the work twice …

@dougludlow ,Its working perfect for the project i am working on !! Thanks a lot!!

+1

@Nick-Thakkar :thumbsup:

+1

+1

+1 and ty for doing this awsome work

+1

+1

+1

+1

For any interested, you might take a look at https://github.com/dougludlow/ng2-bs3-modal for a working bootstrap modal component.

@dougludlow that means another module and another dependency...

@bdsoha that's how we roll :bike:

I tired ng2-bs3-modal which doesn't work for me.
As mentioned in document ng2-bs3-modal depends on bootstrap which depends on jquery, you'll need to include both scripts before ng2-bs3-modal:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.js"></script>

instead of it I used

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.js"></script>
    <script src="node_modules/ng2-bootstrap/bundles/ng2-bootstrap.min.js"></script>
    <script src="node_modules/ng2-bs3-modal/bundles/ng2-bs3-modal.js"></script>

and it doesn't work. Any clue?

@kalpeshrajvir-virtueinfo ng2-bootstrap.min.js has nothing to do with bootstrap.js. They are totally different, that's why you can't make it run with such set of libraries. Use dependencies proposed by library author. And you better ask such question on ng2-bs3-modal's github page

Do you mean ng2-bootstrap.min.js and bootstrap.js both is required? I
though they will conflict that's why I tried with one.

On Fri, Apr 22, 2016 at 7:15 PM, Alexey Lizurchik [email protected]
wrote:

@kalpeshrajvir-virtueinfo https://github.com/kalpeshrajvir-virtueinfo
ng2-bootstrap.min.js has nothing to do with bootstrap.js. They are
totally different, that's why you can't make it run with such set of
libraries. Use the libraries proposed by library author. And you better ask
such question on ng2-bs3-modal's github page
https://github.com/dougludlow/ng2-bs3-modal/issues

—
You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
https://github.com/valor-software/ng2-bootstrap/issues/29#issuecomment-213434259

_------------------------------------------------Thanks & Regards,Kalpesh
RajvirTeam LeaderVirtueinfo Web Technologies (India) Pvt.
Ltd.www.virtueinfo.com http://www.virtueinfo.com/mobile:+91
9375701917E-mail: kalpeshrajvir.[email protected]
kalpeshrajvir.[email protected]: kjrajvir.virtueinfoGtalk:
kalpeshrajvir.virtueinfo_

@kalpeshrajvir-virtueinfo No they will not. Bootstrap (original) uses jquery for their components, but ng2-bootstrap utilizes self-built components on vanilla js (without heavy jquery). So basically ng2-bootstrap just visually is like bootstrap, but actually not. And also that's why new components appear slowly, because @valorkin should make them almost from scratch. Let's stop this discussion, because other guys get notified, but there are no changes for this issue

+1

+1

+1

+1

+1

+1 Awaiting this feature, noticed it was "coming soon" in December, updates?

I would say it will be soon enough :)
https://twitter.com/shlomiassaf/status/730164935947370496

@shlomiassaf implemented modal in a different way, I would like it to be similar way as we have it in ui-bootstrap, because a lot of use cases are covered using that.

While we are waiting, if you want to use code to control when to open/close the modal now, my walkaround way right now is adding hidden buttons. No need 3rd-party library. And it can give you full control.

This way can keep the Bootstrap style of the modal and the fade in/out animation, which works perfect.

Say I have a modal:

<div id="myModal" class="modal fade">
  You modal content goes here
</div>

Open modal

Add a hidden button:

<button id="openModalButton" [hidden]="true" data-toggle="modal" data-target="#myModal">Open modal</button>

Then use this code to "click" the button to open the modal:

document.getElementById("openModalButton").click();

Close modal

Similar, add a hidden button:

<button id="closeModalButton" [hidden]="true" data-dismiss="modal">Close modal</button>

Then use this code to "click" the button to close the modal:

document.getElementById('closeModalButton').click();

@Hongbo-Miao That would require jquery and bootstrap javascript files to be included, if the project doesn't uses them, then we cant use it.

just to keep you updated
work in progress
https://github.com/valor-software/ng2-bootstrap/tree/feat-modal

:+1:

tracing last issues before release

@valorkin I looked into the code of that branch and I have two questions:

  • Is it possible to reference the modal via template url?
  • Is it possible to put a separat ts file behind a modal window?
  • Is it possible to exchange information between the modal window and its parent?

Released :)

@jhiemer

Is it possible to reference the modal via template url?

it will be added, but not as templateUrl in html, but as component to inherit and replace html

Is it possible to put a separate ts file behind a modal window?

please elaborate

Is it possible to exchange information between the modal window and its parent?

they share context, so yes

it will be added, but not as templateUrl in html, but as component to inherit and replace html

Ok, waiting for it. :-)

Is it possible to put a separate ts file behind a modal window?

please elaborate

I think the separate component/html one, would fit into this.

Is it possible to exchange information between the modal window and its parent?

they share context, so yes

I will try it.

Question after trying the modal: Let's say I have two buttons, one to save, and one to cancel. Both need to issue the onHide(), default value is always $event. What is the cleanest way to distinct those two states in my component?

@valorkin to be more precise, here is a sample from Angular 1.

$scope.open = function (size) {

    var modalInstance = $uibModal.open({
      animation: $scope.animationsEnabled,
      templateUrl: 'myModalContent.html',
      controller: 'ModalInstanceCtrl',
      size: size,
      resolve: {
        items: function () {
          return $scope.items;
        }
      }
    });

    modalInstance.result.then(function (selectedItem) {
      $scope.selected = selectedItem;
    }, function () {
      $log.info('Modal dismissed at: ' + new Date());
    });
  };

@jhiemer modal is just a UI tool, it doesn't create separate context (at least for now or should not)
so it doesn't have result in a separate way
it just allows you to show data in different way
but handling of data streams is up to you

if doesn't make sense I can elaborate a bit more

@valorkin ok, but having just this popup without being able to transfer any data into it and getting back some results from e.g. Save() or Cancel() does not help in many cases.

Which use cases do you see for a modal, which just opens and displays "data in a different way"?

Taking an example: you want to have modal, which opens up, if you want to delete a resource. Then it would be very nice to have at least way to get a reference of the entity to delete into the modal and vice versa.

This also has another limitation, you cannot open one modal from different location in the application.

And also how should we be able to open multiple modals?!

How can we integrate modal with the router?!

And also how should we be able to open multiple modals?!

http://v4-alpha.getbootstrap.com/components/modal/

Multiple open modals not supported
Be sure not to open a modal while another is still visible. Showing more than one modal at a time
requires custom code.

This also has another limitation, you cannot open one modal from different location in the application.

actually you can but the way it is in ng2 is a bit different from ng1

Other question that you can not create components dynamically via just ModalsService.open
This is planned but will be later

How can we integrate modal with the router?!

How can you integrate opening dropdown with router?
Same way works for modal :)

PS do not hesitate to ask questions, I am listing them and will update documentation with answers

right now top prio datepicker popup, than update docs ( more samples, may be even FAQ per component)

@valorkin my questions are still open. :-)

thanks for the great library btw.

@valorkin

Multiple open modals not supported

Even thought Jquery Bootstrap didn't support it, we had Angular UI (for 1.x) which is a custom code as is ng2-bootstrap, which supported it.

@mohammedzamakhan agreed, should be added

How can I close a modal from within its own controller? For example, I have a modal that shows a form. The save button is executing a method in modal's controller. Once everything is saved, I want to close it.
Is there any reference to lgModal?

http://valor-software.com/ng2-bootstrap/#modals
like in demo

In general you have two options how to get instance of modal component:

  • via View\Content child
  • via html like this #lgModal="bs-modal"
    than you have an access to hide method

Right, so I have this as a template:

<div bsModal #lgModal="bs-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="goalFormModal" aria-hidden="true">
....
      <div class="modal-footer">
        <button type="submit" class="btn btn-primary">Create</button>
        <button type="reset" class="btn btn-danger" (click)="lgModal.hide()">Cancel</button>
      </div>
    </div>
  </div>
</div>

And the controller attached to it is something like this

export class GoalFormComponent {

  newGoalModel: NewGoal = new NewGoal('');

  constructor(
    private goalsService: GoalsService
  ) {}

  newGoalSubmit() {
    this.goalsService.createNewGoal(this.newGoalModel)
      .subscribe(
        _ => this.loadGoals(),
        err => console.error(err),
        () => lgModal.hide()
      );
  }
}

So basically, I am within the modal's component. See the line () => lgModal.hide(), that is the one I am refering to.

@ShurikAg no no, this should throw an exception
please refer to this post:
http://blog.mgechev.com/2016/01/23/angular2-viewchildren-contentchildren-difference-viewproviders/
and inject modal into your component via View or Content child

and let us move to https://gitter.im/valor-software/ng2-bootstrap
to not spam to all here :)

How to use bootstrap nested modal in simple way?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Scooviese picture Scooviese  Â·  3Comments

KimBum picture KimBum  Â·  3Comments

ravirajhalli picture ravirajhalli  Â·  3Comments

RolfVeinoeSorensen picture RolfVeinoeSorensen  Â·  3Comments

PascalHonegger picture PascalHonegger  Â·  3Comments