user728650
user728650

Reputation: 1986

Switching favicon dynamically in Aurelia preferably using binding

I have an Aurelia messaging app where I need to change the favicon dynamically when some new message is received.

Something that you might have observed many apps are doing these days to let the user know about a state change.

Especially helpful when the user is on other tabs.

Looking into similar questions here and here it seems pretty straight forward work in vanilla JS or in JQuery.

my current take on this problem is to add a function in my view model that can directly access the DOM.

activate() {
    PLATFORM.addEventListener('newMessageIsReceived', this.msgReceived, true);
    PLATFORM.addEventListener('msgIsRead', this.msgRead, true);       
  }

  deactivate() {
    PLATFORM.removeEventListener('newMessageIsReceived', this.msgReceived);
    PLATFORM.removeEventListener('msgIsRead', this.msgRead);
  }

  msgReceived(event) {
    // new msg received. Change the favicon to alert mode 
    let link = PLATFORM.querySelector("link[rel*='icon']") || PLATFORM.createElement('link');
    link.type = 'image/x-icon';
    link.rel = 'shortcut icon';
    link.href = 'alert.ico';
    PLATFORM.getElementsByTagName('head')[0].appendChild(link);
  }

  msgRead(event) {
     // msg read by the user, change the favicon back to default 
     let link = PLATFORM.querySelector("link[rel*='icon']") || PLATFORM.createElement('link');
     link.type = 'image/x-icon';
     link.rel = 'shortcut icon';
     link.href = 'default.ico';
     PLATFORM.getElementsByTagName('head')[0].appendChild(link);
  }

But the very obvious problem here is the very JQuery-ish approach to directly manipulate the DOM from inside my view model.

Considering this is just a special case, I can live with it but wondering if there is any better Aurelia way to achieve this.

something like

<link rel="shortcut icon" type="image/ico" href.bind="faviconLink">

But how can you use bindings in the head of your index page? Aurelia does update the page title on each route navigation and as the title is also outside the aurelia-app root, it should be possible to bind/manipulate other head properties as well from inside Aurelia app. right?

There is another interesting approach to use canvas and we can have dynamic favicons.

const canvas = document.createElement('canvas')
canvas.height = 64
canvas.width = 64

const ctx = canvas.getContext('2d')
ctx.font = '64px serif'
ctx.fillText('🛰', 0, 64)
console.log(canvas.toDataURL())

const favicon = document.querySelector('link[rel=icon]')
favicon.href = canvas.toDataURL()

but then again how to avoid the direct DOM manipulation and use the bindings of Aurelia even for this method?

Upvotes: 1

Views: 482

Answers (1)

bigopon
bigopon

Reputation: 1964

You can totally do this, demo here https://1rn1866v64.codesandbox.io/

source demo at https://codesandbox.io/s/1rn1866v64

copied at discourse https://discourse.aurelia.io/t/better-know-a-framework-21-enhance-document-head-with-aurelia/2374

What you want is a way to enhance document.head template to an object as view model. You can find the code for that demo here. Typically it looks this simple:

au.enhance({
  root: someObjectAsViewModel_for_the_enhancement,
  host: document.head
})
<link rel="icon" href.bind="iconHref">

Upvotes: 4

Related Questions