Better know a framework #21: enhance document head with Aurelia

Binding favicon to a view model, demo at https://1rn1866v64.codesandbox.io/

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

SO question at https://stackoverflow.com/questions/55175968/switching-favicon-dynamically-in-aurelia-preferably-using-binding/55178896

Basically enhance document.head with a view model:

aureliaInstance.enhance(someViewModel, document.head)

example:

document head:

<link rel="icon" href.bind="iconHref" >

enhancement

aureliaInstance.enhance(
  {
    iconHref: 'https://aurelia.io/media/aurelia-favicon.ico'
  },
  document.head
)
7 Likes

I like it a lot. It’s not super intuitive on its own because it just kinda says “this” and “document.head” but it’s all connected to each other cleanly and super quick which is nice. Guess it can’t be any clearer than that in a way since it’s a view model.

1 Like

Nice example, but best to avoid “magic” in your example solutions, as it causes confusion.
For example <link rel="icon" href.bind="iconHref"> is great, but it’s unclear where iconHref comes from as it’s not a field in the viewmodel and is only declared in a view.
I like seeing views at least pretending to be type-safe in the same way as models :slight_smile:

4 Likes

This works, but could you elaborate on how you would include resources? I’m struggling to provide a value converter to a binding expression I’m declaring on my body tag, I tried the following:

let resources = await this.viewEngine.importViewResources(
      ["./resources/value-converters/module-id-to-class"],
		["module-id-to-class"],
      this.aurelia.resources,
	);
	  this.templatingEngine.enhance({
		  element: document.body,
		  bindingContext: this,
		  resources: resources
	  })

But this errors out:

aurelia-templating.js:2422 Uncaught (in promise) TypeError: Cannot read property 'behaviorInstructions' of undefined
    at applyInstructions (aurelia-templating.js:2422)
    at ViewFactory.create (aurelia-templating.js:2691)
    at TemplatingEngine.enhance (aurelia-templating.js:5227)
    at App.<anonymous> (app.ts:67)
    at step (app-bundle.js:40)
    at Object.next (app-bundle.js:21)
    at fulfilled (app-bundle.js:12)
1 Like

The error you got seems more like an issue with re-enhancing already enhanced element. Can you check that? I suspected that since you are enhancing document.body

You are correct, enhancing document.head like this works and resolves my value converter just fine.
So I’m guessing this is because the enhancing process processes the entire DOM subtree and a big chuck of that is already enhanced?
Is there a way to tell the enhancing process to enhance just the element provided and not the children?
(I basically want to bind a css class to my body element for styling purposes, the class would change depending on the active route, so document.head isn’t an option for me)

1 Like

Unfortunately no, there’s no easy/performant way to avoid already enhanced DOM nodes. You can have a look at more details here https://github.com/aurelia/templating/issues/654

Thank you for the link, interesting stuff!
I’ll resort to just using old fashioned DOM manipulation in this case, rebinding the entire app seems overkill for this scenario

1 Like