Problems with setting a data attribute using vanilla javascript - javascript

I've been working with a set of data that is returned from a fetch call to a Lucee coldfusion server. The data returned is a structure that looks like this:
{success: true, new_case_number: caseno}
This is how everything starts on the Javascript side. I've setup a submit event handler for the form element using form.addeventlistener('submit', inquirySubmit). This is what that looks like:
function inquirySubmit(){
event.preventDefault();
var data = [this.lastname.value, this.caseno.value, this.id.value];
fetch(`../CFC/flowstatus.cfc?method=setDebtorInfo&action=inquiry&trusteeID=${slush}&values=${data}`, {
method: 'post'
})
.then( res => res.json())
.then( (data)=>{
if( data.SUCCESS == true ){
setNewValues(this.lastname.value, data.NEW_CASE_NUMBER)
background.style.transform = 'scaleY(0)';
setTimeout( ()=>{
inquiryEditForm.reset();
inquiryEditForm.display = 'none';
}, 1000 )
}
if( data.SUCCESS == false) alert('Argh!')
})
} // END FUNCTION
if the data.SUCCESS variable is set to true I use the setNewValues function:
function setNewValues(lastname, caseno){
console.log(`Lastname: ${lastname}\n Caseno: ${caseno}.`)
var dm = document.querySelector('.debtor-main');
var cn = dm.querySelectorAll('div');
cn.forEach( (div)=>{
if( div.dataset.caseNo == caseno){
div.setAttribute('data-case-no', caseno )
var span_lastname = div.querySelector('#lastname');
var span_caseno = div.querySelector('span[id=caseno]');
span_lastname.innerHTML = lastname;
span_lastname.setAttribute('data-case-no', caseno );
span_caseno.innerHTML = caseno;
span_caseno.setAttribute('data-case-no', caseno );
}
})
} // END FUNCTION
I've added some console.log bits in there to make sure I was getting the right values and they are good. As you can see I'm changing the innerHTML values of some span elements to reflect the changes that the user has typed in. The variable span_lastname gets reset no problem. But neither the data-case-no attributes nor the span_caseno.innerHTML respond to the setAttribute('data-case-no', caseno) call. The thing that's really irritating is that I know I'm accessing the right element with the span_caseno variable because I can effect the style attribute like so:
span_caseno.style.opacity = 0;
And it works.
If anyone has some suggestions it would be very helpful. I'd be happy to change the code up completely, so fire away.

Try using:
span_lastname.dataset.caseNo = caseno;
span_caseno.dataset.caseNo = caseno;
Instead of using setAttribute.

function setNewValues(lastname, caseno){
console.log(`Lastname: ${lastname}\n Caseno: ${caseno}.`)
var dm = document.querySelector('.debtor-main');
var cn = dm.querySelectorAll('div');
Array.from(cn).map( (div)=>{
if( div.dataset.caseNo == caseno){
div.setAttribute('data-case-no', caseno )
var span_lastname = div.querySelector('#lastname');
var span_caseno = div.querySelector('span[id=caseno]');
span_lastname.innerHTML = lastname;
span_lastname.setAttribute('data-case-no', caseno );
span_caseno.innerHTML = caseno;
span_caseno.setAttribute('data-case-no', caseno );
}
})
} // END FUNCTION

Related

Call functions from sources directly in Chrome console?

For a website there is this function under sources with the code:
betSlipView.prototype.stakeOnKeyUp = function(_key) {
var model = ob.slip.getModel(),
defval = ob.cfg.default_bet_amount;
selector = toJqId(["#stake-", _key].join('')),
stake_box = $(selector),
spl = stake_box.val();
if(spl != defval) {
spl = ob.slip.cleanFormatedAmount(spl);
if(spl === '' || isNaN(spl)) {
spl = 0;
$(selector).val('');
}
model.setBetStake(_key, spl);
$(toJqId(['#ob-slip-estimate-', _key].join(''))).html(
model.getBet(_key, 'pretty_returns')
);
} else {
$(selector).val(defval);
model.setBetStake(_key, defval);
$(toJqId(['#ob-slip-estimate-', _key].join(''))).html(
model.getBet(_key, 'pretty_returns')
);
}
//Update bonus amount
try {
var offers = model.getBet(_key, 'offers');
}
catch(err) {
var offers = "";
}
if(offers !== "" && typeof offers['STLWIN'] !== "undefined") {
this._handleAccumulatorBonusElements(_key, offers['STLWIN']);
};
// potential returns for this bet
this.updateTotals();
};
I cannot figure out how to (if possible) call this function directly from the console. Firstly, when I try to write betSlipView in the console, it cannot be found. Consequently if I copy the code to the console to define the function, betSlipView is still not found and if I try to change the function name, there are some names in the function body that cannot be found either. I wish to call this function with certain arguments, is this possible?
The whole code can be found here https://obstatic1.danskespil.dk/static/compressed/js/ob/slip/crunched.pkg.js?ver=0305f181cb96b61490e0fd2adafa3a91

Associative array not filling up in server-sent-event environement

I think I'm on the wrong track here:
I have an event source that gives me updates on the underlying system oprations. The page is intended to show said events in a jquery powered treetable. I receieve the events perfectly but I realized that there were a case I did not handle, the case where an event arrives but is missing it's parent. In this case I need to fetch the missing root plus all potentially missing children of that root node from the database. This works fine too.
//init fct
//...
eventSource.addEventListener("new_node", onEventSourceNewNodeEvent);
//...
function onEventSourceNewNodeEvent(event) {
let data = event.data;
if (!data)
return;
let rows = $(data).filter("tr");
rows.each(function (index, row) {
let parentEventId = row.getAttribute("data-tt-parent-id");
let parentNode = _table.treetable("node", parentEventId);
// if headless state is not fully
// resolved yet keep adding new rows to array
if (headlessRows[parentEventId]) {
headlessRows[parentEventId].push(row);
return;
} else if (parentEventId && !parentNode) { // headless state found
if (!headlessRows[parentEventId])
headlessRows[parentEventId] = [];
headlessRows[parentEventId].push(row);
fetchMissingNodes(parentEventId);
return;
}
insertNode(row, parentNode);
});
}
function fetchMissingNodes(parentEventId) {
let url = _table.data("url") + parentEventId;
$.get(url, function (data, textStatus, request) {
if (!data)
return;
let rows = $(data).filter("tr");
//insert root and children into table
_table.treetable("loadBranch", null, rows);
let parentNode = _table.treetable("node", parentEventId);
let lastLoadedRow = $(rows.last());
let headlessRowsArray = headlessRows[parentEventId];
while (headlessRowsArray && headlessRowsArray.length > 0) {
let row = headlessRowsArray.shift();
let rowId = row.getAttribute("data-tt-id");
if (rowId <= lastLoadedRow) // already loaded event from previous fetch
continue;
insertNode(row, parentNode);
let pendingUpdatesArray = pendingUpdates[rowId];
// shouldn't be more than one but who know future versions
while (pendingUpdatesArray && pendingUpdatesArray.length > 0) {
let updateEvent = headlessRowsArray.shift();
updateNode(updateEvent)
}
delete pendingUpdates[rowId]; // <- something better here?
}
delete headlessRows[parentEventId]; // <- something better here too?
});
}
The problem is around the line if (headlessRows[parentEventId]).
When I run it step by step (putting a debugger instruction just before) everything works fine, the headless array is created and filled correctly.
But as soon as I let it run full speed everything breaks.
The logs I printed seems to indicate that the array is not behaving in the way I was expecting it to. If I print the array with a console.log it shows as follow :
(2957754) [empty × 2957754]
length : 2957754
__proto__ : Array(0)
It seems to be missing any actual data. whereas it shows as follow when I execute it step by step:
(2957748) [empty × 2957747, Array(1)]
2957747:[tr.node.UNDETERMINED]
length:2957748
__proto__:Array(0)
I'm missing something but it is still eluding me.
your code is async, you do http request but you treat him as synchronized code.
try this fix
//init fct
//...
eventSource.addEventListener("new_node", onEventSourceNewNodeEvent);
//...
async function onEventSourceNewNodeEvent(event) {
let data = event.data;
if (!data)
return;
let rows = $(data).filter("tr");
rows.each(function (index, row) {
let parentEventId = row.getAttribute("data-tt-parent-id");
let parentNode = _table.treetable("node", parentEventId);
// if headless state is not fully
// resolved yet keep adding new rows to array
if (headlessRows[parentEventId]) {
headlessRows[parentEventId].push(row);
return;
} else if (parentEventId && !parentNode) { // headless state found
if (!headlessRows[parentEventId])
headlessRows[parentEventId] = [];
headlessRows[parentEventId].push(row);
await fetchMissingNodes(parentEventId);
return;
}
insertNode(row, parentNode);
});
}
function fetchMissingNodes(parentEventId) {
return new Promise((resolve,reject) =>{
let url = _table.data("url") + parentEventId;
$.get(url, function (data, textStatus, request) {
if (!data){
resolve()
return;
}
let rows = $(data).filter("tr");
//insert root and children into table
_table.treetable("loadBranch", null, rows);
let parentNode = _table.treetable("node", parentEventId);
let lastLoadedRow = $(rows.last());
let headlessRowsArray = headlessRows[parentEventId];
while (headlessRowsArray && headlessRowsArray.length > 0) {
let row = headlessRowsArray.shift();
let rowId = row.getAttribute("data-tt-id");
if (rowId <= lastLoadedRow) // already loaded event from previous fetch
continue;
insertNode(row, parentNode);
let pendingUpdatesArray = pendingUpdates[rowId];
// shouldn't be more than one but who know future versions
while (pendingUpdatesArray && pendingUpdatesArray.length > 0) {
let updateEvent = headlessRowsArray.shift();
updateNode(updateEvent)
}
delete pendingUpdates[rowId]; // <- something better here?
}
delete headlessRows[parentEventId]; // <- something better here too?
resolve()
});
})
}

How long should I let a javascript function run before manually ending it?

I have a javascript function that has about 4 ajax requests in it. It typically takes less than a second to run. However, I'm working on the error handling now and was wondering. How long, in seconds, should I allow my javascript function to try to keep working until I manually cancel it and allow the user to try again?
Here's what the function in question looks like. (not everything is there, but it could potentially have (1000*5000*3)+(70)+(1000)+(6)+(2500) bytes being sent)
function saveChanges(bypassDeckSave){
// bypassDeckSave = undefined - does not bypass
showSavedNotification_check = 1;
if(userid != 0){
//values in database
var subjectID = $('.lib_folder_id').val(),
folderID = $('.lib_subject_id').val();
if(subjectID == 0 || folderID == 0){//if database values null, ask for some
console.log("db deck location not saved, asked for it");
//values to set to
var setFolderID = $('.libDeckLocationModifierDiv .folders li.on').val(),
setSubjectID = $('.libDeckLocationModifierDiv .subjects li.on').val();
if(isNaN(setFolderID) || isNaN(setSubjectID) ||
setFolderID == 0 || setSubjectID == 0)
{
openDeckLocationDiv();
showSavedNotification_check = 0;
return;
}
}
}
var deck_id = $('.deck_id').val();
if(deck_id == 0){
// create a new deck
createDeckThenSave();
return;
}
if(userid != 0){
//values in database
var subjectID = $('.lib_folder_id').val(),
folderID = $('.lib_subject_id').val();
if(subjectID == 0 || folderID == 0){//if database values null, ask for some
//values to set to
saveDeckLocation();
}
}
// removes empty rows
$('.editMain li').each(function(){
var one = $(this).find('.text1').val(),
two = $(this).find('.text2').val();
if(one == "" && two == ""){
//remove this row and remove value from updateSaveArray + add to delete array
var currentval = $(this).val();
var rowid = ".row_"+currentval;
updateSaveArray = jQuery.grep(updateSaveArray, function(value) {
return value != currentval;
});
$(rowid).remove();
updateDeleteArray[updateDeleteArray.length] = currentval;
}
});
if(bypassDeckSave == undefined){
// save deck info to db
var deckname = $('.editDeckNameInput').val(),
cardCount = $('.editMain li.mainLi:visible').length,
deckTermLanguage = $('.selector.one select').val(),
deckDefinitionLanguage = $('.selector.two select').val(),
deckThirdBoxLanguage = $('.selector.three select').val(),
deckDescription = $('.editMoreDeckOptionsDiv textarea').val();
if($('.editMoreDeckOptionsSelector .onlyme').hasClass("on")){
var viewPreferences = 1;
}else{
var viewPreferences = 0;
}
if($('.editUseThirdboxDiv').hasClass('on')){ var thirdbox = 1;
}else{ var thirdbox = 2; }
// console.log("deckInfoSave called");
$.ajax({
type: "POST",
url: "/edit/deckInfoSave.php",
data: { pDeckid: deck_id, pDeckname: deckname, pCardCount: cardCount,
pDeckTermLanguage: deckTermLanguage, pDeckDefinitionLanguage: deckDefinitionLanguage,
pDeckThirdBoxLanguage: deckThirdBoxLanguage, pThirdbox: thirdbox,
pDeckDescription: deckDescription, pViewPreferences: viewPreferences
}
})
.done(function(data){
// console.log(data);
// decksaved = 1;
saveDeckInfoHasFinished = 1;
});
}else{
saveDeckInfoHasFinished = 1;
}
// prepares edited card array
// gets all needed values and stores in holdSaveCardArray
var holdSaveCardArray = [];
for (i = 0; i < updateSaveArray.length; ++i) {
var currentCard_id = updateSaveArray[i],
rowidClass = ".row_"+currentCard_id,
text1val = $(rowidClass+" .text1").val(),
text2val = $(rowidClass+" .text2").val(),
text3val = $(rowidClass+" .text3").val();
cardOrder = $(".editMain li.mainLi:visible").index($(rowidClass)) + 1;
holdSaveCardArray[holdSaveCardArray.length] = {
"card_id": currentCard_id,
"text1val": text1val,
"text2val": text2val,
"text3val": text3val,
"cardOrder": cardOrder
};
}
// console.log(print_r(holdSaveCardArray));
// delete cards start
// deletes any card with an id in updateDeleteArray
$.ajax({
type: "POST",
url: "/edit/deleteCards.php",
data: { pDeck_id: deck_id, pDeleteArray: updateDeleteArray }
})
.done(function( msg ) {
// $('.temp').append(msg);
updateDeleteArray = [];
deleteCardsHasFinished = 1;
});
// save cards to database
// loops through each card that had changes made to it
$.ajax({
type: "POST",
url: "/edit/saveCardsArray.php",
dataType: "JSON",
data: { pDeck_id: deck_id, pCardArray: holdSaveCardArray}
}).done(function(data){
for (var i = 0; i < data.length; i++) {
var temp_id = data[i]["temp_id"], // new id
card_key = data[i]["card_key"], // old id
currentClassName = 'row_'+temp_id,
currentClass = '.row_'+temp_id,
nextClassName = 'row_'+card_key;
$(currentClass).val(card_key);
$(currentClass).removeClass(currentClassName).addClass(nextClassName);
}
saveCardsHasFinished = 1;
});
updateSaveArray = [];
// update order start // uses li value
updateOrderArray = [];
$('.editMain').find(".mainLi").each(function(){
var temp = $(this).val();
updateOrderArray[updateOrderArray.length] = temp;
});
$.ajax({
type: "POST",
url: "/edit/orderCards.php",
data: { pUpdateOrderArray: updateOrderArray }
})
.done(function( msg ) {
updateOrder = 0;
updateOrdersHasFinished = 1;
});
closeLibDLM(); console.log("closeLibDLM1");
changeSaveStudyButton(1);
} //saveChanges function end
So you could totally set an arbitrary timeout, or even a timeout that should encompass everything finishing on time? But, what happens when it doesn't? What happens when it takes longer to finish?
At that point, you're going to be in quite a pickle. I did not thoroughly read your code, but I would highly advise trying to use a callback() or Promise to end your function. And, not set a timeout. - This is a cleaner solution in that things happen when you want them, and after some defined has happened. Time is a relative, and finicky attribute of our world (Einstein proved this =P) that would be best be used as your friend, and not your enemy.
The counter argument would be, well sometimes things just hang. And, that is totally valid. For that case, you could set a timeout for a long period of time. But, again, that is still a 'hacky' way to handle things. In this case, I would try to create some handling to detect errors, or timeouts. i.e you could periodically check the page for a status. You could check to see which events are in existence that you could hook into.
If you could share in what instances our program hangs, I could better suggest a solution. Otherwise this question may end up being opinionated based on coding styles.
Hope this helps in some regard :)
I've worked in the Aerospace Aviation Industry and have asked a similar question when working with Microcontrollers. It seems you are looking for an appropriate timeout value based on calculation, but this may not be necessary in your case. Often times timeout values are more or less arbitrary. If your function executes in an average of roughly 1 second, maybe your timeout value should be set to 3 seconds. You should come to a conclusion based on testing.

Can't update javaScript global variable

Here I have global variable userId, and i want to update it inside signInUserFunction(), to use is in other function. I have tried to define it using var, window, But all these didn't help. This variable doesn't update. As i see its about AJAX async. So, what can i do with it?
And yes, I know that its not good to make authentication with JS, I am quite new to it. So, I am just creating random methods to improve.
var userId = 1;
function signInUser() {
$.getJSON('http://localhost:8887/JAXRSService/webresources/generic/getAllUsers', function(data) {
var items = [];
var i = 0;
$.each(data, function(firstname, value) {
var str = JSON.stringify(value);
data = JSON.parse(str);
var innerId;
for (p in data) {
innerId = data[p].id;
if ($('#nameSignIn').val() == data[p].first_name && $('#passwordSignIn').val() == data[p].password) { //
userId = innerId;
window.location.href = "content.html";
break;
} else {
i++;
if (i == data.length) {
alert("Ощибка в логине или пароле!")
}
}
}
});
});
}
How are you determining whether or not it has been set? It looks like immediately after you set it, you navigate to a different page. When you get to that page, you will have an entirely new window.
Try alerting the value before navigating away.
EDITED: Here is how you could pass it to the other page (but you shouldn't do this in a real app)
window.userId=innerId;
alert(window.userId);
//this isn't a very secure way to do this. I DON'T recommend this
window.location.href = "content.html?id=" + innerId ;
Then in the other page, you could access it off the document.location:
alert(document.location.toString().split("?id=")[1]);
After reading my comments, you may want to try this:
var userId = 1;
function signInUser(){
$.getJSON('http://localhost:8887/JAXRSService/webresources/generic/getAllUsers', function(data){
var items = [], actors = data.Actors, l = 0;
$.each(actors, function(i, o){
l++;
if($('#nameSignIn').val() === o.first_name && $('#passwordSignIn').val() === o.password){
userId = o.id;
// this will redirect before any other code runs -> location = 'content.html';
if(l === actors.length){
alert('End of Loop');
}
}
});
});
}
signInUser();
I would not store sensitive data in JSON such as passwords. Use a database. There is no need to get all the data at the same time either.
Using the idea #mcgraphix proposed (and giving you the same warning...this would certainly not be the way to transfer data like this in a production environment), here is one way to do it:
function signInUser() {
var url = 'http://localhost:8887/JAXRSService/webresources/generic/getAllUsers';
var userId;
$.getJSON(url, function(data) {
$.each(data.Actors, function(index, actor) {
// Cache the values of the #nameSignIn and #passwordSignIn elements
var name = $('#nameSignIn').val();
var password = $('#passwordSignIn').val();
if (actor.first_name === name && actor.password === password) {
// We have found the correct actor.
// Extract its ID and assign it to userId.
userId = actor.id;
window.location.href = "content.html?userId=" + userId;
}
});
// This alert should only be reached if none of the actor objects
// has a name and password that matches your input box values.
alert("Ощибка в логине или пароле!");
});
}
// On the next page...
// Top answer from http://stackoverflow.com/questions/2090551/parse-query-string-in-javascript
// This approach can handle URLs with more than one query parameter,
// which you may potentially add in the future.
function getQueryVariable(variable) {
var query = window.location.search.substring(1);
var vars = query.split('&');
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('=');
if (decodeURIComponent(pair[0]) == variable) {
return decodeURIComponent(pair[1]);
}
}
console.log('Query variable %s not found', variable);
}
var userId = getQueryVariable('userId');
Thanks you for help.Ended it all with usage of:
sessionStorage.getItem('label')
sessionStorage.setItem('label', 'value')

LocalStorage storing multiple div hides

I am using a simple code to hide multiple divs if the link to hide them is clicked.
On one of them I have local storage set-up to remember of the div is hidden or not.
The thing is this. How can I write a code to make local storage remember the hidden state of multiple divs WITHOUT having to put localstorage.setItem for each individual div. Is it possible to store an array with the div ids and their display set to true or false to decide if the page should show them or not?
**********EDITED************
function ShowHide(id) {
if(document.getElementById(id).style.display = '') {
document.getElementById(id).style.display = 'none';
}
else if (document.getElementById(id).style.display = 'none') {
document.getElementById(id).style.display = '';
}
Like you said, you already have an array storing all your state. You can serialize this using JSON.stringify() and put the result into localStorage.
// your array
var divstate = [ ... ];
// store it
localStorage.setItem( 'divstate', JSON.stringify( divstate ) );
If you want to retrieve the array again, use JSON.parse():
// restore
var divstate = JSON.parse( localStorage.getItem( 'divstate' );
EDIT
To store the actual ids of all divs, you probably will use something like this
var divstate = {
'divid1': true,
'divid2': false,
...
};
This can easily be used with the above pattern.
2nd EDIT
For the above code I would suggest loading the state variable once at page load using the above statement.
Then transform the function like this:
function ShowHide(id) {
var el = document.getElementById(id);
if ( divstate[id] === true ) {
divstate[id] = false;
el.style.display = 'none';
} else {
divstate[id] = true;
el.style.display = '';
}
localStorage.setItem( 'divstate', JSON.stringify( divstate ) );
}
That way the divstate is updated and stored with each function call.
Note, that I would not recommend this, if the number of divs is too high, but for smaller amounts this should be sufficient.

Categories

Resources