Adding HTML using JQuery - javascript

The jquery below leaves the time from datetime out of the brackets but not the date.
below is the jquery:
$('.counter_area').html('<div class="open-ViewCustomer well well-sm"' +
'data-toggle="modal" data-id=' + v.id +
' data-first=' + v.first_name +
' data-last=' + v.last_name +
' data-time=' + v.joined_at +
' data-note=' + v.note +
' data-download=' + v.attach +
' href="#viewCustomer" data-placement="bottom" title="View Customer Details And Options">' + v.first_name +
' ' + v.last_name +
'</div>'
);
this is what it produces:
<div class="open-ViewCustomer well well-sm" data-toggle="modal" data-id="2" data-first="joe"
data-last="doe" data-time="2014-03-26" 18:22:50="" data-note="null" data-download="null"
href="#viewCustomer" data-placement="bottom" title="View Customer Details And Options">joe doe</div>
as you can see data-time="2014-03-26" 18:22:50="" should be data-time="2014-03-26 18:22:50"
I'm quite new to front end development, any help to solving this is appreciated.

There is a space in your joined date string, so you will need the quotes around the attribute:
' data-time="' + v.joined_at + '"'+

Right now you are stitching a string of HTML together via jQuery, then appending it to your website. This will generally give you the results that you want, but there is a better way to do this:
// select the counter_area div, and append() a new jQuery object
$('.counter_area').append(
// create a new div and make it as a jQuery object
$('<div class="open-ViewCustomer well well-sm"></div>')
// Set each attribute via the jQuery attr() method
.attr("data-toggle", "modal")
.attr("data-id", v.id)
.attr("data-first", v.first_name)
.attr("data-last", v.last_name)
.attr("data-time", v.joined_at)
.attr("data-note", v.note)
.attr("data-download", v.attach)
.attr("href", "#viewCustomer")
.attr("data-placement", "modal")
.attr("title", "View Customer Details And Options")
// set the text of your new div
.text(v.first_name + " " + v.last_name)
);
Why do it this way?
If someone says that their first name is "onload="window.location='http://example.com', then anyone who visits this page will be redirected from the site. This is a security risk known as XSS: people will use it to hack your website.
If you use the code that I have provided, then jQuery will clean up the names for you: the control characters (specifically the quote (")) will be written in such a way that it is made safe.
jQuery will also automatically handle spaces, quotes, and any other weird characters that might appear in the date or name, so you'll have one less thing to worry about.

Try to add quotes around your values (after the equals and after the concatenated value).
Without them, a space in your values will be interpreted as the end of your value and the begin of a new attribute.

Related

How can I use innerText instead of innerHTML in dynamically created HTML elements?

I use Javascript to dynamically create a lot of elements. Divs, images, spans, etc.
Here is an example piece of code that my JS would run:
infoCell.innerHTML = "Submitted by " + "<a href='/user/" + this.poster + "'><img src='" + this.poster_avatar_src + "' class='avatarimg'> <span style='color:blue'>" + this.poster + "</span> </a>in " + "<span style='color:blue; font-weight: 900;'><a href='/h/" + href + "'>" + this.topic + "</a></span>"
This was written early in my JS development, but now I realize that it can very quickly become very insecure, as almost all of the javascript variables being inserted into the HTML are written by the user with no limitations to character usage, etc.
How can I go through my javascript and change all of these so they still function, but without worrying about users inserting script into my site?
I am fine rewriting a lot but I would like to not do this again. I have about 90 innerHTML DOM modifications in my main JS file (typescript).
you could try to use a combination of document.createElement and HTMLElement.append
an example for the first <a> tag:
function makeElem (tagname, properties) {
let elem = document.createElement(tagname);
for (const key in properties) {
elem[key] = properties[key];
}
return elem;
}
infoCell.append("Submitted by ");
let a = makeElem("a", {href:'/user/"' + this.poster + '"'});
a.replaceChildren(makeElem("img", {'src':this.poster_avatar_src, 'className':'avatarimg'}), makeElem("span", {'textContent':this.poster,'style':'color:blue;'}));
infoCell.append(a);
this might not be the easiest but it should work, the reason for the "makeElem" function is purely convenience and you don't necessarily need it
There are a few approaches.
One is to use a sanitizer to translate all of the dynamic values into properly escaped strings before interpolation - but you'd have to be sure you get it right, otherwise there could still be problems.
Another way is to construct the element structure, then insert the dynamic strings at the appropriate points, eg:
const cell = document.createElement('div');
cell.innerHTML = `
Person info
<div class="name"></div>
<div class="age"></div>
`;
cell.querySelector('.name').textContent = name; // where name is dynamic
cell.querySelector('.age').textContent = age; // where age is dynamic
But this can be tedious if you have a lot of dynamic values to insert.
A third way (and one that I'd recommend for serious applications) is to use a framework to handle it for you. For example, in React, the above "cell" could be made like:
const Cell = ({ name, age }) => (
<div>
Person info
<div class="name">{name}</div>
<div class="age">{age}</div>
</div>
);
It takes some learning and getting used to, but once you get going it's a lot easier to read and write than other approaches.

Trying to use nested if statements inside forEach loop on javascript array

I am trying to use an if statement inside of another if statement and I simply can't figure out how to get the second if statement to work. The second if statement applies all style changes to the first element (school) in the array. I would like the second if statement to apply the correct styling to all items in the array based on the json data ([school.status]).
I've tried switching to a for statement, tried moving the if statements around and nesting them differently, tried async and moving different parts of the formulas in and out of the code blocks. I've tried running a second forEach statement after the append but I couldn't get that to work either. I think I lack an understanding of how this process works, beyond just the code part, but more the logical operator, and after hours of searching for a straight forward answer, and it being almost 4AM, I figured I would just ask here.
schools.forEach(function(school, index) {
dashboardItemStatus = $(".dashboard-item-status");
if (App.hasClass("mainDash")) {
App.append(
'<div class="dashboard-item"><h5 class="mb-1">' +
[school.name] +
"</h5>" +
'<p style="margin-bottom: -2px">' +
[school.address.street] +
"</p>" +
'<p style="margin-bottom: -2px">' +
[school.address.city] +
"," +
" " +
[school.address.state] +
" " +
[school.address.zip] +
"</p>" +
'<p style="margin-bottom: -2px">' +
[school.phone] +
"</p>" +
'<p style="margin-bottom: -2px">' +
[school.principal] +
"</p>" +
'<p style="margin-top: 8px;background-color: #FFF;padding: 8px 14px;border-radius: 5px;" class="dashboard-item-status" id="dashboardItemStatus">' +
[school.status] +
"</p>" +
"</div>"
);
}
if (school.status == "Normal Operation") {
dashboardItemStatus.addClass("dashboard-item-status-normal");
} else if (school.status == "Full Change") {
dashboardItemStatus.addClass("dashboard-item-status-change");
}
});
So, I suppose the expected results are anytime one of the statuses is "Full Change" the dashboard-item-status-change class is applied, and the dashboard-item-status-normal class is applied to any status that has "Normal Operation". That data is an array that is coming from a json file. That part works just fine. The forEach function works fine and the information displays correctly on the screen. Now though, I need to be able to affect the elements that show the status individually based on the status itself. Right now, as stated above, no matter what status I attempt to affect, the channges all occur on the first element in the array, which I guess makes sense, but I have no idea how to fix it. If I console.log() the names and statuses of the schools inside the second if statement, they display correctly so I know I can find the right values, I just don't know how to affect them. Maybe map or something may work but I honestly don't know how to use that correctly. Any help is really appreciated.

executing javascript inside href attribute of anchor tag

I checked a lot on Hrefs but couldn't get something related.
I am trying to do this in code behind which is actually a custom control class
writer.Write("<a href='javascript:document.location.href?" + filter.ParameterName + "=" + filter.QueryValue + "'>" + filter.UserVisibleValue + "</a>| ");
now this gets me something like this on hover of above anchor 'document.location.href?Test one=2013' and when i click it, this throws an obvious javascript error 'SyntaxError: missing : in conditional expression' because it takes it as a conditional operator and hence finds : missing.
I simply want that document.location.href (current url) should be calculated and the value put in where i use it.
I know that i may simply call a javascript function and inside that function i set the href but can i do it this way?
Try this:
writer.Write("<a href='javascript:window.location = document.location.href?" + filter.ParameterName + "=" + filter.QueryValue + "'>" + filter.UserVisibleValue + "</a>| ");
Note that you might have to escape values as needed otherwise JavaScript will become invalid. To prove that above approach works, you can copy-paste following simpler example in any HTML page and see it working:
bla

Javascript- Setting Input Value

EDIT: As this question turned out to be quite a bit different than originally stated, please refer instead to HTML- Altering Input Value
I have an input element that I am trying to set while I'm creating a pair of tables (the value should reflect the total value of the row). However, the statement is not working for some reason. The basics of the code are as follows:
prevTotalElt = $('#TimeSheetTable #ProjectData #projectBody #' + curProj + '_total');
alert(prevTotalElt.val() + '\n' + prevTotalVal);
prevTotalElt.val(prevTotalVal);
This code is in an if statement, and the alert message appears as expected with the proper values. The weirdest bit is that the same statement executes at the end of the loop (to take care of the final total element in the table) and works perfectly. I can't really understand what the issue is here, but any help would be appreciated.
EDIT: Due to requests, here is the line that creates the input element I am trying to set:
$('#TimeSheetTable #ProjectData #projectBody').html($('#TimeSheetTable #ProjectData #projectBody').html() +
'<tr><td align="center"><input id="' + curProj + '_total" type="number"' +
'align="center" value="' + tmpInd + '" style="width:17px; border:none;" disabled></td>');

Why functionToCallOnOk I pass to my function does not get called when I attach it to callback via jQuery?

So I try such code:
function showAlertWithCallback(w, h, name, body_text, functionToCallOnOk) {
prepareWindow();
var ran_alert_number=Math.random()*50000;
$("#alert_content").html(body_text + '<br/>' + '<input type=\"button\" class=\"eButton\" value=\"Cancel\" onClick=$(\".alert\").hide() />' + '<input id=\"general-alert-'+ ran_alert_number +'\" type=\"button\" class=\"eButton\" value=\"OK\" onClick=\"$(\'.alert\').hide();\"/>');
$('#general-alert-' + ran_alert_number).click(functionToCallOnOk);
// also tried $('#general-alert-' + ran_alert_number).click(function(){functionToCallOnOk();});
showAlertBase(w, h, name);
}
called via something like:
showAlertWithCallback(
600,
100 ,
('New name for to ' + file_title + ' file.'),
'<input type="text" style="width:590px" class="text" value=\"' + file_title + '\">',
function(){
alert("hi!");
}
);
runs with no errors (chrome debugger) but function does not get called on OK click. Why and how to fix such thing?
Math.random()*50000 will produce a number like 38518.060150090605, which when you concatenate with '#general-alert-' in the jQuery call will produce a selector like this:
#general-alert-38518.060150090605
That will be treated as a selector which finds an element with id general-alert-38518 and class 060150090605, since the class name comes after the dot.
To make the random number, use, say, Math.floor(Math.random()*5000) instead.
A better option would be to use an incrementing global variable (eg, _global_counter++ each time you use it), then you would not have a chance of getting two elements with the same id.
An even better solution would be to create actual DOM elements in JavaScript, attach events to those elements, then insert those elements into the correct place in the document. That way they won't need to have ids at all.
Try removing the onClick attribute of the OK button.

Categories