From b0a87f9e3180cb55031bf2f4d410644f72d79e44 Mon Sep 17 00:00:00 2001 From: Pavel Jbanov Date: Mon, 26 May 2014 13:25:00 -0400 Subject: [PATCH] feat(router): added vetoable preLeave event BREAKING CHANGE Previously, vetoing was allowed on leave (RouteLeaveEvent) which caused issues because routes had no way to recover from other route vetoing a leave event. Now, similar to preEnter and enter, leave event was split into vetoable preLeave (RoutePreLeaveEvent) and non-vetoable leave (RouteLeaveEvent). views.configure({ 'foo': ngRoute( path: '/foo', preLeave: (RoutePreLeaveEvent e) { e.allowLeave(new Future.value(false)); }) }); --- lib/routing/routing.dart | 12 +++++-- pubspec.lock | 2 +- pubspec.yaml | 2 +- test/angular_spec.dart | 2 ++ test/routing/routing_spec.dart | 60 ++++++++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 5 deletions(-) diff --git a/lib/routing/routing.dart b/lib/routing/routing.dart index c40aa0684..43f88f317 100644 --- a/lib/routing/routing.dart +++ b/lib/routing/routing.dart @@ -53,6 +53,11 @@ class RouteViewFactory { cfg.preEnter(e); } }, + preLeave: (RoutePreLeaveEvent e) { + if (cfg.preLeave != null) { + cfg.preLeave(e); + } + }, leave: cfg.leave, mount: (Route mountRoute) { if (cfg.mount != null) { @@ -66,10 +71,10 @@ class RouteViewFactory { NgRouteCfg ngRoute({String path, String view, String viewHtml, Map mount, modules(), bool defaultRoute: false, RoutePreEnterEventHandler preEnter, RouteEnterEventHandler enter, - RouteLeaveEventHandler leave}) => + RoutePreLeaveEventHandler preLeave, RouteLeaveEventHandler leave}) => new NgRouteCfg(path: path, view: view, viewHtml: viewHtml, mount: mount, modules: modules, defaultRoute: defaultRoute, preEnter: preEnter, - enter: enter, leave: leave); + preLeave: preLeave, enter: enter, leave: leave); class NgRouteCfg { final String path; @@ -80,10 +85,11 @@ class NgRouteCfg { final bool defaultRoute; final RouteEnterEventHandler enter; final RoutePreEnterEventHandler preEnter; + final RoutePreLeaveEventHandler preLeave; final RouteLeaveEventHandler leave; NgRouteCfg({this.view, this.viewHtml, this.path, this.mount, this.modules, - this.defaultRoute, this.enter, this.preEnter, this.leave}); + this.defaultRoute, this.enter, this.preEnter, this.preLeave, this.leave}); } /** diff --git a/pubspec.lock b/pubspec.lock index dc4a9ab74..da2d74f6e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -68,7 +68,7 @@ packages: route_hierarchical: description: route_hierarchical source: hosted - version: "0.4.20" + version: "0.4.21" source_maps: description: source_maps source: hosted diff --git a/pubspec.yaml b/pubspec.yaml index eb984f17f..55dbfe073 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -23,7 +23,7 @@ dependencies: html5lib: '>=0.10.0 <0.11.0' intl: '>=0.8.7 <0.10.0' perf_api: '>=0.0.8 <0.1.0' - route_hierarchical: '>=0.4.18 <0.5.0' + route_hierarchical: '>=0.4.21 <0.5.0' web_components: '>=0.3.3 <0.4.0' dev_dependencies: benchmark_harness: '>=1.0.0' diff --git a/test/angular_spec.dart b/test/angular_spec.dart index 638548bee..cc7485477 100644 --- a/test/angular_spec.dart +++ b/test/angular_spec.dart @@ -264,6 +264,8 @@ main() { "route.client.RouteLeaveEventHandler", "route.client.RoutePreEnterEvent", "route.client.RoutePreEnterEventHandler", + "route.client.RoutePreLeaveEvent", + "route.client.RoutePreLeaveEventHandler", "route.client.Router", "route.client.RouteStartEvent", "url_matcher.UrlMatch", diff --git a/test/routing/routing_spec.dart b/test/routing/routing_spec.dart index bbc63cd31..e94849708 100644 --- a/test/routing/routing_spec.dart +++ b/test/routing/routing_spec.dart @@ -169,6 +169,66 @@ main() { })); + it('should call preEnter callback and be able to veto', async(() { + int preEnterCount = 0; + initRouter((Router router, RouteViewFactory views) { + views.configure({ + 'foo': ngRoute( + path: '/foo', + preEnter: (RoutePreEnterEvent e) { + preEnterCount++; + e.allowEnter(new Future.value(false)); + }, + view: 'foo.html' + ), + }); + }); + + Element root = _.compile(''); + expect(root.text).toEqual(''); + + router.route('/foo'); + microLeap(); + + expect(preEnterCount).toBe(1); + expect(root.text).toEqual(''); // didn't enter. + })); + + + it('should call preLeave callback and be able to veto', async(() { + int preLeaveCount = 0; + initRouter((Router router, RouteViewFactory views) { + views.configure({ + 'foo': ngRoute( + path: '/foo', + preLeave: (RoutePreLeaveEvent e) { + preLeaveCount++; + e.allowLeave(new Future.value(false)); + }, + view: 'foo.html' + ), + }); + }); + _.injector.get(TemplateCache) + .put('foo.html', new HttpResponse(200, '

Foo

')); + + Element root = _.compile(''); + expect(root.text).toEqual(''); + + router.route('/foo'); + microLeap(); + + expect(preLeaveCount).toBe(0); + expect(root.text).toEqual('Foo'); + + router.route(''); + microLeap(); + + expect(preLeaveCount).toBe(1); + expect(root.text).toEqual('Foo'); // didn't leave. + })); + + it('should call preEnter callback and load modules', async(() { int preEnterCount = 0; int modulesCount = 0;