Rerun JS functions with button onclick

Waubain

New Member
I have a student simulation that has about 100 embedded dates in a text file. The dates are choreographed back in time from the date of the simulation. Each year I have to redo all the dates to match the date of the simulation before printing it out

I am trying to create a html file to run in my browser to recalculate all the dates based on the Activity Date in a textbox. Based on what I have found on the web I can calculate the days until the activity. I cannot figure out how to make the dates recalculate when the Recalculate Date button is clicked.

I just read that document.write only works when the form is loaded. I cannot find how to rewrite this so all the dates recalculate based on the textbox.

Here is what I have. Any help would be appreciated.

Code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

<head>
	<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
	<meta name="author" content="Robert Shaw" />

	<title>Print Chart Test</title>
</head>

<script type="text/javascript">
    function GetDaysToActivity() //calculates number of days until the Activity date
    {
        var dob1 = document.getElementById("activitydate");
        var age1 = document.getElementById("daystoactivity");
        var ms = 86400000
        var dateAry = dob1.value.split("/");
        var birthMonth = parseInt(dateAry[0]);
        var birthDay = parseInt(dateAry[1]);
        var birthYear = parseInt(dateAry[2]);
        var birthDate = new Date(birthYear, birthMonth - 1, birthDay);
        var currentDate = new Date();
        var age = birthDate - currentDate;  // result is number of milliseconds difference
        var mtg = age/ms;
            mtg = Math.ceil(mtg);

            if(birthDate < currentDate) {
                alert("Activity date cannot be in the past");
                document.getElementById("activitydate").value ="";
                document.printchart.activitydate.focus();
                }
                else {
                    age1.value = mtg;
                }
    }
</script>

<script type="text/javascript">
    function ActivityDate(x) //calculates the dates in the text
    {
        var date = new Date();     
        var ms = 86400000 
        var mtg = document.getElementById("daystoactivity").value;
        if (mtg < 1){
            mtg = 0
            };
        var daysback = x - mtg;
        var nd = date - (daysback * ms);
        nd = new Date(nd);
        var curr_day = ("0" + nd.getDate()).slice(-2);
        var curr_month = ("0" + (nd.getMonth() + 1)).slice(-2);
        var curr_year = nd.getFullYear();
        return curr_month + "/" + curr_day + "/" + curr_year;
        }
</script>

</head>

<body>

<div><form name="printchart">
<label>Future date of activity (mm/dd/yyyy): &nbsp;</label>
    <input type="text" id="activitydate"name="activitydate" onblur="GetDaysToActivity()"/>
    <script>document.printchart.activitydate.focus();</script>
    <!--<input type="hidden" id="daystoactivity" name="daystoactivity" style="display: none;" /> -->
    <input type="text" id="daystoactivity" name="daystoactivity" />
    <input type="button" value="Recalculate Dates" onclick='DateActivity()' />
    &nbsp;
    <input type="button" value="Print Chart" onclick="" />
    </div>
    <br />
    <br />
    <div>Activity Date = Today: <script>document.write(ActivityDate(0.0000001));</script> (This should be the same as the Activity Date)<br />

    <br />
    Activity Date = Yesterday: <script>document.write(ActivityDate(1));</script> (This should be the same as the Activity Date - 1)<br />
    <br />
    Activity Date = 30 days ago: <script>document.write(ActivityDate(30));</script><br />
</div>

</body>
</html>
 

chrishirst

Well-Known Member
Staff member
<button onclick="Put_the_Function_Here()" .... >


document.write runs whenever your script tells it to run.
 

Waubain

New Member
That is how I have it set up (spelling error corrected) but the dates do not update. The dates are calculated when the page is loaded based on the fact that the textbox is null. After I populate the textbox with a different function I want to be able to rerun the ActivityDate(x) functions located in the body of the page.

If I use <button onclick="ActivityDate()">Recalculate Dates</button>
I do not see how that reruns the functions since it is looking for a value.

<body>
Activity Date = 30 days ago: <script>document.write(ActivityDate(30));</script><br />
</body>
 

chrishirst

Well-Known Member
Staff member
After I populate the textbox with a different function

Then call your update routine when your "different function" finishes.

By the way;
The "document.write" operations DO need to be INCLUDED in your update routine to actually 'print' the new values to the elements.
 

Waubain

New Member
Thank you for the direction.

By the way;
The "document.write" operations DO need to be INCLUDED in your update routine to actually 'print' the new values to the elements.

I am not quite sure about this comment about adding the document.write statements in the function. I cannot find any examples so the js function is beyond my novice capabilities.

Possibly not the best solution, but I ended up writing 5 different functions, one for each date back in time. I use one function tied to the onclick button for recalculating dates to run all the functions. I used the GetElementID('each date id').innerHTML to switch out the new calculated dates.

Thanks again.
 

Iconiplex

New Member
With only one additional function and some additional HTML elements, the code I've included will work fine.

I've included <span> tags with ID attributes around your initial date outputs in order to identify their location in the DOM.

I added the function updateDates (run on button click) that retrieves the day offset in the daystoactivity input, calculates the new ActivityDate inputs by subtracting the offset from the initial inputs (0.0000001, 1, 30), and outputting the ActivityDate return value to the span fields.

HTML:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

<head>
	<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
	<meta name="author" content="Robert Shaw" />

	<title>Print Chart Test</title>
</head>

<script type="text/javascript">
    function GetDaysToActivity() //calculates number of days until the Activity date
    {
        var dob1 = document.getElementById("activitydate");
        var age1 = document.getElementById("daystoactivity");
        var ms = 86400000
        var dateAry = dob1.value.split("/");
        var birthMonth = parseInt(dateAry[0]);
        var birthDay = parseInt(dateAry[1]);
        var birthYear = parseInt(dateAry[2]);
        var birthDate = new Date(birthYear, birthMonth - 1, birthDay);
        var currentDate = new Date();
        var age = birthDate - currentDate;  // result is number of milliseconds difference
        var mtg = age/ms;
            mtg = Math.ceil(mtg);

            if(birthDate < currentDate) {
                alert("Activity date cannot be in the past");
                document.getElementById("activitydate").value ="";
                document.printchart.activitydate.focus();
                }
                else {
                    age1.value = mtg;
                }
    }
</script>

<script type="text/javascript">
	function updateDates() {
		var daysToActivity = document.getElementById("daystoactivity").innerHTML;
		var todayInput = 0.0000001 - daysToActivity;
		var yesterdayInput = 1 - daysToActivity;
		var thirtyDayInput = 30 - daysToActivity;
		
		document.getElementById("todayfield").innerHTML = ActivityDate(todayInput);
		document.getElementById("yesterdayfield").innerHTML = ActivityDate(yesterdayInput);
		document.getElementById("30dayfield").innerHTML = ActivityDate(thirtyDayInput);
	}

    function ActivityDate(x) //calculates the dates in the text
    {
        var date = new Date();     
        var ms = 86400000 
        var mtg = document.getElementById("daystoactivity").value;
        if (mtg < 1){
            mtg = 0
            };
        var daysback = x - mtg;
        var nd = date - (daysback * ms);
        nd = new Date(nd);
        var curr_day = ("0" + nd.getDate()).slice(-2);
        var curr_month = ("0" + (nd.getMonth() + 1)).slice(-2);
        var curr_year = nd.getFullYear();
        return curr_month + "/" + curr_day + "/" + curr_year;
        }
</script>

</head>

<body>

<div><form name="printchart">
<label>Future date of activity (mm/dd/yyyy): &nbsp;</label>
    <input type="text" id="activitydate"name="activitydate" onblur="GetDaysToActivity()"/>
    <script>document.printchart.activitydate.focus();</script>
    <!--<input type="hidden" id="daystoactivity" name="daystoactivity" style="display: none;" /> -->
    <input type="text" id="daystoactivity" name="daystoactivity" />
    <input type="button" value="Recalculate Dates" onclick='updateDates()' />
    &nbsp;
    <input type="button" value="Print Chart" onclick="" />
    </div>
    <br />
    <br />
    <div>Activity Date = Today: <span id="todayfield"><script>document.write(ActivityDate(0.0000001));</script></span> (This should be the same as the Activity Date)<br />

    <br />
    Activity Date = Yesterday: <span id="yesterdayfield"><script>document.write(ActivityDate(1));</script></span> (This should be the same as the Activity Date - 1)<br />
    <br />
    Activity Date = 30 days ago: <span id="30dayfield"><script>document.write(ActivityDate(30));</script></span><br />
</div>

</body>
</html>
 

chrishirst

Well-Known Member
Staff member
I've included <span> tags with ID attributes around your initial date outputs in order to identify their location in the DOM.
Why? They are already div elements (block level), whereas a span is an inline level element.

Just in case you hadn't noticed, here we work on the "teach someone to fish" principle rather them relying on us to give them a fish occasionally.

Which means we offer pointers and advice on HOW TO SOLVE THE PROBLEM for themselves, not simply give them a ready made solution and make them dependant on others for future solutions.
 

Iconiplex

New Member
Why? They are already div elements (block level), whereas a span is an inline level element.

Just in case you hadn't noticed, here we work on the "teach someone to fish" principle rather them relying on us to give them a fish occasionally.

Which means we offer pointers and advice on HOW TO SOLVE THE PROBLEM for themselves, not simply give them a ready made solution and make them dependant on others for future solutions.
Lol why? With only the <div> element, this is what the date container would work out to in HTML (without the line break elements, etc.):

HTML:
<div>
    Activity Date = Today: (some-date-here) (This should be the same as the Activity Date)
    Activity Date = Yesterday: (another-date-here) (This should be the same as the Activity Date - 1)
    Activity Date = 30 days ago: (last-date-here)
</div>

Now, he wants to update those dates that I marked in parentheses. Using your suggestion and wondering cluelessly why I've added <span> elements, I could parse that whole <div>, try to find the date I need, then update it accordingly, which would take a ton more code and execution time than is needed.

Or, I can put <span> elements around the dates so that they are readily accessible by getElementById or jQuery if so desired, then their HTML can be updated very quickly rather than only having the <div> and trying to parse each piece of it to update the dates he needs.

Or he could keep the <div>, drop the <span>s, and rewrite the entire <div> on each update starting from "Activity Date..." on to "(last-date-here)" which would be equally moronic.

If you actually operated on your suggested ideology, I'd be happy to agree with that. However, I have looked through your post history and the history of many other members, and your condescending yet completely non-contributing demeanor rather infuriates me to the point where I'd rather give users the answers directly rather than have them rely on this joke of a community for help they will never receive.
 

chrishirst

Well-Known Member
Staff member
Or he could keep the <div>, drop the <span>s, and rewrite the entire <div> on each update starting from "Activity Date..." on to "(last-date-here)" which would be equally moronic.
If it was a continual process, a clock or other counter, yes it would be inefficient, but as it is a single write, creating a string and pushing that to a single element it less resource intensive than updating two or more independant elements.
 

Iconiplex

New Member
If it was a continual process, a clock or other counter, yes it would be inefficient, but as it is a single write, creating a string and pushing that to a single element it less resource intensive than updating two or more independant elements.

I see. And since OP pointed out that this will be, in fact, a continual process, let's go ahead and replicate this to see which has better efficiency in the long-run (since execution time is essentially identical and asymptotic to 0 on a single run of your method or mine). Both functions run 1000 times in an embedded loop for a better estimate of efficiency.

Your Suggestion
Code:
function updateDates() {
	var startTime = performance.now();
	
	for (i = 0; i < 1000; i++) {
		var daysToActivity = document.getElementById("daystoactivity").innerHTML;
		var todayInput = 0.0000001 - daysToActivity;
		var yesterdayInput = 1 - daysToActivity;
		var thirtyDayInput = 30 - daysToActivity;
		
		document.getElementById("ActivityResult").innerHTML = "Activity Date = Today: " + ActivityDate(todayInput) + " (This should be the same as the Activity Date)<br><br>" + 
			"Activity Date = Yesterday: " + ActivityDate(yesterdayInput) + " (This should be the same as the Activity Date - 1)<br><br>" + 
			"Activity Date = 30 days ago: " + ActivityDate(thirtyDayInput);
	}
	
	var endTime = performance.now();
	var totalTime = endTime - startTime;
	document.getElementById("executionTime").innerHTML = totalTime;
}

Execution Times in Milliseconds
20.00000001862645
25.000000023283064
23.999999975785613
22.99999992828816
26.000000070780516
25.000000023283064
23.999999975785613
22.99999992828816
24.000000092200935
23.999999975785613

Mean: 23.8000000012107
Median: 23.9999999757856

My Suggestion
Code:
function updateDates() {
	var startTime = performance.now();
	
	for (i = 0; i < 1000; i++) {
		var daysToActivity = document.getElementById("daystoactivity").innerHTML;
		var todayInput = 0.0000001 - daysToActivity;
		var yesterdayInput = 1 - daysToActivity;
		var thirtyDayInput = 30 - daysToActivity;
		
		document.getElementById("todayfield").innerHTML = ActivityDate(todayInput);
		document.getElementById("yesterdayfield").innerHTML = ActivityDate(yesterdayInput);
		document.getElementById("30dayfield").innerHTML = ActivityDate(thirtyDayInput);
	}
	
	var endTime = performance.now();
	var totalTime = endTime - startTime;
	document.getElementById("executionTime").innerHTML = totalTime;
}

Execution Times in Milliseconds
18.00000004004687
16.99999999254942
18.00000004004687
17.99999992363155
16.99999999254942
17.00000010896474
16.99999999254942
17.99999992363155
16.99999999254942
17.99999992363155

Mean: 17.499999993015
Median: 17.5000000162981

So not only does my solution provide cleaner, more logical code with more structurally-sound HTML that doesn't require double-maintenance when modifying the output (which is reason in itself to use it), it provides 26.47% to 27.08% (mean and median comparison) faster execution time. It should be noted that the benchmark does rely on the execution speed of ActivityDate(), and the test case could be rewritten to avoid this dependence, but the significant difference in execution times yields itself to the fact that this is a result of the HTML output method used.

Do tell me again why your solution should be implemented... I'm not sure why you would ever suggest implementing code that you admit would eventually be inefficient, when a code that takes negligibly more time to write adheres to better coding practices. Granted, my code is probably not the fastest form available either (I could have avoided three variable assignments, etc.), but it's wrong from a programming responsibility standpoint to suggest using whatever code you feel like just because the efficiency doesn't matter to you.
 
Last edited:

chrishirst

Well-Known Member
Staff member
in fact, a continual process,

Yes but NOT a process that RUNS continously while the document is open. The original code in the first post only runs ONCE when the document is first loaded.

The phrase "continual process" in this context, is with respect to a 'one off' action that needs to be performed at certain intervals, rather than a continuous process.
 

Iconiplex

New Member
Yes but NOT a process that RUNS continously while the document is open. The original code in the first post only runs ONCE when the document is first loaded.

The phrase "continual process" in this context, is with respect to a 'one off' action that needs to be performed at certain intervals, rather than a continuous process.
OP said he had a document with 100 dates. It can be assumed that, at one point or another, he will somehow loop through these dates - it may be only one-at-a-time with button click as you suggest, or he may opt to loop through them or even process them asynchronously.

Given that, it is always best to implement the most efficient and responsible code. Just because it doesn't make a "difference" during a one-off comparison doesn't mean the implementation doesn't matter. Your suggestion is akin to putting donut spare tires on a car when you drive short distances because they are capable of getting you there, whereas that is the most moronic and irresponsible thing someone could do even if it will get the job done.
 

chrishirst

Well-Known Member
Staff member
Your suggestion is akin to putting donut spare tires on a car when you drive short distances

Not really, my approach to coding has always been a "least cost code" route. Concatenating a string and writing to a single element is far less memory intensive than creating uneccesary extra elements and object references, then having to write out several values.
 
Top