1

I'm asynchronously rendering a template serverside with rapscallion in node. At the point of rendering the body, I have a string (containing line breaks) that needs to be inserted in the document head:

// this is what I have serverside
var stylestring = `<style type="text/css" data-style="some-id-that needs to be preserved">
.lfwARz {
  margin-bottom: 0;
  margin-top: 0;
}
</style>`

Since at that point I've already sent the <head> to the client, I need to insert a script that sets these styles to the head clientside. But I'm having trouble getting this to work.

This approach works:

// gets run clientside
<script>
  var style = document.createElement('style')
  style.type = 'text/css'
  style.innerHTML = '${() => sheet.getStyleTags().replace(/(\r\n|\n|\r)/gm, '').replace(/<\/?style.*?>/g, '')}'
  document.head.appendChild(style)
</script>

But it results in a loss of the data attribute (which I need to preserve so the styles won't get rerendered on the client).

  • How are you rendering the template exactly? – Halcyon May 06 '17 at 14:57
  • @Halcyon I'm using node and [rapscallion](https://github.com/FormidableLabs/rapscallion). What I'm doing is basically this: https://github.com/FormidableLabs/rapscallion#example –  May 06 '17 at 14:57
  • Can you do something like `document.head.appendChild(style_element)`? – Halcyon May 06 '17 at 14:58
  • @Halcyon No, because it is not a valid dom element yet. I only have a string with `' –  May 06 '17 at 15:01
  • @Halcyon So if I do `document.head.appendChild(style_string)` I get `Uncaught SyntaxError: Unexpected token <` –  May 06 '17 at 15:02

1 Answers1

2

Use document.createElement('div') then insert the string to it, get the DOM from that fragment so that it can be inserted to the <head> using appendChild:

var fragment = document.createElement('div');
// remove newlines from the string and insert it in the fragment
fragment.innerHTML = the_style_string.replace(/(\r\n|\n|\r)/gm, '');
document.head.appendChild(fragment.firstChild);
Taufik Nurrohman
  • 3,329
  • 24
  • 39
  • Thanks for your answer, but the string already contains the style tags though. So this won't work. I'd rather parse it to an element directly, if that's possible. –  May 06 '17 at 15:03
  • try this: `document.head.innerHTML = document.head.innerHTML + ' – maioman May 06 '17 at 15:06
  • @vsjn3290ckjnaoij2jikndckjb Updated the answer. – Taufik Nurrohman May 06 '17 at 15:07
  • I've tested your answer. It fails with: `Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.` –  May 06 '17 at 15:10
  • Then, I would simply set a hard-coded ` – Taufik Nurrohman May 06 '17 at 15:13
  • @TaufikNurrohman Problem is, there are some data-attributes on the style tag that I need to preserve. Otherwise the styles will be rerendered on the client. So removing the outer style tags would also result in me losing those data attributes. Otherwise, your approach would work.. –  May 06 '17 at 15:21
  • Ah, so using your `document.createElement('div')` approach works. The `document.createDocumentFragment();` approach doesn't (as said it fails with `Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.`). The one thing that I needed to add serverside is `.replace(/(\r\n|\n|\r)/gm, '')`, to replace the newlines in the string. –  May 06 '17 at 15:35