0

I am trying to figure out how to have a <div/> automatically reposition itself based upon the current date. Basically, the <div/> to be moved contains an <hr/> line that separates 'past' and 'future' items in a list, the items of which are identified by a date (YYMMDD). Here is what I mean:

<head>
<!-- FIRST, SET DATE (YYMMDD) AS ID FOR DIV 'TIMELINE' -->
<script>
var today = new Date();
var dd = today.getDate();
var mm = today.getMonth()+1; //January is 0!
var yy=today.getFullYear().toString().substr(2, 2);

if(dd<10) { 
    dd='0'+dd
} 

if(mm<10) {
    mm='0'+mm
} 
today = yy+mm+dd;

var element = document.getElementById("timeline");
element.setAttribute("data_date", today);

</script>


<!-- NEXT, MOVE 'TIMELINE' DYNAMICALLY SO THAT IT POSITIONS ITSELF IN-BETWEEN PAST & FUTURE EVENTS -->
<script type="text/javascript">
function sortdiv() {
var container = document.getElementById("content");
var elements = container.childNodes;
var sortMe = [];
for (var i=0; i<elements.length; i++) {
    if (!elements[i].id) {
        continue;
    }
    var sortPart = elements[i].id.split("-");
     if (sortPart.length > 1) {
        sortMe.push([ 1 * sortPart[1] , elements[i] ]);
    }
}
 sortMe.sort(function(x, y) {
    return y[0] - x[0];
});
for (var i=0; i<sortMe.length; i++) {
    container.appendChild(sortMe[i][1]);
}
document.getElementById("button").innerHTML = "done.";
}
</script>
</head>

<div id="content">
<div id="button"><a href="#" onclick="sortdiv();">sort!</a></div>
<!-- RIGHT NOW I HAVE A BUTTON TO TRIGGER THE FUNCTION FOR TESTING, BUT THIS WILL CHANGE TO AN ONLOAD WHEN IT WORKS -->
<div id="timeline">
    <HR align="left">
    <HR align="left">
</div>

<div class="date" data_date="170206">SOME CONTENT</DIV>
<div class="date" data_date="161011">SOME MORE CONTENT</DIV>
<div class="date" data_date="160915">EVEN MORE CONTENT</DIV>
ssc-hrep3
  • 15,024
  • 7
  • 48
  • 87
Paul Clift
  • 169
  • 8
  • 1
    changing id is not a good idea. Try keeping `data-*` attributes and update them. – Iceman Aug 14 '16 at 07:46
  • I'm also open to that idea! But I am something of a beginner with javascript. Could you help me a little with this? If you, or someone, can get me started, I can probably manage the rest on my own. – Paul Clift Aug 14 '16 at 07:47
  • Thanks for the edit fix! I haven't been on this site for a while and managed to mess up the formatting of my post.... – Paul Clift Aug 14 '16 at 07:49
  • You probably want to start by giving all your date divs a class so they can be manipulated more easily (`document.getElementsByClassName`). If you then use @Iceman's suggestion of adding a date `data-*` attribute you should be able to easily write a function that finds the first div that has a `data-date` your target date is greater than or equal to. – Tibrogargan Aug 14 '16 at 07:51
  • @PaulClift do you want a vanilla javascript soln or is jquery ok? – Iceman Aug 14 '16 at 07:53
  • I added a 'class="date"' to each relevant div and switched the 'id="xxx"' for 'data-date="yymmdd"' ...... – Paul Clift Aug 14 '16 at 07:55
  • I would prefer pure javascript - up to now my whole site is built that way, without jquery. – Paul Clift Aug 14 '16 at 07:56
  • BUT if there is a good reason for adding jquery, then sure - no problem. – Paul Clift Aug 14 '16 at 07:56
  • jQuery is big. If you're going to do it, you want to convert a bunch of stuff to use it so you're making good use of it. BTW. Once you have found the correct div, moving your line is easy enough using `element.appendChild` – Tibrogargan Aug 14 '16 at 08:01
  • @Tibrogargan: yeah, I agree... that's why I am trying to avoid it. It seems like bad coding practice to just use it for something small that could be done with good old javascript. – Paul Clift Aug 14 '16 at 08:05
  • @PaulClift: If you're keen on learning good coding practice, try storing your data in an array, and then updating the DOM whenever you change. Storing app data in the DOM will lead you to a lot of pain later as your app gets more complex, both keeping things in sync between and with regards to performance. – Jim O'Brien Aug 14 '16 at 08:16
  • @Jim O'Brien Thanks for the advice! I know that this is far better coding practice, but it is tricky for a beginner like me. – Paul Clift Aug 14 '16 at 08:19
  • @PaulClift because this is out of scope of the question, I've popped up [an example of how I would do this in pure JS](https://jsfiddle.net/eutLgfca/10/). I hope this is helpful -- if you have any questions just shout. – Jim O'Brien Aug 14 '16 at 08:59
  • @Jim O'Brien this is really elegant and beautiful code! The only problem I have with it is that the text items require a fair bit of formatting, and I always try to avoid doing lots of text style stuff in JS. – Paul Clift Aug 14 '16 at 09:03
  • Text formatting is never a pleasant task! In the example I've given, however, you could perform all of that in the `formatItem` function, so it keeps your rendering code super clean (and only deals with rendering, not formatting!). – Jim O'Brien Aug 14 '16 at 09:07
  • 1
    @Jim O'Brien Thanks a million for all of this. I'm going to slowly work on switching all my awful, patched-together JS into array storage as you suggest. I guess that I have put off learning this stuff properly for long enough. – Paul Clift Aug 14 '16 at 09:18
  • No worries, I'm happy to help :) Reply here if you need any more help, and we can take this to a better discussion medium – Jim O'Brien Aug 14 '16 at 09:19

1 Answers1

1

Decided to just do a snippet. There's some possible javascript issues with the posted code that may be causing problems

var today = new Date();
var dd = today.getDate();
var mm = today.getMonth()+1; //January is 0!
var yy=today.getFullYear().toString().substr(2, 2);

if(dd<10) {
    dd='0'+dd
}

if(mm<10) {
    mm='0'+mm
}
today = yy+mm+dd;

function sortdiv() {
    var container = document.getElementById("content");
    var elements = container.childNodes;
    var sortMe = [];
    for (var i=0; i<elements.length; i++) {
        if (!elements[i].id) {
            continue;
        }
        var sortPart = elements[i].id.split("-");
        if (sortPart.length > 1) {
            sortMe.push([ 1 * sortPart[1] , elements[i] ]);
        }
    }
    sortMe.sort(function(x, y) {
        return y[0] - x[0];
    });
    for (var i=0; i<sortMe.length; i++) {
        container.appendChild(sortMe[i][1]);
    }
    document.getElementById("button").innerHTML = "done.";
}

// insertAfter is from karim79's answer to http://stackoverflow.com/questions/4793604/how-to-do-insert-after-in-javascript-without-using-a-library
function insertAfter(newNode, referenceNode) {
    referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}

function moveLine() {
    var timeline = document.getElementById("timeline");
    var timelineDate = parseInt(timeline.dataset.date);
    var divs = document.getElementsByClassName('date');
    var moveTo = null;
    for (var i = 0; i < divs.length; i++) {
        if (timelineDate < parseInt(divs[i].dataset.date)) {
            moveTo = divs[i];
        } else {
            break;
        }
    }
    if (moveTo) {
        timeline.parentNode.removeChild(timeline);
        insertAfter(timeline, moveTo);
    } else {
        timeline.parentNode.removeChild(timeline);
        divs[0].parentNode.insertBefore(timeline, divs[0]);
    }
}

function init() {
    var element = document.getElementById("timeline");
    element.setAttribute("data-date", today);
    document.getElementById("moveLine").addEventListener("click", moveLine, false );
}

document.addEventListener( "DOMContentLoaded", init, false );
<body>
<div id="content">
    <input id="moveLine" type="button">
    <div id="button"><a href="#" onclick="sortdiv();">sort!</a></div> <!--RIGHT NOW I HAVE A BUTTON TO TRIGGER THE FUNCTION FOR TESTING, BUT THIS WILL CHANGE TO AN ONLOAD WHEN IT WORKS-->
    <div id="timeline">
        <HR align="left">
        <HR align="left">
    </div>
    <div class="date" data-date="170206">SOME CONTENT</DIV>
    <div class="date" data-date="161011">SOME MORE CONTENT</DIV>
    <div class="date" data-date="160915">EVEN MORE CONTENT</DIV>
    <div class="date" data-date="160804">EVEN MORE CONTENT</DIV>
</div>
</body>
Tibrogargan
  • 4,508
  • 3
  • 19
  • 38
  • Yes, I guess that there is no reason to use two-digit values for the year.... I just had it like that from the beginning. – Paul Clift Aug 14 '16 at 08:23
  • THANKS! The only part of that which I do not understand is the first bit: function insertAfter(newNode, referenceNode) { referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); } – Paul Clift Aug 14 '16 at 08:26
  • Elements in the DOM that belong to the same parent are like array elements. There's a function in javascript to insert something *before* an element, but no native function to insert after. The `insertAfter` function uses the nextSibling property of the target element to find the correct element to insertBefore. If that's null, it will insert at the end of the children array - which is what you want. Imagine: [A, B, C]. To insert after A you must insert before B – Tibrogargan Aug 14 '16 at 08:31
  • ah, I see - thank you for the explanation. I hate to be so dense but I am still having a little trouble with the implementation of this. I changed the code and am triggering moveLine() with a button, but nothing happens. – Paul Clift Aug 14 '16 at 08:35
  • Try `data-date` not `data_date` – Tibrogargan Aug 14 '16 at 08:35
  • Change made! But do I need to trigger the first function, 'insertAfter()' somehow? Again, please forgive my lack of knowledge. – Paul Clift Aug 14 '16 at 08:45
  • No, it's being called from `moveLine()` – Tibrogargan Aug 14 '16 at 08:45
  • So then this action in the body should move the 'timeline', right? – Paul Clift Aug 14 '16 at 08:50
  • The relevant page is online here, by the way: http://www.paulclift.net/news_TEMP.html – Paul Clift Aug 14 '16 at 08:58
  • Just noticed your dates are descending. My bad. Will update the answer – Tibrogargan Aug 14 '16 at 09:03
  • Hmm, still no movement here. I understand pretty much everything you put in your code and can't see why it is not having any effect on the page. – Paul Clift Aug 14 '16 at 09:15
  • I think maybe there's other issues in your code. Are you running in a debugger? I've done a snippet that's working. – Tibrogargan Aug 14 '16 at 09:25
  • Got it! I just switched the trigger to a and it's all working beautifully. THANK YOU THANK YOU THANK YOU – Paul Clift Aug 14 '16 at 09:28
  • Using is frowned upon. General consensus is to attach an onload handler to the document. I've done this in the snippet (`document.addEventListener( "DOMContentLoaded", init, false );`) You can see in there where I also attach an event listener to the `moveLine` button. You could just call `moveLine` instead of attaching the click handler – Tibrogargan Aug 14 '16 at 09:45
  • Got it! Since I'm rather new to JS, I probably am doing all sorts of things which are considered poor practice by the professionals. – Paul Clift Aug 14 '16 at 10:28