From bad0b4d4602f557ccd96da165b387decce893efd Mon Sep 17 00:00:00 2001 From: Francesco Pontillo Date: Mon, 2 Sep 2013 17:07:47 +0200 Subject: [PATCH] fix(stateDirectives): Generate the proper URL when the state changes As of now, the generated URL changes if and only if its parameters do. So something like `ui-sref="{{myState}}({id: myId})" would simply work for the first time. When `$scope.myState` changes and `$scope.myId` stays the same, the URL is not regenerated. This commit fixes this by observing the attribute and regenerating the URL if it changes. I have also added a test to make sure everything works. This commit may also be also be relevant for #371, as it allows for empty state values (` `) to be processed and set into the `href` attribute. We could bind this parameter to a directive attribute so the user can decide wether to accept this behavior or not. --- src/stateDirectives.js | 26 ++++++++++++++++++-------- test/stateDirectivesSpec.js | 18 ++++++++++++++++-- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/stateDirectives.js b/src/stateDirectives.js index 38078d26d..1a9a2607b 100644 --- a/src/stateDirectives.js +++ b/src/stateDirectives.js @@ -13,6 +13,7 @@ function $StateRefDirective($state) { var params = null, url = null; var isForm = element[0].nodeName === "FORM"; var attr = isForm ? "action" : "href", nav = true; + var allowEmptyState = true; // Use attribute to set this? var update = function(newVal) { if (newVal) params = newVal; @@ -20,19 +21,28 @@ function $StateRefDirective($state) { var newHref = $state.href(ref.state, params); - if (!newHref) { + if (!newHref && !allowEmptyState) { nav = false; return false; } element[0][attr] = newHref; }; - - if (ref.paramExpr) { - scope.$watch(ref.paramExpr, function(newVal, oldVal) { - if (newVal !== oldVal) update(newVal); - }, true); - params = scope.$eval(ref.paramExpr); - } + + attrs.$observe('uiSref', function(newVal, oldVal) { + if (newVal !== oldVal) { + ref = parseStateRef(attrs.uiSref); + params = scope.$eval(ref.paramExpr); + update(params); + + if (ref) { + scope.$watch(ref.paramExpr, function(newVal, oldVal) { + if (newVal !== oldVal) update(newVal); + }, true); + params = scope.$eval(ref.paramExpr); + } + } + }, true); + update(); if (isForm) return; diff --git a/test/stateDirectivesSpec.js b/test/stateDirectivesSpec.js index 2a31b3c20..ed4b46953 100644 --- a/test/stateDirectivesSpec.js +++ b/test/stateDirectivesSpec.js @@ -11,7 +11,10 @@ describe('uiStateRef', function() { url: '/contacts' }).state('contacts.item', { url: '/:id' - }).state('contacts.item.detail', {}); + }).state('contacts.item.detail', { + }).state('contacts.item.more', { + url: '/more' + }); })); beforeEach(inject(function($document) { @@ -51,8 +54,9 @@ describe('uiStateRef', function() { describe('links', function() { beforeEach(inject(function($rootScope, $compile) { - el = angular.element('Details'); + el = angular.element('Details'); scope = $rootScope; + scope.state = 'contacts.item.detail'; scope.contact = { id: 5 }; scope.$apply(); @@ -64,6 +68,16 @@ describe('uiStateRef', function() { expect(el.attr('href')).toBe('#/contacts/5'); }); + it('should update the href when the state changes', function() { + expect(el.attr('href')).toBe('#/contacts/5'); + scope.state = 'contacts.item.more'; + scope.$apply(); + expect(el.attr('href')).toBe('#/contacts/5/more'); + scope.state = 'contacts.item.detail'; + scope.$apply(); + expect(el.attr('href')).toBe('#/contacts/5'); + }); + it('should update the href when parameters change', function() { expect(el.attr('href')).toBe('#/contacts/5'); scope.contact.id = 6;