From 0c6b0b227bd82e14e647c6ccb2ad773f290da8b1 Mon Sep 17 00:00:00 2001 From: Yuriy Sannikov Date: Fri, 8 May 2015 18:18:34 -0400 Subject: [PATCH] Fix issue with angular router and route-segment uses side-by-side When your application in a transition stage, some of routes registered old way. When you navigate through these url's your app view segment remains the same. This happens when you have something like this: ng-view div(app-view-segment="0") --- build/angular-route-segment.js | 153 +++++++++++++++-------------- build/angular-route-segment.min.js | 2 +- src/route-segment.js | 153 +++++++++++++++-------------- 3 files changed, 159 insertions(+), 149 deletions(-) diff --git a/build/angular-route-segment.js b/build/angular-route-segment.js index b9efc11..64a73db 100644 --- a/build/angular-route-segment.js +++ b/build/angular-route-segment.js @@ -223,103 +223,108 @@ mod.provider( '$routeSegment', $rootScope.$on('$routeChangeSuccess', function(event, args) { var route = args.$route || args.$$route; - if(route && route.segment) { + if(!route || !route.segment) { + // Clear outermost segment if this route wasn't configured by route-segment + $rootScope.$broadcast( 'routeSegmentChange', { + index: 0, + segment: {} } ); + return; + } - var segmentName = route.segment; - var segmentNameChain = segmentName.split("."); - var updates = [], lastUpdateIndex = -1; + var segmentName = route.segment; + var segmentNameChain = segmentName.split("."); + var updates = [], lastUpdateIndex = -1; + + for(var i=0; i < segmentNameChain.length; i++) { - for(var i=0; i < segmentNameChain.length; i++) { - - var newSegment = getSegmentInChain( i, segmentNameChain ); + var newSegment = getSegmentInChain( i, segmentNameChain ); - if(resolvingSemaphoreChain[i] != newSegment.name || updates.length > 0 || isDependenciesChanged(newSegment)) { + if(resolvingSemaphoreChain[i] != newSegment.name || updates.length > 0 || isDependenciesChanged(newSegment)) { - if($routeSegment.chain[i] && $routeSegment.chain[i].name == newSegment.name && - updates.length == 0 && !isDependenciesChanged(newSegment)) - // if we went back to the same state as we were before resolving new segment - resolvingSemaphoreChain[i] = newSegment.name; - else { - updates.push({index: i, newSegment: newSegment}); - lastUpdateIndex = i; - } - } - } + if($routeSegment.chain[i] && $routeSegment.chain[i].name == newSegment.name && + updates.length == 0 && !isDependenciesChanged(newSegment)) + // if we went back to the same state as we were before resolving new segment + resolvingSemaphoreChain[i] = newSegment.name; + else { + updates.push({index: i, newSegment: newSegment}); + lastUpdateIndex = i; + } + } + } - var curSegmentPromise = $q.when(); + var curSegmentPromise = $q.when(); - if(updates.length > 0) { + if(updates.length > 0) { - for(var i=0; i segmentNameChain.length) { - var oldLength = $routeSegment.chain.length; - var shortenBy = $routeSegment.chain.length - segmentNameChain.length; - $routeSegment.chain.splice(-shortenBy, shortenBy); - for(var i=segmentNameChain.length; i < oldLength; i++) { - updateSegment(i, null); - lastUpdateIndex = $routeSegment.chain.length-1; - } + // Removing redundant segment in case if new segment chain is shorter than old one + if($routeSegment.chain.length > segmentNameChain.length) { + var oldLength = $routeSegment.chain.length; + var shortenBy = $routeSegment.chain.length - segmentNameChain.length; + $routeSegment.chain.splice(-shortenBy, shortenBy); + for(var i=segmentNameChain.length; i < oldLength; i++) { + updateSegment(i, null); + lastUpdateIndex = $routeSegment.chain.length-1; } - }).then(function() { - - var defaultChildUpdatePromise = $q.when(); - - if(lastUpdateIndex == $routeSegment.chain.length-1) { - - var curSegment = getSegmentInChain(lastUpdateIndex, $routeSegment.name.split(".")); - - while(curSegment) { - var children = curSegment.children, index = lastUpdateIndex+1; - curSegment = null; - for (var i in children) { - (function(i, children, index) { - if (children[i].params['default']) { - defaultChildUpdatePromise = defaultChildUpdatePromise.then(function () { - return updateSegment(index, {name: children[i].name, params: children[i].params}) - .then(function (result) { - if (result.success) broadcast(result.success); - }); - }); - curSegment = children[i]; - lastUpdateIndex = index; - } - })(i, children, index); - + } + }).then(function() { + + var defaultChildUpdatePromise = $q.when(); + + if(lastUpdateIndex == $routeSegment.chain.length-1) { + + var curSegment = getSegmentInChain(lastUpdateIndex, $routeSegment.name.split(".")); + + while(curSegment) { + var children = curSegment.children, index = lastUpdateIndex+1; + curSegment = null; + for (var i in children) { + (function(i, children, index) { + if (children[i].params['default']) { + defaultChildUpdatePromise = defaultChildUpdatePromise.then(function () { + return updateSegment(index, {name: children[i].name, params: children[i].params}) + .then(function (result) { + if (result.success) broadcast(result.success); + }); + }); + curSegment = children[i]; + lastUpdateIndex = index; + } + })(i, children, index); + - } } } + } - return defaultChildUpdatePromise; - }); - } + return defaultChildUpdatePromise; + }); }); function isDependenciesChanged(segment) { diff --git a/build/angular-route-segment.min.js b/build/angular-route-segment.min.js index a7572f9..b86e93f 100644 --- a/build/angular-route-segment.min.js +++ b/build/angular-route-segment.min.js @@ -4,4 +4,4 @@ * @author Artem Chivchalov * @license MIT License http://opensource.org/licenses/MIT */ -"use strict";!function(a){var b=a.module("route-segment",[]);b.provider("$routeSegment",["$routeProvider",function(b){function c(a){return a.replace(/([\:\-\_]+(.))/g,function(a,b,c,d){return d?c.toUpperCase():c})}function d(a,b){if(!a)throw new Error("Invalid pointer segment");var e;return{segment:function(b,d){return a[c(b)]={name:b,params:d},e=b,this},within:function(b){var g;if(b=b||e,g=a[c(b)])void 0==g.children&&(g.children={});else{if(f.strictMode)throw new Error("Cannot get into unknown `"+b+"` segment");g=a[c(b)]={params:{},children:{}}}return d(g.children,this)},up:function(){return b},root:function(){return h}}}var e=this,f=e.options={autoLoadTemplates:!0,strictMode:!1},g=this.segments={},h=d(g,null),i={};e.when=function(a,c){return b.when(a,{segment:c}),i[c]=a,this},a.extend(e,h),this.$get=["$rootScope","$q","$http","$templateCache","$route","$routeParams","$injector",function(b,d,e,h,j,k,l){function m(b){var c=!1;return b.params.dependencies&&a.forEach(b.params.dependencies,function(b){a.equals(r.$routeParams[b],k[b])||(c=!0)}),c}function n(a,b){return r.chain[a]&&r.chain[a].clearWatcher&&r.chain[a].clearWatcher(),b?(s[a]=b.name,b.params.untilResolved?o(a,b.name,b.params.untilResolved).then(function(c){return void 0!=c.success&&p(a),o(a,b.name,b.params)}):o(a,b.name,b.params)):(s[a]=null,void p(a))}function o(c,g,i){var j=a.extend({},i.resolve);return a.forEach(j,function(b,c){j[c]=a.isString(b)?l.get(b):l.invoke(b)}),i.template&&(j.$template=i.template,a.isFunction(j.$template)&&(j.$template=l.invoke(j.$template))),f.autoLoadTemplates&&i.templateUrl&&(j.$template=i.templateUrl,a.isFunction(j.$template)&&(j.$template=l.invoke(j.$template)),j.$template=e.get(j.$template,{cache:h}).then(function(a){return a.data})),d.all(j).then(function(e){if(s[c]!=g)return d.reject();if(r.chain[c]={name:g,params:i,locals:e,reload:function(){var a=q(c,r.name.split("."));n(c,a).then(function(a){void 0!=a.success&&p(c)})}},i.watcher){var f=function(){if(!a.isFunction(i.watcher)&&!a.isArray(i.watcher))throw new Error("Watcher is not a function in segment `"+g+"`");return l.invoke(i.watcher,{},{segment:r.chain[c]})},h=f();r.chain[c].clearWatcher=b.$watch(f,function(a){a!=h&&(h=a,r.chain[c].reload())})}return{success:c}},function(b){if(i.resolveFailed){var e={error:function(){return d.when(b)}};return o(c,g,a.extend({resolve:e},i.resolveFailed))}throw new Error("Resolving failed with a reason `"+b+"`, but no `resolveFailed` provided for segment `"+g+"`")})}function p(c){r.$routeParams=a.copy(k),r.name="";for(var d=0;d=b.length)return null;for(var d,e=g,f=0;a>=f;f++)d=b[f],void 0!=e[c(d)]&&(e=e[c(d)]),a>f&&(e=e.children);return{name:d,params:e.params,children:e.children}}var r={name:"",$routeParams:a.copy(k),chain:[],startsWith:function(a){var b=new RegExp("^"+a);return b.test(r.name)},contains:function(a){for(var b=0;b0||m(j))&&(r.chain[i]&&r.chain[i].name==j.name&&0==g.length&&!m(j)?s[i]=j.name:(g.push({index:i,newSegment:j}),h=i))}var k=d.when();if(g.length>0)for(var i=0;if.length){var a=r.chain.length,b=r.chain.length-f.length;r.chain.splice(-b,b);for(var c=f.length;a>c;c++)n(c,null),h=r.chain.length-1}}).then(function(){var a=d.when();if(h==r.chain.length-1)for(var b=q(h,r.name.split("."));b;){var c=b.children,e=h+1;b=null;for(var f in c)!function(c,d,e){d[c].params["default"]&&(a=a.then(function(){return n(e,{name:d[c].name,params:d[c].params}).then(function(a){a.success&&p(a.success)})}),b=d[c],h=e)}(f,c,e)}return a})}}),r}]}]),b.filter("routeSegmentUrl",["$routeSegment",function(a){var b=function(b,c){return a.getSegmentUrl(b,c)};return b.$stateful=!0,b}]),b.filter("routeSegmentEqualsTo",["$routeSegment",function(a){var b=function(b){return a.name==b};return b.$stateful=!0,b}]),b.filter("routeSegmentStartsWith",["$routeSegment",function(a){var b=function(b){return a.startsWith(b)};return b.$stateful=!0,b}]),b.filter("routeSegmentContains",["$routeSegment",function(a){var b=function(b){return a.contains(b)};return b.$stateful=!0,b}]),b.filter("routeSegmentParam",["$routeSegment",function(a){var b=function(b){return a.$routeParams[b]};return b.$stateful=!0,b}])}(angular),function(a){a.module("view-segment",["route-segment"]).directive("appViewSegment",["$route","$compile","$controller","$routeParams","$routeSegment","$q","$injector","$timeout","$animate",function(a,b,c,d,e,f,g,h,i){return{restrict:"ECA",priority:400,transclude:"element",compile:function(a,b){return function(a,c,d,f,g){function j(){o&&(i.cancel(o),o=null),l&&(l.$destroy(),l=null),m&&(o=i.leave(m),o&&o.then(function(){o=null}),m=null)}function k(b){p=b;var d=a.$new(),e=g(d,function(a){b&&a.data("viewSegment",b),i.enter(a,null,m||c),j()});m=e,l=d,l.$emit("$viewContentLoaded"),l.$eval(q)}var l,m,n,o,p={},q=b.onload||"",r=parseInt(b.appViewSegment);e.chain[r]?n=h(function(){k(e.chain[r])},0):k(),a.$on("routeSegmentChange",function(a,b){n&&h.cancel(n),b.index==r&&p!=b.segment&&k(b.segment)})}}}}]),a.module("view-segment").directive("appViewSegment",["$route","$compile","$controller",function(b,c,d){return{restrict:"ECA",priority:-400,link:function(b,e){var f=e.data("viewSegment")||{},g=a.extend({},f.locals),h=g&&g.$template;h&&e.html(h);var i=c(e.contents());if(f.params&&f.params.controller){g.$scope=b;var j=d(f.params.controller,g);f.params.controllerAs&&(b[f.params.controllerAs]=j),e.data("$ngControllerController",j),e.children().data("$ngControllerController",j)}i(b)}}}])}(angular); \ No newline at end of file +"use strict";!function(a){var b=a.module("route-segment",[]);b.provider("$routeSegment",["$routeProvider",function(b){function c(a){return a.replace(/([\:\-\_]+(.))/g,function(a,b,c,d){return d?c.toUpperCase():c})}function d(a,b){if(!a)throw new Error("Invalid pointer segment");var e;return{segment:function(b,d){return a[c(b)]={name:b,params:d},e=b,this},within:function(b){var g;if(b=b||e,g=a[c(b)])void 0==g.children&&(g.children={});else{if(f.strictMode)throw new Error("Cannot get into unknown `"+b+"` segment");g=a[c(b)]={params:{},children:{}}}return d(g.children,this)},up:function(){return b},root:function(){return h}}}var e=this,f=e.options={autoLoadTemplates:!0,strictMode:!1},g=this.segments={},h=d(g,null),i={};e.when=function(a,c){return b.when(a,{segment:c}),i[c]=a,this},a.extend(e,h),this.$get=["$rootScope","$q","$http","$templateCache","$route","$routeParams","$injector",function(b,d,e,h,j,k,l){function m(b){var c=!1;return b.params.dependencies&&a.forEach(b.params.dependencies,function(b){a.equals(r.$routeParams[b],k[b])||(c=!0)}),c}function n(a,b){return r.chain[a]&&r.chain[a].clearWatcher&&r.chain[a].clearWatcher(),b?(s[a]=b.name,b.params.untilResolved?o(a,b.name,b.params.untilResolved).then(function(c){return void 0!=c.success&&p(a),o(a,b.name,b.params)}):o(a,b.name,b.params)):(s[a]=null,void p(a))}function o(c,g,i){var j=a.extend({},i.resolve);return a.forEach(j,function(b,c){j[c]=a.isString(b)?l.get(b):l.invoke(b)}),i.template&&(j.$template=i.template,a.isFunction(j.$template)&&(j.$template=l.invoke(j.$template))),f.autoLoadTemplates&&i.templateUrl&&(j.$template=i.templateUrl,a.isFunction(j.$template)&&(j.$template=l.invoke(j.$template)),j.$template=e.get(j.$template,{cache:h}).then(function(a){return a.data})),d.all(j).then(function(e){if(s[c]!=g)return d.reject();if(r.chain[c]={name:g,params:i,locals:e,reload:function(){var a=q(c,r.name.split("."));n(c,a).then(function(a){void 0!=a.success&&p(c)})}},i.watcher){var f=function(){if(!a.isFunction(i.watcher)&&!a.isArray(i.watcher))throw new Error("Watcher is not a function in segment `"+g+"`");return l.invoke(i.watcher,{},{segment:r.chain[c]})},h=f();r.chain[c].clearWatcher=b.$watch(f,function(a){a!=h&&(h=a,r.chain[c].reload())})}return{success:c}},function(b){if(i.resolveFailed){var e={error:function(){return d.when(b)}};return o(c,g,a.extend({resolve:e},i.resolveFailed))}throw new Error("Resolving failed with a reason `"+b+"`, but no `resolveFailed` provided for segment `"+g+"`")})}function p(c){r.$routeParams=a.copy(k),r.name="";for(var d=0;d=b.length)return null;for(var d,e=g,f=0;a>=f;f++)d=b[f],void 0!=e[c(d)]&&(e=e[c(d)]),a>f&&(e=e.children);return{name:d,params:e.params,children:e.children}}var r={name:"",$routeParams:a.copy(k),chain:[],startsWith:function(a){var b=new RegExp("^"+a);return b.test(r.name)},contains:function(a){for(var b=0;b0||m(k))&&(r.chain[j]&&r.chain[j].name==k.name&&0==h.length&&!m(k)?s[j]=k.name:(h.push({index:j,newSegment:k}),i=j))}var l=d.when();if(h.length>0)for(var j=0;jg.length){var a=r.chain.length,b=r.chain.length-g.length;r.chain.splice(-b,b);for(var c=g.length;a>c;c++)n(c,null),i=r.chain.length-1}}).then(function(){var a=d.when();if(i==r.chain.length-1)for(var b=q(i,r.name.split("."));b;){var c=b.children,e=i+1;b=null;for(var f in c)!function(c,d,e){d[c].params["default"]&&(a=a.then(function(){return n(e,{name:d[c].name,params:d[c].params}).then(function(a){a.success&&p(a.success)})}),b=d[c],i=e)}(f,c,e)}return a})}),r}]}]),b.filter("routeSegmentUrl",["$routeSegment",function(a){var b=function(b,c){return a.getSegmentUrl(b,c)};return b.$stateful=!0,b}]),b.filter("routeSegmentEqualsTo",["$routeSegment",function(a){var b=function(b){return a.name==b};return b.$stateful=!0,b}]),b.filter("routeSegmentStartsWith",["$routeSegment",function(a){var b=function(b){return a.startsWith(b)};return b.$stateful=!0,b}]),b.filter("routeSegmentContains",["$routeSegment",function(a){var b=function(b){return a.contains(b)};return b.$stateful=!0,b}]),b.filter("routeSegmentParam",["$routeSegment",function(a){var b=function(b){return a.$routeParams[b]};return b.$stateful=!0,b}])}(angular),function(a){a.module("view-segment",["route-segment"]).directive("appViewSegment",["$route","$compile","$controller","$routeParams","$routeSegment","$q","$injector","$timeout","$animate",function(a,b,c,d,e,f,g,h,i){return{restrict:"ECA",priority:400,transclude:"element",compile:function(a,b){return function(a,c,d,f,g){function j(){o&&(i.cancel(o),o=null),l&&(l.$destroy(),l=null),m&&(o=i.leave(m),o&&o.then(function(){o=null}),m=null)}function k(b){p=b;var d=a.$new(),e=g(d,function(a){b&&a.data("viewSegment",b),i.enter(a,null,m||c),j()});m=e,l=d,l.$emit("$viewContentLoaded"),l.$eval(q)}var l,m,n,o,p={},q=b.onload||"",r=parseInt(b.appViewSegment);e.chain[r]?n=h(function(){k(e.chain[r])},0):k(),a.$on("routeSegmentChange",function(a,b){n&&h.cancel(n),b.index==r&&p!=b.segment&&k(b.segment)})}}}}]),a.module("view-segment").directive("appViewSegment",["$route","$compile","$controller",function(b,c,d){return{restrict:"ECA",priority:-400,link:function(b,e){var f=e.data("viewSegment")||{},g=a.extend({},f.locals),h=g&&g.$template;h&&e.html(h);var i=c(e.contents());if(f.params&&f.params.controller){g.$scope=b;var j=d(f.params.controller,g);f.params.controllerAs&&(b[f.params.controllerAs]=j),e.data("$ngControllerController",j),e.children().data("$ngControllerController",j)}i(b)}}}])}(angular); \ No newline at end of file diff --git a/src/route-segment.js b/src/route-segment.js index 66b7b4b..b58ecb8 100644 --- a/src/route-segment.js +++ b/src/route-segment.js @@ -217,103 +217,108 @@ mod.provider( '$routeSegment', $rootScope.$on('$routeChangeSuccess', function(event, args) { var route = args.$route || args.$$route; - if(route && route.segment) { + if(!route || !route.segment) { + // Clear outermost segment if this route wasn't configured by route-segment + $rootScope.$broadcast( 'routeSegmentChange', { + index: 0, + segment: {} } ); + return; + } - var segmentName = route.segment; - var segmentNameChain = segmentName.split("."); - var updates = [], lastUpdateIndex = -1; + var segmentName = route.segment; + var segmentNameChain = segmentName.split("."); + var updates = [], lastUpdateIndex = -1; + + for(var i=0; i < segmentNameChain.length; i++) { - for(var i=0; i < segmentNameChain.length; i++) { - - var newSegment = getSegmentInChain( i, segmentNameChain ); + var newSegment = getSegmentInChain( i, segmentNameChain ); - if(resolvingSemaphoreChain[i] != newSegment.name || updates.length > 0 || isDependenciesChanged(newSegment)) { + if(resolvingSemaphoreChain[i] != newSegment.name || updates.length > 0 || isDependenciesChanged(newSegment)) { - if($routeSegment.chain[i] && $routeSegment.chain[i].name == newSegment.name && - updates.length == 0 && !isDependenciesChanged(newSegment)) - // if we went back to the same state as we were before resolving new segment - resolvingSemaphoreChain[i] = newSegment.name; - else { - updates.push({index: i, newSegment: newSegment}); - lastUpdateIndex = i; - } - } - } + if($routeSegment.chain[i] && $routeSegment.chain[i].name == newSegment.name && + updates.length == 0 && !isDependenciesChanged(newSegment)) + // if we went back to the same state as we were before resolving new segment + resolvingSemaphoreChain[i] = newSegment.name; + else { + updates.push({index: i, newSegment: newSegment}); + lastUpdateIndex = i; + } + } + } - var curSegmentPromise = $q.when(); + var curSegmentPromise = $q.when(); - if(updates.length > 0) { + if(updates.length > 0) { - for(var i=0; i segmentNameChain.length) { - var oldLength = $routeSegment.chain.length; - var shortenBy = $routeSegment.chain.length - segmentNameChain.length; - $routeSegment.chain.splice(-shortenBy, shortenBy); - for(var i=segmentNameChain.length; i < oldLength; i++) { - updateSegment(i, null); - lastUpdateIndex = $routeSegment.chain.length-1; - } + // Removing redundant segment in case if new segment chain is shorter than old one + if($routeSegment.chain.length > segmentNameChain.length) { + var oldLength = $routeSegment.chain.length; + var shortenBy = $routeSegment.chain.length - segmentNameChain.length; + $routeSegment.chain.splice(-shortenBy, shortenBy); + for(var i=segmentNameChain.length; i < oldLength; i++) { + updateSegment(i, null); + lastUpdateIndex = $routeSegment.chain.length-1; } - }).then(function() { - - var defaultChildUpdatePromise = $q.when(); - - if(lastUpdateIndex == $routeSegment.chain.length-1) { - - var curSegment = getSegmentInChain(lastUpdateIndex, $routeSegment.name.split(".")); - - while(curSegment) { - var children = curSegment.children, index = lastUpdateIndex+1; - curSegment = null; - for (var i in children) { - (function(i, children, index) { - if (children[i].params['default']) { - defaultChildUpdatePromise = defaultChildUpdatePromise.then(function () { - return updateSegment(index, {name: children[i].name, params: children[i].params}) - .then(function (result) { - if (result.success) broadcast(result.success); - }); - }); - curSegment = children[i]; - lastUpdateIndex = index; - } - })(i, children, index); - + } + }).then(function() { + + var defaultChildUpdatePromise = $q.when(); + + if(lastUpdateIndex == $routeSegment.chain.length-1) { + + var curSegment = getSegmentInChain(lastUpdateIndex, $routeSegment.name.split(".")); + + while(curSegment) { + var children = curSegment.children, index = lastUpdateIndex+1; + curSegment = null; + for (var i in children) { + (function(i, children, index) { + if (children[i].params['default']) { + defaultChildUpdatePromise = defaultChildUpdatePromise.then(function () { + return updateSegment(index, {name: children[i].name, params: children[i].params}) + .then(function (result) { + if (result.success) broadcast(result.success); + }); + }); + curSegment = children[i]; + lastUpdateIndex = index; + } + })(i, children, index); + - } } } + } - return defaultChildUpdatePromise; - }); - } + return defaultChildUpdatePromise; + }); }); function isDependenciesChanged(segment) {