Update a global variable from a function - javascript

I have 2 variables which are concatenated into another variable. On the click of a button the values of the variables should update and also the concatenated variable, but the global variable is keeping the original value.
<button class="filter period" data-sort-value="number" data-period="ltd">LTD</button>
<button class="filter period" data-sort-value="number" data-period="r3">R+3</button>
<button class="filter period" data-sort-value="number" data-period="r12">R+12</button>
<button class="filter period" data-sort-value="number" data-period="rtodec">RTODEC</button>
<script>
var region = "ww";
var period = "ltd";
var finalFilter = "data-" + region + "-" + period;
$('button.filter').on('click', function () {
if ( $(this).hasClass("period") ) {
period = $(this).attr('data-period');
console.log(finalFilter);
console.log(period);
updatedFinalFilter();
}
});
</script>

Yes, i want that finalFilter to be update automatically when one of period or region change value
The only way to make that happen is to actually update it. Variables in JavaScript don't update automatically based on the expression you used to set them the first time. After:
var finalFilter = "data-" + region + "-" + period;
has run, finalFilter is purely set to "data-ww-ltd" - it has no knowledge of or link to region or period.
So before you call updatedFinalFilter(), you'd have to re-evaluate the expression:
var region = "ww";
var period = "ltd";
var finalFilter = "data-" + region + "-" + period;
$('button.filter').on('click', function () {
if ( $(this).hasClass("period") ) {
period = $(this).attr('data-period');
finalFilter = "data-" + region + "-" + period;
console.log(finalFilter);
console.log(period);
updatedFinalFilter();
}
});
Note the lack of var when we update it from in the function - you don't want to redeclare it there otherwise it will become a different finalFilter locally scoped to that function.

Related

How to create an “unlimited” number of independent timers as individual list items in an unordered list with Javascript or jQuery?

I am trying to write a function which when executed (e.g. user clicks a button or image) creates and displays a new timer as a new list item in an unordered list (jQuery Sortable list). It doesn’t need to be super accurate so SetInterval should work fine. It doesn’t need any stops or resets. I would like the user to be able to create as many new independent (count-up) timers (as list items) in the list as they want, theoretically (although in reality there will likely be less than 10-15 on the go at the same time).
The following code does achieve this (or at least does the first time it is run). Subsequent clicks cause grief as I suspect that the same id is being used more than once for both “minutes” and “seconds” causing a conflict between list items.
function listTimer() {
var sec = 0;
function pad ( val ) { return val > 9 ? val : "0" + val; }
setInterval (function(){
document.getElementById("seconds").innerHTML=pad(++sec%60);
document.getElementById("minutes").innerHTML=pad(parseInt(sec/60,10));
}, 1000);
$(document).ready(function(){
$("#sortable1").append('<li class="ui-state-default">' + '<span id="minutes">' + '' + '</span>' + ':' + '<span id="seconds">' + '' + '</span>' + '</li>');
});
}
To allow multiple timers I then figured that each time the function is executed, the values should increment so they are seen as separate. As such I tried
Var i = 0;
function listTimer() {
var sec = 0;
function pad ( val ) { return val > 9 ? val : "0" + val; }
setInterval (function(){
document.getElementById("seconds"+i).innerHTML=pad(++sec%60);
document.getElementById("minutes"+i).innerHTML=pad(parseInt(sec/60,10));
}, 1000);
$(document).ready(function(){
$("#sortable1").append('<li class="ui-state-default">' + '<span id="minutes"+i>' + '' + '</span>' + ':' + '<span id="seconds"+i>' + '' + '</span>' + '</li>');
i=++;
});
}
The “seconds” + i ( and “minutes” =i ) in the .innerHTML works because if I leave var i=0 and then hard code “seconds0” and “minutes0” (instead of “seconds”+i etc) in the span id, a timer is generated as planned (once). The trick is that the “seconds” + i (and “minutes” =i ) in the span id do not work as I imagined. If I leave it as per the code above (e.g. in both the .innerHTML and span id) no list item is generated. I suspect the problem is in incrementing the span id.
Addressing the “span id=” to increment it (multiple ways) does not seem to have helped.
I have tried declaring and inserting a variable with no luck:
var newSeconds= “seconds” +i;
var newMinutes= “seconds” +i;
$(document).ready(function(){
$("#sortable1").append('<li class="ui-state-default">' + '<span id=newMinutes >' + '' + '</span>' + ':' + '<span id=newSeconds>' + '' + '</span>' + '</li>');
I have tried changing the id of the span just prior to the append with either:
document.getElementById("seconds").setAttribute("id", "seconds" +i);
document.getElementById("minutes").setAttribute("id", "minutes" + i);
or
document.getElementById("seconds").id("seconds" +i);
document.getElementById("minutes").id ("minutes" + i);
or
var newSeconds= “seconds” +i;
var newMinutes= “seconds” +i;
document.getElementById("seconds").setAttribute("id", newSeconds);
document.getElementById("minutes").setAttribute("id", newMinutes);
or by combinations of these e.g putting quotation marks around the newSeconds/newMinutes in both the .id and .setAttribute.
but I can’t seem to make the append method work and create a new independent list timer each time the trigger is clicked. The timers jump all over the place (or not at all) when the function is executed multiple times.
I have tried searching for javascript or jQuery ways of doing this but I can only seem to see previous questions that revolve around a certain number of timers (and hard coding them e.g. timer1, timer2 etc) rather than an "unlimited" number of timers. I have looked at books on Javascript and jQuery but can't seem to nut out the solution.
I am hoping I have given a minimal reproducible example. I am obviously missing fundamental issues but am unconscious incompetent at the moment. Is anyone happy to show me the error of my ways and help me get the function working?
I think that the issue stems from your referring to the timers by their Id attributes - an Id attribute is supposed to appear once per page, so having it appear in each timer will definitely cause some confusion.
I would recommend a different structure as well for organization. Here are my thoughts in pseudocode (leaving the implementation up to you)
const $timerContainerDiv = $("…"); // the place where timers live
var timers = []; // this is an array containing all of your timers
// function to add a new timer to the array
var addTimer = function(int minutes, int seconds, int title) {
// html that defines the actual structure of the timer,
// including elements for hours and minutes, each identifiable
// by a js class, and each one including a data attribute giving its value
// for example:
var $timer = $("<div class='timer' data-minutes='" + minutes + "' data-seconds='" + seconds + "' title='" + title + "'>");
timers.push(timer);
}
// now define a timer function to update all timers once per second
var updateTimers = function() {
// update each timer, decrementing one second
$.each(timers, function(index, val) {
var $timer = $(val);
var minutes = $timer.data("minutes");
var seconds = $timer.data("seconds");
var title = $timer.attr("title");
seconds--;
// need logic for when seconds goes negative to reset to 59 and decrement minutes
// need logic for when timer done, etc
$timer.empty();
$timer.append("<span>" + title + ": " + minutes + ":" + seconds + " remaining</span>");
});
setTimeout(updateTimers,1000); // call itself
}
updateTimers(); // get the whole thing started

How to change only the second parameter of an onclick function when it's clicked

I have an onclick handler with two parameters. When it's clicked I want to update only the second parameter value. I prefer jQuery.
I have tried all kinds of jQuery combinations.
The included code works but I want to exclude replacing the first parameter.
The link:
<a href="#" id="messageremove" onclick="messageremove('param1', 'param2')"
The jQuery code:
$("#messageremove").attr('onclick', 'messageremove(' + "'" + param1 + "'" + ', ' + "'" + param2_new + "'" + ')');
I want to exclude replacing the first parameter, but right now both are being replaced.
Pass the variables, store the before variable and the new variable. Then update accordingly. I just switched them in this exmaple.
let before = '';
let after = '';
function messageremove(param1, param2) {
before = param1;
after = param2;
$("#messageremove").attr('onclick', `messageremove(`+ after + `,` + before + `)`)
console.log($("#messageremove").attr('onclick'))
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Switch

Encode a string to pass as a parameter

I have this function:
function eLookup(type, long, lat, distance) {
//var sFilter = getCompanyProductFamilies();
distance = distance * 1000;
$.ajax({
url: O.GenURL('xtmp_Maps/Get' + type + '.asp', 'long=' + long + '&lat=' + lat + '&distance=' + distance),
success: eval('plotEntity' + type)
});
}
I have another function called getCompanyProductFamilies which I have commented out the call for in the above function as there is something wrong and this is partly where I'm stuck.
function getCompanyProductFamilies()
{
var cb = document.getElementsByClassName("PRODFAM");
var sAnd = "";
for(var i = 0; i < cb.length; i++)
{
sAnd += "comp_c_productfamily like '%," + cb[i].id.replace("pdfam_", "") + ",%' or ")
}
if(cb.length > 0)
{
sAnd = sAnd.slice(0, -4);
sAnd = " and (" + sAnd + ")";
}
return sAnd;
}
The above function should get all checkboxes with the class name of PRODFAM, and for each one that is checked, it should slowly generate part of a where clause for a SQL statement. I am aware of the implications of SQL injections, but this is not something on the open internet, so ignore that. I tried several ways of getting the checked ones using jQuery but nothing I did worked.
An example of the HTML it is working on is here:
<input type="checkbox" id="pdfam_711121" class="PRODFAM"/>
<label for="pdfam_711121" class="VIEWBOX">Local Wage Rate</label><br />
<input type="checkbox" id="pdfam_711131" class="PRODFAM"/>
<label for="pdfam_711131" class="VIEWBOX">Temporary Staff</label><br />
<input type="checkbox" id="pdfam_711341" class="PRODFAM"/>
<label for="pdfam_711341" class="VIEWBOX">Other Contractors</label><br />
There are about 25 of the above categories, and this is just 3 as an example. The number of categories could change as well. What I need my my function(s) to do is:
Get a list of checkbox IDs that are checked and construct a string that can be passed as a parameter to the ajax call in the top function. When the parameter is received by the target of the ajax call, I can put a function in that page that creates the where clause for the SQL call.
Any help would be most appreciated. The top function called eLookup can't change too much but I can add querystring parameters, which is what I want to do. The other function it doesn't matter about that.
This is the code that works.
function getCompanyProductFamilies()
{
var cb = document.getElementsByClassName("PRODFAM");
var sAnd = "";
var bChecked = false;
for(var i = 0; i < cb.length; i++)
{
if(cb[i].checked == true)
{
sAnd += "comp_c_productfamily like '%," + cb[i].id.replace("pdfam_", "") + ",%' or ";
bChecked = true;
}
}
if(bChecked)
{
sAnd = sAnd.slice(0, -4);
sAnd = " and (" + sAnd + ")";
}
return sAnd;
}
As this returns a plain text string that is passed directly to an ASP page on the querystring, I may encrypt it. If I use encodeURIComponent, that makes it safe to pass onto the querystring, but still it can be altered. It isn't critical because of where the system is running, but I may look into something to safeguard the string.

Need to export tables inside a <div> as excel, keeping filled-in input and option data

I have a page that takes some selections in javascript and makes a recommendation based on the inputs. Some of my customers want to be able to save this data in excel format, but I'm running into issues retrofitting that.
Here is the code that I found to export the HTML in a DIV as an XLS:
$('btnExport').addEvent('click', function(e){
//getting values of current time for generating the file name
var dt = new Date();
var day = dt.getDate();
var month = dt.getMonth() + 1;
var year = dt.getFullYear();
var hour = dt.getHours();
var mins = dt.getMinutes();
var postfix = day + "." + month + "." + year + "_" + hour + "." + mins;
//creating a temporary HTML link element (they support setting file names)
var a = document.createElement('a');
//getting data from our div that contains the HTML table
var data_type = 'data:application/vnd.ms-excel';
var table_div = document.getElementById('dvData');
var table_html = table_div.outerHTML.replace(/ /g, '%20');
a.href = data_type + ', ' + table_html;
//setting the file name
a.download = 'exported_table_' + postfix + '.xls';
//triggering the function
a.click();
//just in case, prevent default behaviour
e.preventDefault();
});
This almost does what I need it to, but I would like to be able to preserve the initial selections (both drop downs and fields) as their values in the final output. I found some related code to go in and replace those tags with their values, but that affects the page itself, not the output.
var inputs = document.querySelectorAll('select');
for (var i = 0; i < inputs.length; i++) {
var text = document.createTextNode(inputs[i].value);
inputs[i].parentNode.replaceChild(text, inputs[i]);
}
How do I combine these two functions into something that makes sense? The data I need to export is split across multiple tables. I found some solutions leveraging jquery, but I'm using mootools on the site, and combining the two seems to break things.
I will give you a hint for a lazy solution. On page load clone that div with cloneNode and keep it as a variable. When you need to do the export just export that reference (not the actual div).
On the other hand, if you need to keep some other information entered by user still clone the node and run through all the fields and dropdowns within a cloned instance and set them back to default. If you need a reference to each default value of each dropdown you can do so with some kind of data-* attribute. Then again, export the cloned node.

How to write arguments in function?

I have been using functions but I am not able to tackle this.
What I have done is created a function, then made this to use the values provided by the document class or ids and do the work. Once work is done then just give the data back! It worked!
Now I want to make this function happen for two divs, the first function works good. The issue is with the second one. The function is correct, their is some other bug while writing the result.
Here is my code:
function time_untilCom(id) {
var Time2 = Date.parse(document.getElementById("time_" + 2).value);
var curTime2 = new Date();
var timeToWrite2 = "";
var seconds2 = Math.floor((curTime2 - Time2) / (1000));
if (seconds2 > 0 && seconds2 < 60) {// seconds..
timeToWrite2 = seconds2 + " seconds ago";
$('#update_' + 2).html(seconds2);
$('#jstime_' + 2).html(timeToWrite2 + " <b>Time that was captured!</b>");
}
}
If I use it as it is, it works! The issue comes when I try to replace these
("time_" + 2), ("#update_" + 2), ("#jstime" + 2) with ("time_" + id), ("#update_" + id), ("#jstime_" + id).
What i want to happen is that the function would be provided with a common ID that is applied throughout the div and use that ID, to get the value of time, convert it to seconds, do other stuff and then provide me with the result in the corresponding element with the id that was in the argument.
function works great, it do provide me with the result. But the issue is with the id its not being sent I guess. Or if is being sent then not being applied. What might be the issue here? And don't mind the seconds i have that covered too.
I am really very sorry for short code:
Pardon me, I was about to write the code for the function too. But electricity ran out!
Here is the code: onload="time_untilCom('2'), this is the way I am executing this.
And once in the main code, it will be executed like this: onload="time_untilCom(#row.Id) because I am using ASP.NET Web Pages I will be using the server side code to write the ID from Database. And will then user the ID throughtout the div to update the time!
From what I understand, you probably want to replace the second line
var Time2 = Date.parse(document.getElementById("time_" + 2).value);
with
var Time2 = Date.parse(document.getElementById(id).value);
And at the end you can also use
$('#'+id).html(timeToWrite2 + " <b>Time that was captured!</b>");
You are passing "id" as an argument, but you never use it inside the function. My question is: In your example you are using 2 as appendix to id attributes. Is it the 2 (or other numbers respectively) that you want to have as the id parameter of the function?
Then you could just replace each + 2 in your code by + id
function time_untilCom(id) {
var Time2 = Date.parse(document.getElementById("time_" + id).value);
var curTime2 = new Date();
var timeToWrite2 = "";
var seconds2 = Math.floor((curTime2 - Time2) / (1000));
if (seconds2 > 0 && seconds2 < 60) {// seconds..
timeToWrite2 = seconds2 + " seconds ago";
$('#update_' + id).html(seconds2);
$('#jstime_' + id).html(timeToWrite2 + " <b>Time that was captured!</b>");
}
}
EDIT: Please tell us where and how exactly do you call time_untilCom? Did you pass the id there?

Categories

Resources