appending to the start of a container

Discuss how to use and promote Web standards with the Mozilla Gecko engine.
Post Reply
Bethrezen
Posts: 445
Joined: September 13th, 2003, 11:56 am

appending to the start of a container

Post by Bethrezen »

Quick question how do you append to the start of a container?

Now at first this might appear to be simple task but unfortunately it isn’t nearly so simple as it appears, so what the problem

Ok so say I have a div and I want to insert some content to the start of that div, say 3 paragraphs of text for example now your first though might be to do something like this

Code: Select all

document.querySelector('div').insertAdjacentHTML("afterbegin", content);
document.querySelector('div').prepend(content);
Trouble is both give the wrong output so instead of

<div>
paragraphs 1
paragraphs 2
paragraphs 3
pre-existing content
</div>

What you actually get is

<div>
paragraphs 3
paragraphs 2
paragraphs 1
pre-existing content
</div>

So I’m sure you can see how in this example that would be a big problem, because order in for the text to make sense each paragraph must be inserted in the correct order.

Now of course the content doesn’t have to be paragraphs of text the content could be anything I’m just using paragraphs of text to try and illustrate the problem more clearly.

So as you can see although this seems like a simple task its anything but because I need to so 2 entirely opposite things at the same time aka I need to insert content at the start of an element but each inserted item must be inserted after the previous one so when I’m inserting content from a loop I end up with the expected output.

In the case of the example above the expected out put would be

<div>
paragraphs 1
paragraphs 2
paragraphs 3
pre-existing content
</div>

I also tried using the .reverse() method but to no avail so I'm not sure if it just doesn't work for what I'm trying to do or if I'm just going about it the wrong way

when I ran

Code: Select all

Object.keys(name_of_object).reverse()
in the console it did seem to reverse the order of the content of the object but when I tried to output the code to the page like so

Code: Select all

var key = Object.keys(icons).reverse()

function style(key)
{
  var css = `
  #top:checked ~ img#${key} 
  {
  top:${Math.round(calculate(key).z) + 'px'};
  left:${Math.round(calculate(key).x) + 'px'};
  }
  `;

  document.querySelector("style").insertAdjacentHTML("afterbegin", css.replace(/^\s+/gm, '') + "\n")
}
the code was still being inserted in the wrong order, which came as something of a surprise because I would have though that reversing the order of the objects content would make the insertion would work correctly as it would be inserting the last entry first and the first entry last thus the code would appear in the correct order in the page.

So that one has me scratching my head and I really don't understand why that's not working as expected, hence the question.
Bethrezen
Posts: 445
Joined: September 13th, 2003, 11:56 am

Re: appending to the start of a container

Post by Bethrezen »

ok so after playing around a bit more I think I have discovered what I was doing wrong.

so for the benefit of anyone else that wants to do something similar here is what I came up with

Code: Select all

var reverse_keys = Object.keys(icons).reverse(); 
var reverse_values = Object.values(icons).reverse();

function calculate(key)
{
  var x = (((reverse_values[key]['x'] / 222 - 1700) / 51000) + 1) / 2 * 513;
  var y = (((-reverse_values[key]['y'] / 222 + 3000) / 51100) + 1) / 2 * 513;
  var z = (((-reverse_values[key]['z'] / 222 + 3000) / 51100) + 1) / 2 * 513;

  return {x, y, z} 
}

for (var key in reverse_keys)
{
  var css = `
  #top:checked ~ img#${reverse_keys[key]} 
  {
  top:${Math.round(calculate(key).z) + 'px'};
  left:${Math.round(calculate(key).x) + 'px'};
  }
  `;

  document.querySelector("style").prepend(css.replace(/^\s+/gm, '') + "\n");
}
this will insert the css to the start of the style element but will do so forwards instead of backwards, I'll admit this is a bit of a kludge and really what is needed here is a proper native function, but it does work.

if you want to insert something other then css say a bunch of images for example then all you need to is change the bit inside the for loop accordingly for example

Code: Select all

var reverse_keys = Object.keys(name of object).reverse();

for (var key in reverse_keys)
{
  var html = `<img src="images/${reverse_keys[key]}.png" alt="${reverse_keys[key]} Icon">
  `;

  document.querySelector('div').insertAdjacentHTML("afterbegin", html);
}
by default when pre-pending to the start of an element .insertAdjacentHTML() will insert the images in reverse order aka

<img src="images/image3.png" alt="image3">
<img src="images/image2.png" alt="image2">
<img src="images/image1.png" alt="image1">

however by getting the keys and then reversing the order and then pre-pending when you look at the source they will be inserted forwards instead of backwards aka

<img src="images/image1.png" alt="image1">
<img src="images/image2.png" alt="image2">
<img src="images/image3.png" alt="image3">

again this is a bit of a kludge and what is really need here is a proper native function for inserting content into a page perhaps something like this

Code: Select all

.insert("content", prepend/append, before/after)
so to achieve the above affect you would do

Code: Select all

for (var key in object)
{
  var html = `<img src="images/${key}.png" alt="${key} Icon">
  `;

  document.querySelector('div').insert(html, prepend, after);
}
which frankly would be a lot simpler and a lot less messing about if you where simply able to specify a couple of parameters to tell it where and how to insert the content.

Question: do you think it would be possible to build a custom function to do this?

I came across http://prototypejs.org/doc/latest/language/String/ which is similar but as far as I can tell that isn't native JavaScript and so wont work unless you are using the prototypejs library.

so its not really much use to me though it could perhaps provide some insight in to how they implement the insert function and therefore how to replicate it with native JavaScript so that you could use the insert function without the prototypejs library.

its a shame that the people who designed JavaScript didn't think to give developers a choice when implementing things like prepend /append or toPrecision / toFixed so that developers have more fine grained control without all the extra messing about that usually results from not being given a choice.

for example
element.prepend(content, before/after);
element.append(content, before/after);

when inserting more then 1 element the before/after perimeters would control whither the next element to be inserted would be inserted before or after the previous one

so if for example you where prepending /appending multiple images the before/after perimeters would control whither image 2 could be inserted before image 1 or after image 1 thus allowing you to avoid a whole lot of unnecessary messing about.

number.toPrecision(precision, up, down, none);
number.toFixed(precision, up, down, none);

precision would control the number of decimal places/significant digits the up, down, none perimeters would control the direction of rounding or would turn rounding off all together

well who knows maybe this will spark an idea in someone at some point and at some time in the future oversights like this will be corrected.
Post Reply