How to select elements by css property - html

I have a third party library that add texts to my angular app, and I want to style it, unfortunately there is no class or specific element name to do css selector by.
My question is if is it possible to do css selector based on css property.
For example select all elements that are bold
I tried this but doesn't work and I get SassError: Expected identifier
ngx-contentful-rich-text {
line-height: 2rem;
*[font-weight=700] {
margin-top: 2rem;
}
}

You might want to use this:
var paragraphs = document.getElementsByTagName('p');
function change() {
var paragraphs = document.getElementsByTagName('p');
for (i = 0; i < paragraphs.length; i++) {
if (getComputedStyle(paragraphs[i]).fontWeight == 700) {
paragraphs[i].style.backgroundColor = '#00ff00';
}
}
}
Snippet:
function change() {
var paragraphs = document.getElementsByTagName('p');
for (i = 0; i < paragraphs.length; i++) {
if (getComputedStyle(paragraphs[i]).fontWeight == 700) {
paragraphs[i].style.backgroundColor = '#00ff00';
}
}
}
<button onclick="change()">Change!</button>
<p style="font-weight:400;">Will not change.</p>
<p style="font-weight:700;">Will change.</p>

Related

HTML - Hiding objects based on class

I have a function that hides a div with the corresponding ID based on a radio button change, however, I would like to hide multiple items at once and as ID is unique I am not able to just hide them all. How would I set up a class that I can hide and how would I adjust this code below to make that work?
Any help greatly appreciated
function onChangePackage() {
const nodes = document.getElementsByClassName("baseClass");
var selectedValue;
// Get selected radio
for (var i = 0, length = nodes.length; i < length; i++) {
if (nodes[i].checked) {
selectedValue = nodes[i].value;
break;
}
}
// Showing all nodes first
const nodePostFix = ['A','B','C'];
nodePostFix.forEach( node => {
const currentElement = elementsToHide.item(i);
if (currentElement.hasClass("hidden" + selectedValue)) {
currentElement.style.display = "none";
} else {
currentElement.style.display = "block";
}
});
};
You can use data attributes for this purpose together with the attribute selectors. So you need just to add the data-hidden-for attributes to the required nodes and access them using document.querySelector() or document.querySelectorAll()
First give all the elements a base class name baseClass. You could just give them a class name like hidden and then in your code you could do something like below:
const elementsToHide = document.getElementsByClassName("baseClass");
for (var i = 0; i < elementsToHide.length; i++) {
const currentElement = elementsToHide.item(i);
if (currentElement.hasClass("hidden")) {
currentElement.style.display = "none";
} else {
currentElement.style.display = "block";
}
}
And on the click event of the radio button you could add this class I mentioned above to whichever ones you want to hide:
element.classList.add("hidden");
or
element.classList.remove("hidden");

Static/sticky Header Using Dynamic Table

Please can someone guide me on how to implement a static (sticky) header to this dynamically created table?
I have tried multiple things from Stackoverflow threads for a while now but lack HTML/CSS knowledge and I'm obviously missing something simple.
I have managed to get it working using a table created directly in the main body of the code, but when I use my dynamically created tables from JSON I can't get anything to 'stick'.
Below the code:
<!DOCTYPE html>
<html>
<meta name="viewport" content="width=device-width, initial-scale=0.50, maximum-scale=1, user-scalable=0"/>
<head>
<title>iNews HTML Running Order</title>
<style>
table
{
border: solid 1px #CCCCCC;
border-collapse: collapse;
text-align: left;
font:30px Arial;
}
tr, th, td
{
white-space: nowrap;
padding-right: 50px;
}
tr
{
background-color: #ffffff;
border: solid 1px #CCCCCC;
}
th
{
background-color: #CCCCCC;
}
#container
{
text-align: center;
max-width: 100%;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<body onload="initialisePage('LW')">
<p id="showData">Loading Running Order...</p>
</body>
<script>
var loop;
var filename;
var table;
function updateJSONData(filename)
{
getDataFromJSON(filename)
loop = setInterval(function(){getDataFromJSON(filename);}, 500);
}
function initialisePage(newFilename)
{
filename = newFilename;
updateJSONData(filename)
}
function setFileName(newFilename)
{
clearInterval(loop)
filename = newFilename;
updateJSONData(filename)
}
function getDataFromJSON(filename)
{
$.get( "http://10.142.32.72/dashboard/"+filename+".json", function( data ) {
var myBooks = JSON.parse(data);
CreateTableFromJSON(myBooks)
});
}
function CreateTableFromJSON(myBooks)
{
var title = ["Page", "Slug", "Pres 1", "Pres 2", "CAM", "Format", "Clip Dur", "Total", "Backtime"];
var col = ["page-number", "title", "pres1", "pres2", "camera", "format", "runs-time", "total-time", "back-time"];
// CREATE DYNAMIC TABLE.
table = document.createElement("table");
// CREATE HTML TABLE HEADER ROW USING THE EXTRACTED HEADERS ABOVE.
var tr = table.insertRow(-1); // TABLE ROW.
for (var i = 0; i < col.length; i++) {
var th = document.createElement("th"); // TABLE HEADER.
th.innerHTML = title[i];
tr.appendChild(th);
}
// ADD JSON DATA TO THE TABLE AS ROWS.
for (var i = 0; i < myBooks.length; i++) {
tr = table.insertRow(-1);
if (myBooks[i]["floated"] == "true"){
tr.style.color = "#ffffff";
tr.style.background = "blue";
}
if ((myBooks[i]["break"] == "true") && (myBooks[i]["floated"] == "false")){
tr.style.background = "#00ff00";
}
for (var j = 0; j < col.length; j++) {
var tabCell = tr.insertCell(-1);
tabCell.innerHTML = myBooks[i][col[j]];
}
}
// FINALLY ADD THE NEWLY CREATED TABLE WITH JSON DATA TO A CONTAINER.
var divContainer = document.getElementById("showData");
divContainer.innerHTML = "";
divContainer.appendChild(table);
console.log("Refreshed: " + filename);
}
</script>
</html>
Many thanks in advance,
Joe
Remove <body onload="initialisePage('LW')"> and use DOMContentLoaded instead as it happens much sooner than the document load event.
load is only fired after ALL resources/content has been loaded, including "non-essential" (non-DOM) content like images and external content like ad-banners, which means the load event may be fired tens-of-seconds after DOMContentLoaded which makes the load event kinda useless today).
Change your CSS to this:
table > thead > tr > th {
position: sticky;
top: 0;
z-index: 10;
}
table > tbody > tr.floated {
color: '#ffffff';
background-color: 'blue';
}
table > tbody > tr.broken {
background-color: '#00ff00';
}
JavaScript uses camelCase for functions, values (variables and parameters) and properties, not PascalCase.
Avoid var and use const and let in scripts where appropriate instead. Note that const means "unchanging reference" (kinda like C++); it does not mean "immutable" or "compile-time constant value". I think this definition of const was a mistake by the JavaScript language designers, but that's just, like, my opinion, man.
Use CSS classes via classList instead of setting individual style properties using .style.
The current JavaScript ecosystem also generally uses 1TBS instead of the Allman style.
Prefer === (exactly-equals) instead of == (equals) because JavaScript's type coercion can be surprising).
Avoid using innerHTML wherever possible. Use .textContent for setting normal text content (and avoid using .innerText too). Misuse of innerHTML leads to XSS vulnerabilities.
It's 2020. STOP USING JQUERY!!!!!!!!!!
Cite
Cite
Cite
Cite
DONT USE ALL-CAPS IN YOUR JAVASCRIPT COMMENTS BECAUSE IT LOOKS LIKE THE AUTHOR IS SHOUTING AT YOU NEEDLESSLY AND IT GETS QUITE ANNOYING FOR OTHER READERS ARRRRGGGHHHHH
You need to handle HTTP request responses correctly (e.g. to check for succesful responses with the correct Content-Type).
Avoid using j as an iterable variable name because it's too visually similar to i.
Change your JavaScript to this:
<script>
// You should put all of your own application-specific top-level page script variables in their own object so you can easily access them separately from the global `window` object.
const myPageState = {
loop : null,
fileName: null,
table : null
};
window.myPageState = myPageState; // In the top-level function, `const` and `let`, unlike `var`, do not create a global property - so you need to explicitly set a property like so: `window.{propertyName} = ...`.
window.addEventListener( 'DOMContentLoaded', onDOMLoaded );
function onDOMLoaded( ev ) {
window.myPageState.fileName = "LW";
window.myPageState.loop = setInterval( refreshTable, 500 );
}
async function refreshTable() {
if( typeof window.myPageState.fileName !== 'string' || window.myPageState.fileName.length === 0 ) return;
const url = "http://10.142.32.72/dashboard/" + window.myPageState.fileName + ".json";
const resp = await fetch( url );
if( resp.status === 200 && resp.headers['ContentType'] === 'application/json' ) {
const deserialized = await resp.json();
ceateAndPopulateTableFromJSONResponse( deserialized );
}
else {
// Error: unexpected response.
// TODO: error handling
// e.g. `console.error` or `throw new Error( "Unexpected response." )`, etc.
}
}
function ceateAndPopulateTableFromJSONResponse( myBooks ) {
// TODO: Verify the `myBooks` object layout (i.e. schema-verify `myBooks`).
const columnTitles = ["Page", "Slug", "Pres 1", "Pres 2", "CAM", "Format", "Clip Dur", "Total", "Backtime"];
const columnNames = ["page-number", "title", "pres1", "pres2", "camera", "format", "runs-time", "total-time", "back-time"];
const table = window.myPageState.table || document.createElement( 'table' );
if( window.myPageState.table !== table ) {
window.myPageState = table;
document.getElementById("showData").appendChild( table );
}
// Create the <thead>, if nnecessary:
if( table.tHead === null )
{
table.tHead = document.createElement( 'thead' );
const tHeadTR = table.tHead.insertRow(-1);
for( let i = 0; i < columnNames.length; i++ ) {
const th = document.createElement('th');
th.textContent = columnTitles[i];
tHeadTR.appendChild( th );
}
}
// Clear any existing tbody:
while( table.tBodies.length > 0 ) {
table.removeChild( table.tBodies[0] );
}
// Populate a new <tbody>:
{
const tbody = document.createElement('tbody');
for( let i = 0; i < myBooks.length; i++ ) {
const tr = table.insertRow(-1);
tr.classList.toggle( 'floated', myBooks[i]["floated"] === "true" );
tr.classList.toggle( 'broken' , myBooks[i]["break" ] === "true" && myBooks[i]["floated"] === "false" );
for( let c = 0; c < columnNames.length; c++ ) {
const td = tr.insertCell(-1);
const colName = columnNames[c];
td.textContent = myBooks[i][ colName ];
}
}
table.appendChild( tbody );
}
console.log( "Refreshed: " + window.myPageState.fileName );
}
</script>

Many checkbox elements "slows" down Safari

I am encountering an issue, in Safari. When I have many type="checkbox" elements on a page, interacting with with a text input becomes very slow and laggy.
This seems much more severe in Safari than Chrome/Firefox (on Mac).
I noticed the performance issue when doing some filtering on the massive list that contains checkboxes, but noticed that even if I remove my filtering code, the performance is still very poor.
Snippet #1
1600 type="checkbox" elements. Try interacting with the text input on Safari - Fiddle Here
function make() {
var num = 1600;
for( var i = 0; i < num; i++) {
var p = document.createElement("div");
var input = document.createElement("input");
input.type = "checkbox";
p.appendChild(input);
document.getElementById("container").appendChild(p);
}
}
make();
<input type="text">
<div id="container">
</div>
Snippet #2
1600 span elements; interacting with the text input is as smooth as usual in Safari - Fiddle Here
function make() {
var num = 1600;
for( var i = 0; i < num; i++) {
var p = document.createElement("div");
var input = document.createElement("input");
input.type = "checkbox";
p.appendChild(input);
document.getElementById("container").appendChild(p);
}
}
function make2() {
var num = 1600;
for( var i = 0; i < num; i++) {
var p = document.createElement("div");
var sp = document.createElement("span");
sp.innerHTML = Math.floor(Math.random() * 1600);
p.appendChild(sp);
document.getElementById("container").appendChild(p);
}
}
make2();
<input type="text">
<div id="container">
</div>
Is there anyway I can remedy this issue in Safari and get the performance closer to how Firefox and Chrome handle this?
Summary:
From my understanding of your question, your stating the webpage performance is lost when you use checkboxes over spans, and would like to know why this may be
Answer
You have an unusually high number of form checkboxes, whilst a browser can quite easily handle more form elements, it will ultimately depend on how much RAM you have available and installed on that terminal.
There is no official limit to the number of DOM elements you can have on a website, the only thing I can suggest is to use AJAX and pagination to break down the number of checkboxes you have on 1 page at any given time or upgrade your computer.
I have checked out the links you profiled to JSFiddle and did not have any issues with lag typing into the text box myself.
I dont feel this is an HTML question, but rather a memory / performance issue
Check to see how much memory you have, how much memory you have free and available and if there is an issue with your version of your browser that may be causing a memory lag. For instance Firefox has been notoriously known for causing memory issues when left running for a while.
The issue seems to lie with displaying the Safari checkbox. If the checkboxes exist in the dom but are hidden, by using display: none, the performance degradation is gone.
While I don't understand exactly why this is occuring, I can essentially resolve the issue by using custom checkbox element and applying the display: none property on the original.
Snippet - Fiddle Here
function make() {
var num = 1600;
for( var i = 0; i < num; i++) {
var p = document.createElement("div");
var input = document.createElement("input");
var l = document.createElement("label");
var c = "c-" + Math.floor(Math.random() * 1600);
input.type = "checkbox";
l.htmlFor = c;
input.id = c;
p.appendChild(input);
p.appendChild(l);
document.getElementById("container").appendChild(p);
}
}
function make2() {
var num = 1600;
for( var i = 0; i < num; i++) {
var p = document.createElement("div");
var sp = document.createElement("span");
sp.innerHTML = Math.floor(Math.random() * 1600);
p.appendChild(sp);
document.getElementById("container").appendChild(p);
}
}
make();
input[type=checkbox] {
display: none;
}
label {
cursor: pointer;
border: 1px solid #ccc;
border-radius: 50%;
display: block;
height: 12px;
width: 12px;
margin-bottom: 4px;
position: relative;
}
label:after {
background: red;
border-radius: 50%;
content: "";
position: absolute;
height: 8px;
width: 8px;
top: 2px;
left: 2px;
display: none;
}
input[type=checkbox]:checked + label {
border-color: red;
}
input[type=checkbox]:checked + label:after {
display: block;
}
<input type="text">
<div id="container">
</div>

Bootstrap slider/carousel

I want to make a bootstrap carousel with text, on top of this 4 circles where everytime 1 circle is 'selected/hovered' the right circle and the right line underneath is shown. Something like this:
Who can help me with this issue?
Here's a vanilla JS carousel you can look at, however as others pointed out Stack Overflow is not a service to create your projects for you. You will need to research CSS more so you can get the carousel to appear how you would like.
//Changed index so 1 is actually first image, rather than starting at 0 index
var index = 1;
var paused = false;
var slideShow = [];
for (i=0; i<document.getElementsByClassName("slideShow").length; i++) {
slideShow[i] = document.getElementsByClassName("slideShow")[i];
slideShow[i].style.display = "none";
}
slideShow[0].style.display = "inline";
var slides = setInterval(function() {
if (index < slideShow.length) {
index++;
showDivs();
}
else {
index = 1;
showDivs();
}
},1000);
function control(n) {
clearInterval(slides);
if (index+n > slideShow.length) {
index = 1;
}
else if (index+n <= 0) {
index = slideShow.length;
}
else {
index += n;
}
showDivs();
}
function showDivs() {
//Hide all slideShow elements, and then show only the targeted element
for (let i=1; i<=slideShow.length; i++) {
slideShow[i-1].style.display = "none";
}
slideShow[index-1].style.display = "inline";
}
<button onclick="control(-1)" class="arrows" id="left"><</button>
<p class="slideShow">1</p>
<p class="slideShow">2</p>
<p class="slideShow">3</p>
<p class="slideShow">4</p>
<p class="slideShow">5</p>
<button onclick="control(1)" class="arrows" id="right">></button>

Auto hide rows in HTML table when entire row is empty

In a HTML table how can I auto hide an entire row if all the cells (columns) within that row are empty?
I presume there is something I can add to the tag that would do this, but I cannot seem to find a solution anywhere.
In HTML, you can use the hidden attribute, as in <tr hidden>, but this is an HTML5 novelty and has limited browser support. But if you can directly change the HTML markup, the best way to hide an element is to remove it.
Assuming you want something that still lets you have the row there in the markup, for some reason, then you can use JavaScript e.g. as follows:
<script>
function emptyCellsOnly(row) {
var cells = row.cells;
for(var j = 0; j < cells.length; j++) {
if(cells[j].innerHTML !== '') {
return false;
}
}
return true;
}
var rows = document.getElementsByTagName('tr');
for(var i = 0; i < rows.length; i++) {
if(emptyCellsOnly(rows[i])) {
rows[i].style.display = 'none';
}
}
</script>
The test if(cells[j].innerHTML !== '') checks whether cell is completely empty, as in <td></td>. A space character, or a line break, is not counted as empty. If they should be, modify the condition as needed.
The code rows[i].style.display = 'none' hides the row by setting its display property to none, so CSS-enabled browsers will show the page as if the element were not there, but it is still accessible to scripts, etc. You could alternative remove the element completely from the DOM.
You can use a javascript like this
$('tr').each(function() {
if($(this).find('td').length == 0) {
$(this).hide();
}
});
After some research I found this sollution, which has the advantage over empty-cells:hide, that it completely removes the space an empty cell would take up.
<style type="text/css">
table {
border-spacing: 0px; // removes spaces between empty cells
border: 1px solid black;
}
tr, td {
border-style: none; // see note below
padding: 0px; // removes spaces between empty cells
line-height: 2em; // give the text some space inside its cell
height: 0px; // set the size of empty cells to 0
}
</style>
Unfortunately you have to set border-style: none;, else the borders of empty cells will be painted anyway (which results in thick lines).
I tried additional code like:
td:empty {
display: none;
border-style: none;
}
But in my table of 2 columns it removes the borders of either the left or the right column, but never of both...
Any hint at how to remove the borders of empty rows would be appreciated.
in my case cells have Spaces tabs . they are not data.
areAllCellsEmpty : true if, all cells.textContent are empty or Whitespace
innerHTML didnt give the result i wanted.
usage:
hideEmptyRows_ofTableById("myTable_id"); /* <- your table id here */
code:
function isEmptyOrSpaces(str){
return str === null || str.trim() === '' ;
}
function areAllCellsEmpty(row) {
var cells = row.cells;
var anyCellFull = false;
for(var j = 0; j < cells.length; j++) {
if( ! isEmptyOrSpaces(cells[j].textContent) ) {
anyCellFull =true;
break;
}
}
return !anyCellFull;
}
function hideEmptyRows_ofTableById(elem_id){
var table = document.getElementById(elem_id);
var rows = table.getElementsByTagName('tr');
for(var i = 0; i < rows.length; i++) {
if( areAllCellsEmpty(rows[i]) ) {
rows[i].style.display = 'none';
}
}
}