I have an interesting problem with the uiSref
directive and I haven't been able to find a solution (well an elegant one anyway) anywhere on the web. Basically I have a requirement from a client to be able to click a row in a table of resources and go to the editing view for that resource. Normally the uiSref
directive works beautifully, but the problem resides in the fact that I have a Bootstrap dropdown in the last <td>
of the table with a bunch of quick actions in it. The HTML looks something like this:
<table class="table table-bordedered table-hover">
<thead>
<tr>
<td>Name</td>
<td>Actions</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="resource in resources" ui-sref="edit({id: resource.id})">
<td ng-bind="resource.name"></td>
<td class="actions-column">
<div class="btn btn-xs btn-default" data-toggle="dropdown">
<i class="fa fa-cog"></i>
</div>
<ul class="dropdown-menu pull-right">
<li>
<a href="javascript:void(0)" ng-click="doSomethingCrazy(resource)">SOMETHING CRAZY</a>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
The problem is that when I click on the button in the actions column, the uiSref
overrides the default action of the dropdown and takes me to the edit page. Now you might be asking yourself "well that's easy, why can't you just stop the propagation of the event!?"... doesn't work. When I add this to the actions column:
<td class="actions-column" ng-click="$event.stopPropagation()">
It kills the functionality of the dropdown menu and nothing shows up. Right now I have a workaround in place where I define an ngClick
on the <tr>
element that then deciphers where the state should go depending on the element clicked like so:
<tr ng-repeat="resource in resources" ng-click="goToEdit(resource, $event)">
And The JS looks like this:
scope.goToEdit = function(resource, event) {
// if the event.target has parent '.actions-column' or is that column, do nothing else
// invoke $state.go('edit', {id: resource.id})
}
I hate it though and I have a lot of list views like this. All I'm looking for is an elegant and portable solution that hopefully works natively through UI Router like $event.stopPropagation()
(Although I've poked through the UI Router source and can't seem to find a workable alternative). Basically I want to have my cake and eat it too. Anyway, it'll be interesting to see what the SO community can come up with or if what I'm asking for is not currently possible. Thanks!
I got it! While looking through the UI Router source some more, it appears that the click event will be ignored if the target
attribute is populated on the element that the uiSref
resides on. It may not be the most beautiful thing in the world, but it sure is easier than what I was doing before.
NOTE: This only works if you're using the whole jQuery library, not jQLite
So I wrote this directive:
app.directive('uiSrefIgnore', function() {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
elem.on('click', function(e) {
// Find the ui sref parent
var uiSref = elem.parents('[ui-sref]').first();
// Set the target attribute so that the click event is ignored
uiSref.attr({
target: 'true'
});
// Function to remove the target attribute pushed to the bottom
// of the event loop. This allows for a digest cycle to be run
// and the uiSref element will be evaluated while the attribute
// is populated
setTimeout(function() {
uiSref.attr({
target: null
});
}, 0);
});
}
};
});
That way, whenever I want to ignore the javascript event for just the uiSref
directive, I can just add this to the html:
<tr ui-sref="edit">
<!-- any other elements -->
<td ui-sref-ignore>The element I care about</td>
</tr>
BOOM! Let me know what you guys think about the implications of this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With