66

I have got a a element for invoking modal:

<a class="btn" data-toggle="modal" data-target="#myModal" href="http://some-url" >Launch Modal</a>

And, say this is my modal:

<div class="modal hide" id="myModal">
  <div class="modal-header">
    <button type="button" class="close" data-dismiss="modal">×</button>
    <h3>Modal header</h3>
  </div>
  <div class="modal-body">
    <p>One fine body…</p>
  </div>
  <div class="modal-footer">
    <a href="#" class="btn" data-dismiss="modal">Close</a>
    <a href="#" class="btn btn-primary">Save changes</a>
  </div>
</div>

I can bind functions to events fired by modal:

$('#myModal').on('hidden', function () {
  // do something…
})

My question is: How can i access the a element -which invoked the modal- from my event subscriber function?

cnkt
  • 2,943
  • 5
  • 30
  • 43
  • `$("a[href='#myModal']")` will select that `a` tag. Is that what you're looking for? – sachleen Jul 19 '12 at 22:40
  • No it's not actually. Because it can be anything instead of #mymodal. What i'm looking for is like: event.relatedTarget or event.OriginalTarget or something like that. – cnkt Jul 19 '12 at 22:42
  • Doesn't it have to be `#mymodal` for it to launch the modal `mymodal`? You can replace "mymodal" with a variable containing the ID of the element whose event youre in. – sachleen Jul 19 '12 at 22:45
  • Sure but, the content of the modal will be loading with ajax. So there can be multiple a elements pointing to the same modal. I need to find the clicked a element, get it's href attribute and load it into modal. – cnkt Jul 19 '12 at 22:46
  • I'm not understanding... do you want to fire an event whenever you click on a link? Why does it matter how the modal is loaded? If you have multiple links launching one modal, do you need to get another (unique) attribute from the clicked one? – sachleen Jul 19 '12 at 22:53
  • So: Every "modal opener" a element's data-target attribute is #modal. But their href is different. Modal fires a "show" event before it actually shows the modal. I subscribe to this event so i can get the clicked element's href attribute and load it into modal. But i can't find the clicked a element from my callback function. – cnkt Jul 19 '12 at 23:06
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/14157/discussion-between-sachleen-and-cnkt) – sachleen Jul 19 '12 at 23:16
  • See also: http://getbootstrap.com/javascript/#modals-related-target – cvrebert Jan 27 '15 at 18:43

5 Answers5

111

It was solved in Bootstrap 3.0.0 thanks to event.relatedTarget.

$('#your-modal').on('show.bs.modal', function (e) {
  var $invoker = $(e.relatedTarget);
});
lou
  • 2,050
  • 1
  • 19
  • 28
16

You have to listen to:

$('[data-toggle="modal"]').on('click', function() {
    $($(this).attr('href')).data('trigger', this);
});
$('.modal').on('show.bs.modal', function() {
    console.log('Modal is triggered by ' + $(this).data('trigger'));
});

You can of course replace show.bs.modal with shown.bs.modal or any other event they fire. Note that this is for Bootstrap 3.0.0. If you're using 2.3.2 you need to get rid of .bs.modal (I think).

What I like about this solution: you do not have to remember who is this, self, that and other proxy calls workarounds.

Of course, you have to test if the href attribute is not a real link (the dynamic modal loading option).

velocityhead
  • 172
  • 7
Alex
  • 810
  • 9
  • 16
  • The best options to my case. And, yes, in 2.3.2 you need to remove .bs.modal. – Diogo Paschoal Mar 10 '17 at 23:43
  • Amazingly clever solution! I wish I could upvote this solution multiple times. My problem was that a modal was triggered from multiple elements and I wanted the trigger element upon a click on a button within the modal. Although, the conventional route of using `show.bs.modal` and `event.relatedTarget` is possible, I would either end up making unnecessary `unbind()` calls and/or compromise with performance. Cheers again! – Fr0zenFyr Sep 14 '17 at 06:41
7

The modal element has a data object named modal that saves all the options that are passed. You can set a 'source' data attribute on the element that triggers the modal, set it to the ID of the source, and then retrieve it later from the options variable.

The trigger would be:

<a id="launch-modal-1" class="btn" data-toggle="modal" data-target="#myModal" href="http://some-url" data-source="#launch-modal-1">Launch Modal</a>

In the event callback, get the modal data object, and look at the source option:

$('#myModal').on('hidden', function () {
  var modal = $(this).data('modal');
  var $trigger = $(modal.options.source);
  // $trigger is the #launch-modal-1 jQuery object
});
user2109658
  • 71
  • 1
  • 1
  • 2
    This initially seemed to work for me, but as soon as I had more than one source it stopped working. It seems the modal keeps the options from the first time it was invoked, so whichever anchor you click first, it will use the data-source from that one in all subsequent operations. – izak Jul 07 '15 at 09:34
1

Currently it's not available out-of-box. There is a feature request for it and a work-around if you want to edit the bootstrap-modal code yourself.

See here

Fahim Parkar
  • 30,974
  • 45
  • 160
  • 276
SummerDew
  • 11
  • 1
  • 1
    There was a [pull request](https://github.com/twitter/bootstrap/pull/6256) submitted, but was rejected for some reason. This is a feature I'd very much like to see. – Bojangles Dec 31 '12 at 01:04
1

I had a situation where I had to bind some data related to the "invoker", just like you said. I've managed to solve it by binding a "click" event to it and working with the data like this:

The invoker

<img id="element" src="fakepath/icon-add.png" title="add element" data-toggle="modal" data-target="#myModal" class="add">

The JS to catch data related to the invoker (Just some code example)

$('#element').on('click', function () { // Had to use "on" because it was ajax generated content (just an example)
    var self = $(this);
});

Like this, you can handle the data related to your invoker anyway you want.

darksoulsong
  • 13,988
  • 14
  • 47
  • 90