Skip to content

Commit 7de47f4

Browse files
committed
Ensuring state transitions from uiSref are relative to containing uiView.
1 parent 13776a9 commit 7de47f4

File tree

3 files changed

+46
-7
lines changed

3 files changed

+46
-7
lines changed

src/state.js

+1
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $
211211

212212
$state.transitionTo = function transitionTo(to, toParams, options) {
213213
if (!isDefined(options)) options = (options === true || options === false) ? { location: options } : {};
214+
toParams = toParams || {};
214215
options = extend({ location: true, inherit: false, relative: null }, options);
215216

216217
var toState = findState(to, options.relative);

src/stateDirectives.js

+9-3
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,21 @@ function $StateRefDirective($state) {
1010
restrict: 'A',
1111
link: function(scope, element, attrs) {
1212
var ref = parseStateRef(attrs.uiSref);
13-
var params = null, url = null;
13+
var params = null, url = null, base = $state.$current;
1414
var isForm = element[0].nodeName === "FORM";
1515
var attr = isForm ? "action" : "href", nav = true;
1616

17+
var stateData = element.parent().inheritedData('$uiView');
18+
19+
if (stateData && stateData.state && stateData.state.name) {
20+
base = stateData.state;
21+
}
22+
1723
var update = function(newVal) {
1824
if (newVal) params = newVal;
1925
if (!nav) return;
2026

21-
var newHref = $state.href(ref.state, params);
27+
var newHref = $state.href(ref.state, params, { relative: base });
2228

2329
if (!newHref) {
2430
nav = false;
@@ -39,7 +45,7 @@ function $StateRefDirective($state) {
3945

4046
element.bind("click", function(e) {
4147
if ((e.which == 1) && !e.ctrlKey && !e.metaKey && !e.shiftKey) {
42-
$state.go(ref.state, params);
48+
$state.go(ref.state, params, { relative: base });
4349
scope.$apply();
4450
e.preventDefault();
4551
}

test/stateDirectivesSpec.js

+36-4
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
describe('uiStateRef', function() {
22

3-
var el, scope, document;
3+
var el, template, scope, document;
44

55
beforeEach(module('ui.router'));
66

77
beforeEach(module(function($stateProvider) {
88
$stateProvider.state('index', {
99
url: '/'
1010
}).state('contacts', {
11-
url: '/contacts'
11+
url: '/contacts',
12+
template: '<a ui-sref=".item({ id: 5 })" class="item">Person</a> <ui-view></ui-view>'
1213
}).state('contacts.item', {
13-
url: '/:id'
14-
}).state('contacts.item.detail', {});
14+
url: '/:id',
15+
template: '<a ui-sref=".detail" class="item-detail">Detail</a> | <a ui-sref="^" class="item-parent">Parent</a> | <ui-view></ui-view>'
16+
}).state('contacts.item.detail', {
17+
template: '<div class="title">Detail</div> | <a ui-sref="^" class="item-parent2">Item</a>'
18+
});
1519
}));
1620

1721
beforeEach(inject(function($document) {
@@ -148,6 +152,7 @@ describe('uiStateRef', function() {
148152
scope.$apply();
149153

150154
$compile(el)(scope);
155+
template = $compile(angular.element('<ui-view></ui-view>'))(scope);
151156
scope.$digest();
152157
}));
153158

@@ -158,5 +163,32 @@ describe('uiStateRef', function() {
158163
expect($state.$current.name).toBe("contacts.item.detail");
159164
expect($state.params).toEqual({ id: '5' });
160165
}));
166+
167+
it('should resolve states from parent uiView', inject(function ($state, $stateParams, $q) {
168+
$state.transitionTo('contacts');
169+
$q.flush();
170+
171+
var parentToChild = angular.element(template[0].querySelector('a.item'));
172+
triggerClick(parentToChild);
173+
$q.flush();
174+
175+
var childToGrandchild = angular.element(template[0].querySelector('a.item-detail'));
176+
var childToParent = angular.element(template[0].querySelector('a.item-parent'));
177+
178+
triggerClick(childToGrandchild);
179+
$q.flush();
180+
181+
var grandchildToParent = angular.element(template[0].querySelector('a.item-parent2'));
182+
expect($state.$current.name).toBe("contacts.item.detail")
183+
184+
triggerClick(grandchildToParent);
185+
$q.flush();
186+
expect($state.$current.name).toBe("contacts.item");
187+
188+
$state.transitionTo("contacts.item.detail", { id: 3 });
189+
triggerClick(childToParent);
190+
$q.flush();
191+
expect($state.$current.name).toBe("contacts");
192+
}));
161193
});
162194
});

0 commit comments

Comments
 (0)