router icon indicating copy to clipboard operation
router copied to clipboard

Page title updates

Open vlukashov opened this issue 6 years ago • 2 comments

As a developer I want to update the browser window title when the current route changes.

While there is no special support for this use case, it is straightforward to implement via the onAfterEnter route component lifecycle callback (see #23):

onAfterEnter() {
  document.title = 'Title';
}

vlukashov avatar Apr 25 '18 11:04 vlukashov

Related use case:

Sometimes we need to wait for something else to update the page title. For example, a request to the API to know the title of the post. The same could apply to other meta tags such as description.

abdonrd avatar Jul 31 '19 08:07 abdonrd

The problem with the onAfterEnter callback approach is that it can be seen as mixing concerns - the UI component becomes responsible for the page title, which could be understood as the responsibility of the routing table.

If the router instance itself had callbacks (i.e. hooks), users could implement this feature themselves fairly easily:

// strawman
const router = new Router(document.querySelector('main'), {
    onAfterEnter(location): void {
      const title =
        location.routes.reduceRight((title, route) =>
          title ?? route.metadata?.title ?? route.name ?? null, null);
      document.title = `App | ${title}`.replace(/ \| $/, '');
    },
});

I accomplished this locally using the following @vaadin+router+1.7.2.patch:

diff --git a/node_modules/@vaadin/router/dist/vaadin-router.js b/node_modules/@vaadin/router/dist/vaadin-router.js
index c0dc354..760d442 100644
--- a/node_modules/@vaadin/router/dist/vaadin-router.js
+++ b/node_modules/@vaadin/router/dist/vaadin-router.js
@@ -1524,6 +1524,7 @@ class Router extends Resolver {
     // Using WeakMap instead of WeakSet because WeakSet is not supported by IE11
     this.__createdByRouter = new WeakMap();
     this.__addedByRouter = new WeakMap();
+    this.onAfterEnter = options.onAfterEnter;
   }
 
   __resolveRoute(context) {
@@ -2173,6 +2174,12 @@ class Router extends Resolver {
         currentComponent.onAfterEnter,
         [location, {}, currentContext.resolver],
         currentComponent);
+      if (i === currentContext.chain.length - 1) {
+        runCallbackIfPossible(
+          this.onAfterEnter,
+          [location, {}, currentContext.resolver],
+          this);
+      }
     }
   }
 
diff --git a/node_modules/@vaadin/router/interfaces.d.ts b/node_modules/@vaadin/router/interfaces.d.ts
index 472b8bb..f492f81 100644
--- a/node_modules/@vaadin/router/interfaces.d.ts
+++ b/node_modules/@vaadin/router/interfaces.d.ts
@@ -124,6 +124,8 @@ declare module './dist/vaadin-router' {
 
   export interface RouterOptions {
     baseUrl?: string;
+    onBeforeEnter?: BeforeEnterObserver['onBeforeEnter'];
+    onAfterEnter?: AfterEnterObserver['onAfterEnter'];
   }
   type _RouterOptions = RouterOptions;

See also #465

bennypowers avatar Jul 27 '20 12:07 bennypowers