Reputation: 19896
Let say I have nested DOMs and each has ui-sref
for different angular-ui-router
state. I want to click outer to only alert outer and click inner to only alert inner. Currently if I click inner, it will alert both outer and inner state.
HTML:
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="[email protected]" src="http://code.angularjs.org/1.2.13/angular.js" data-semver="1.2.13"></script>
<script data-require="[email protected]" data-semver="0.2.8" src="http://angular-ui.github.io/ui-router/release/angular-ui-router.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<a ui-sref="outer" style="width:300px;height:300px;background:yellow;">
Outer
<span ui-sref="inner" style="width:100px;height:100px;background:red;">Inner</span>
</a>
</body>
</html>
Javascript:
var app = angular.module('plunker', ['ui.router']);
'use strict';
app.config(['$stateProvider', '$urlRouterProvider', '$locationProvider', function($stateProvider, $urlRouterProvider, $locationProvider) {
$stateProvider
.state("outer", {
url: "/outer",
resolve: {
test: function() {
alert("Triggered state outer");
return true;
}
}
})
.state("inner", {
url: "/inner",
resolve: {
test: function() {
alert("Triggered state inner");
return true;
}
}
});
}]);
app.controller('MainCtrl', function($scope) {
});
Link: http://plnkr.co/edit/yzgUAA3lLwkF9svzczl3?p=preview
Questions:
How to prevent inner to trigger outer state?
Should I implement some kind of stopImmediatePropagation
for the inner DOM so it won't trigger the parent DOM's ui-sref
?
Are there alternatives? Maybe using $state.go
manually?
UPDATE 1:
I cannot change HTML due to requirement. This is just a simplified version because in my code, the outer element is very large containing other elements.
Upvotes: 19
Views: 7947
Reputation: 11137
For a completely different purpose I had a stopEvent directive just waiting to be used for the nested ui-sref
purpose.
<a ui-sref="outer">
Outer
<span ui-sref="inner" stop-event>Inner</span>
</a>
This is the directive
app.directive('stopEvent', function () {
return {
restrict: 'A',
link: function (scope, element, attr) {
element.bind('click', function (e) {
e.stopPropagation();
});
}
};
});
Upvotes: 2
Reputation: 585
USE THIS...
<a ui-sref="outer" style="width:300px;height:300px;background:yellow;">
Outer
<span ui-sref="inner" style="width:100px;height:100px;background:red;"
ng-click="$event.stopPropagation()">Inner</span>
</a>
Upvotes: 40
Reputation: 730
The problem is not with your javascript code but your html
<a ui-sref="outer" style="width:300px;height:300px;background:yellow;">
Outer
<span ui-sref="inner" style="width:100px;height:100px;background:red;">Inner</span>
</a>
when you click anywhere inside the tag, outer state will be invoked.
your
Inner
lies inside tag so this html element is bound to both ui-sref="inner" and ui-sref="outer"
the below code should solve your problem
<a ui-sref="outer" style="width:300px;height:300px;background:yellow;">
Outer
</a>
<span ui-sref="inner" style="width:100px;height:100px;background:red;">Inner</span>
Upvotes: 0
Reputation: 1548
Add the event stop propogation/event prevent default at ur inner stateprovider :
$stateProvider.state("outer", {
url: "/outer",
resolve: {
test: function() {
alert("Triggered state outer");
return true;
}
}
}).state("inner", {
url: "/inner",
resolve: {
test: function() {
alert("Triggered state inner");
//$event.stopPropagation();
$event.preventDefault();
return true;
}
}
})
Update 1: I tried on plunker demo and $event is available. As per angular doc also for
Event object is available as $event. DEMO Angular doc
Update 2: Above works if u press outer div first but that's not rt solution I agree. So here is another solution which works. checking the statechangestart of scope and saving last state name in var and checking if its inner then event preventdefault;
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
var laststate = "";
$scope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams) {
//alert(laststate);
if (laststate == "inner") {
event.preventDefault();
}
laststate = toState.name;
});
});
Upvotes: 0
Reputation: 19896
This works
<a ui-sref="outer" style="width:300px;height:300px;background:yellow;">
Outer
<span ui-sref="inner" style="width:100px;height:100px;background:red;" ng-click="$event.stopPropagation()">Inner</span>
</a>
I didn't know you can add ng-click="$event.stopPropagation()"
in the same element as ui-sref
Upvotes: 6
Reputation: 33399
Should I implement some kind of
stopImmediatePropagation
for the inner DOM so it won't trigger the parent DOM'sui-sref
?
Yes, exactly.
Alternately, you might be able to rearrange your HTML so that the don't have a parent/child relationship.
Upvotes: 0