Reputation: 1986
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
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