I wanted to get the value of the paragraph alignment to put in the IF condition. The example below fails and does not run
Here is the code
const paragraph = document.getElementsByTagName('p');
for (let i = 0; i < paragraph.length; i++) {
if (paragraph[i].getAttribute('align').value == 'center') {
console.log('paragraph' + i + 'centered')
}
}
<p align="center">this is a paragraph!</p>
As you have noted, the value property does not exist in the attribute. How can I get the value of align, whether it is "center, left, right .."?
const paragraph = document.getElementsByTagName('p');
for (let i = 0; i < paragraph.length; i++) {
if (paragraph[i].getAttribute('align') == 'center') {
console.log('paragraph' + i + 'centered')
}
}
<p align="center">this is a paragraph!</p>
But the align attribute is old and deprecated. It's better to use text-align even if it is more code to read the styles.
const paragraph = document.getElementsByTagName('p');
for (let i = 0; i < paragraph.length; i++) {
let computed = window.getComputedStyle(paragraph[i], null);
let alignment = computed.getPropertyValue('text-align')
if (alignment == 'center') {
console.log('paragraph' + i + 'centered')
}
}
p {
text-align: center;
}
<p>this is a paragraph!</p>
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I am working on a project where I have several hundred spans next to each other, with a letter of the text in each span. When I hover over one of the spans, I want to hide it, as well as the other spans nearby.
It makes an image like this:
##############
##############
##############
##############
My goal is to hide all of the spans in a given distance away from the mouse, like this:
HTML
<span id="overlay-1">#</span>
<!-- ... -->
<span id="overlay-142">#</span>
<span id="overlay-143">#</span>
I'm able to hide 1 of the spans by calling their ids on mouseover and changing the style to display=none, but I want to hide all that are in close proximity to the mouse. Any ideas on what I should do?
I tried to solve this through JS. Here is my code:
function paint() {
let txt = "";
for (let j = 0; j < 100; j++) {
txt += "<div>"
for (let i = 0; i < 100; i++) {
txt += `<span onmouseout="hoverOut()" onmouseover="hover(this)" onmouseuop id="overlay-${i}-${j}">#</span>`
}
txt += "</div>"
}
document.getElementById('painting').innerHTML += txt
}
function hover(x) {
let id = x.id;
let i = x.id.split('-')[1];
let j = x.id.split('-')[2];
for (let a = -2; a <= 2; a++) {
for (let b = -1; b <= 1; b++) {
const elem = document.getElementById(`overlay-${i-a}-${j-b}`);
elem ? elem.style.opacity = 0 : null;
}
}
x.style.opacity = '0';
}
function hoverOut() {
for (let i = 0; i < document.getElementsByTagName('span').length; i++) {
document.getElementsByTagName('span')[i].style.opacity = 1;
}
}
<body onload="paint()">
<div id="painting">
</div>
</body>
Another approach without using ids would be to use Element.getBoundingClientRect() to get the size and position of the hovered element and then use Document.elementFromPoint() inside a loop to access elements near the hovered one:
const main = document.querySelector('main')
for (let i = 0; i < 800; i++) main.innerHTML += '<span>#</span>'
const spans = document.querySelectorAll('span')
const areaWidth = 50
const areaHeight = 50
const hidden = []
function getElements(currentSpan, color) {
const { top, right, bottom, left, width, height } = currentSpan.getBoundingClientRect()
for (let col = left - areaWidth / 2; col < right + areaWidth / 2; col += width || 14) {
for (let row = top - areaHeight / 2; row < bottom + areaHeight / 2; row += height || 14) {
const el = document.elementFromPoint(col, row)
if (el?.tagName === 'SPAN') {
el.style.color = color
hidden.push(el)
}
}
}
}
spans.forEach(span => {
span.addEventListener('mouseover', () => getElements(span, 'transparent'))
span.addEventListener('mouseout', () => {
hidden.forEach(el => (el.style.color = ''))
hidden.length = 0
})
})
main {
display: flex;
flex-wrap: wrap;
width: 640px;
cursor: default;
}
<main></main>
You could use a CSS solution - overwrite the adjacent characters with a pseudo element on the clicked character.
This snippet uses a monospace font and it's set line height and letter spacing as CSS variables so you can alter them as required.
function clicked(ev) {
ev.target.classList.add('obscure');
}
const container = document.querySelector('.container');
for (let i = 0; i < 200; i++) {
const span = document.createElement('span');
span.innerHTML = '#';
if (i % 10 == 0) {
container.innerHTML += '<br>';
}
container.appendChild(span);
}
container.addEventListener('click', clicked);
.container {
width: 50vw;
height: auto;
font-family: Courier, monospace;
--line-height: 20px;
--letter-spacing: 5px;
line-height: var(--line-height);
letter-spacing: var(--letter-spacing);
}
.container span {
position: relative;
margin: 0;
padding: 0;
}
.obscure::before {
content: '';
width: calc(5ch + (6 * var(--letter-spacing)));
height: calc(3 * var(--line-height));
background-color: white;
position: absolute;
top: 0;
transform: translate(calc(-50% + 0.5ch), calc(-50% + (1ch)));
left: 0;
z-index: 1;
display: inline-block;
}
<body>
<div class="container"></div>
</body>
If I understand you right, you want the span to vanish, but you don't want its space to also vanish. display:none is the wrong solution. you need visibility:hidden.
hiding the hovered element and elements before and after it is easy. the difficulty is in hiding element that are above or below it.
to do that, you would need to do some math.
assuming the answer doesn't need to be exact, you could do it something like this:
calculate the centre positions of all spans and keep them in an array (so you don't need to recalculate every time)
when a span is mouse-entered, check the array and calculate all spans that are within radius r of that span's centre point - or just above/below/left/right - whatever works.
create a new array of spans that should be hidden
check all hidden spans - if any of them are not in that new array, unhide them (visibility:visible)
finally, go through the new array and set visibility:hidden on all spans in that array
Here is a bit diffrent and custumisable aproch:
// Variables
const ROW = 10; // Total number of rows
const COL = 35; // Total number of items in a row (i.e. columns)
const RANGE = 2; // Total number of items to be selected in each direction
const values = []; // To colect ids of items to be selected
// Utility Function
const push = (value) => {
if (value > 0 && value <= ROW * COL && !values.includes(value)) values.push(value);
};
// Add items in the root div
const root = document.querySelector("#root");
for (let i = 0; i < ROW; i++) {
root.innerHTML += `<div id="row-${i + 1}"></div>`;
for (let j = 0; j < COL; j++) {
document.querySelector(`#row-${i + 1}`).innerHTML += `<span id="item-${COL * i + (j + 1)}">#</span>`;
}
}
// Add class to the items as per the RANGE
root.addEventListener("mouseover", (e) => {
values.length = 0;
const id = e.target.id;
if (!id.includes("item-")) return;
const current = +id.replace("item-", "");
push(current);
for (let i = -RANGE; i < RANGE; i++) {
push(current + i);
for (let j = -RANGE; j <= RANGE; j++) {
push(current + COL * i + j);
push(current - COL * i + j);
}
}
for (let i = 0; i < values.length; i++) {
const item = document.querySelector(`#item-${values[i]}`);
item.classList.add("selected");
}
});
// Remove class from the items as per the RANGE
root.addEventListener("mouseout", () => {
for (let i = 0; i < values.length; i++) {
const item = document.querySelector(`#item-${values[i]}`);
item.classList.remove("selected");
}
});
/* Just for styling purposes */
body {
background-color: #111;
color: #fff;
}
#root [id*="item-"] {
padding: 1px;
}
/* Styles for the selected item */
#root [id*="item-"].selected {
/* color: transparent; */ /* 👈 Use this to get your intended effect */
color: #ffa600;
}
<div id="root"></div>
I'm trying to make a simple Javascript pagination function, but I'm having this issue where instead of iterating through the array, it keeps adding new list items to the innerhtml.
I have tried creating an element and appending it to the DOM.
I have tried using if/else statements to display the list items I
want.
<body>
<div class='result'></div>
<button class="add">+</button>
<script src='pretty.js'></script>
</body>
let dogs = [
'goldendoodle',
'poodle',
'afghan hound',
'golden retriever',
'labrador',
'chihuahua',
'pitbull',
'german shepherd',
'greyhound',
'bull terrier'
]
let high = 1;
let low = 0;
let result = document.querySelector('.result');
let add = document.querySelector('.add');
function Pagination(low,high) {
for(var i = 0 ; i < dogs.length;i++) {
let answer = document.createElement('div');
answer.classList.add('dogs-dom');
answer.innerHTML = dogs[i];
result.appendChild(answer);
if(i >= low && i < high) {
answer.style.display ='block';
}
if(i < low || i > high) {
answer.style.display ='none';
}
}
}
Pagination(low,high);
add.addEventListener('click', () => {
low += 2;
high += 2;
Pagination(low,high);
});
When I click the button, I want the next two array items to appear and replace the last two shown.
To use the approach you've outlined above you'll need to clear the innerHtml of the result element before appending new children. At the top of your Pagination function try result.innerHtml = '';.
That said if you are using a hide/show approach to paginate the list it would be more efficient to create the dom elements only once and modify the style.display property of each instead of clearing out the result and re-creating all of the answer divs on every click.
Your Pagination function only adds elements to the dom each time it is called.
You can either remove the existing elements every time Pagination is called, and render only those that should be displayed, e.g.:
function Pagination(low,high) {
result.innerHTML = ''; // remove all children of result
// only render the children which should be visible
for(var i = low ; i < high;i++) {
let answer = document.createElement('div');
answer.classList.add('dogs-dom');
answer.innerHTML = dogs[i];
result.appendChild(answer);
}
}
Or you can use display: block; / display: none. (Will not scale very well with large lists)
function Pagination(low,high) {
// only append all dogs once
if(result.childElementCount === 0) {
for(var i = 0; i < dogs.length;i++) {
let answer = document.createElement('div');
answer.classList.add('dogs-dom');
answer.style.display ='none';
answer.innerHTML = dogs[i];
result.appendChild(answer);
}
}
// toggle display: none / block for each element
for(var i = 0; i < dogs.length;i++) {
if(i >= low && i < high)
answer.style.display ='block';
else
answer.style.display ='none';
}
}
As a bonus, heres a reusable pagination class example:
function Pagination(container, items) {
this.container = container;
this.result = container.querySelector('.result');
this.prevBtn = container.querySelector('.prev');
this.nextBtn = container.querySelector('.next');
this.items = items;
this.offset = 0;
this.limit = 5;
this.updateDom();
this.prevBtn.onclick = this.prevPage.bind(this);
this.nextBtn.onclick = this.nextPage.bind(this);
}
Pagination.prototype.nextPage = function() {
if((this.offset + this.limit) < this.items.length)
this.offset += this.limit;
this.updateDom();
};
Pagination.prototype.prevPage = function() {
if(this.offset >= this.limit)
this.offset -= this.limit;
this.updateDom();
};
Pagination.prototype.updateDom = function() {
this.result.innerHTML = '';
let stop = Math.min(this.offset + this.limit, this.items.length);
for(let i = this.offset; i < stop; i++) {
let el = document.createElement("div");
el.appendChild(document.createTextNode(this.items[i]));
this.result.appendChild(el);
}
let hasPrev = this.offset > 0;
if(hasPrev)
this.prevBtn.classList.remove('hide');
else
this.prevBtn.classList.add('hide');
let hasNext = (this.offset + this.limit) < this.items.length;
if(hasNext)
this.nextBtn.classList.remove('hide');
else
this.nextBtn.classList.add('hide');
};
let items = [];
for (let i = 1; i <= 50; i++)
items.push(`Item ${i}`);
let pagination = new Pagination(document.querySelector(".paginate"), items);
// You can also programatically switch to the next / prev page:
// pagination.nextPage();
// pagination.prevPage();
.hide { visibility: hidden; }
<div class="paginate">
<div class="result"></div>
<button class="prev">PREV</button>
<button class="next">NEXT</button>
</div>
Maybe this is along the lines of what you want to do?
It tracks only a globalIndex (which would be like like your 'low' variable).
The showNextTwoItems function:
- Notes the indexes where we should start and end
- Clears the container div
- Enters a while loop that appends items and increments the current index
- Updates the globalIndex when enough items have been added
let dogs = [ 'goldendoodle', 'poodle', 'afghan hound', 'golden retriever', 'labrador', 'chihuahua', 'pitbull', 'german shepherd', 'greyhound', 'bull terrier' ],
containerDiv = document.querySelector('.result'),
addBtn = document.querySelector('.add'),
globalIndex = 0; // Tracks where we left off (starts at zero)
const NUMBER_TO_SHOW = 2;
addBtn.addEventListener("click", showNextTwoItems); // Calls function on click
function showNextTwoItems(){
let numberToShow = NUMBER_TO_SHOW, // In case we ever want to change numberToShow
currentIndex = globalIndex, // Gets local copy of globalIndex (always < dogs.length)
// Lets us stop looping when we've shown enough or reach the end of the array
stopBeforeIndex = Math.min(currentIndex + numberToShow, dogs.length);
containerDiv.innerHTML = ""; // Clears div
while(currentIndex < stopBeforeIndex){
// Creates and appends a text node with the next dog
const newItem = document.createTextNode(dogs[currentIndex]);
containerDiv.appendChild(newItem);
// Creates and appends a line break
const lineBreak = document.createElement("BR");
containerDiv.appendChild(lineBreak);
// Moves on to the next index
currentIndex++;
}
// Updates global index (making sure it is not too big for the array)
globalIndex = currentIndex < dogs.length ? currentIndex : 0;
}
<button class="add">+</button>
<div class='result'></div>
This is working fine using the document.getElementsByID, but how do you change all the p tags with a prgrph class to code so that instead of <p class="prgrph"></p> there will be <code class="prgrph"></code>?
var b = document.querySelectorAll('p');
for (var i = 0; i < b.length; i++) {
b[i].setAttribute('id', 'prgrph');
}
But this is not working:
function changeTagName(el, newTagName) {
var n = document.createElement(newTagName);
var attr = el.attributes;
for (var i = 0, len = attr.length; i < len; ++i) {
n.setAttribute(attr[i].name, attr[i].value);
}
n.innerHTML = el.innerHTML;
el.parentNode.replaceChild(n, el);
}
changeTagName(document.getElementsByClassName('prgrph'), 'code');
I tried to use document.getElementsByClassName and it's giving me error on the attr.length:
Uncaught TypeError: Cannot read property 'length' of undefined
IDs need to be unique and you likely want to change the P tags one by one
I am not sure why you first loop over the P tags and then loop again; the first loop is not really needed if the second loop selects the P tag instead of the class
var b = document.querySelectorAll('p');
for (var i = 0; i < b.length; i++) {
b[i].classList.add('prgrph');
}
function changeTagName(el, newTagName) {
var n = document.createElement(newTagName);
var attr = el.attributes;
for (var i = 0, len = attr.length; i < len; ++i) {
n.setAttribute(attr[i].name, attr[i].value);
}
n.innerHTML = el.innerHTML;
el.parentNode.replaceChild(n, el);
}
document.querySelectorAll(".prgrph").forEach(function(p) { // not IE
changeTagName(p, 'code');
})
code {
color: red
}
<p data-attr="one">Paragraph 1</p>
<p data-attr="two">Paragraph 2</p>
<p>Paragraph 3</p>
The code below is for listing blogger posts within a Label Name, if the post has the specific Label Name it will be shown in this list. I would like to be able to change the appearance of how everything is displayed by changing where the post image would look, and where the title would look, change background color, add borders, shadows change the font etc ...(I know how to change the appearance with css, but I do not know how to integrate the code below with css and html) At the moment the code shows the title and the right of the title the image.
var startIndex = 1;
var maxResults = 5;
var allResults = [];
function sendQuery12()
{
var scpt = document.createElement("script");
scpt.src = "https://levon-ltr.blogspot.com//feeds/posts/summary?alt=json&callback=processPostList12&start-index=" + startIndex + "&max-results=" + maxResults;
document.body.appendChild(scpt);
}
function printArrayResults(root)
{
//Sort Alphebetically
allResults.sort(function(a, b){
var a_string = a.children[0].textContent ;
var b_string = b.children[0].textContent ;
if(a_string < b_string) return -1;
if(a_string > b_string) return 1;
return 0;
})
var elmt = document.getElementById("postList12");
for (index = 0; index < allResults.length; index++) {
elmt.appendChild(allResults[index]);
}
}
function processPostList12(root)
{
var elmt = document.getElementById("postList12");
if (!elmt)
return;
var feed = root.feed;
if (feed.entry.length > 0)
{
for (var i = 0; i < feed.entry.length; i++)
{
var entry = feed.entry[i];
var title = entry.title.$t;
var date = entry.published.$t;
if( entry.media$thumbnail != undefined ){
var imageThumb = entry.media$thumbnail.url ;
} else {
var imageThumb = 'https://i.imgur.com/PqPqZQN.jpg' ;
}
for (var j = 0; j < entry.link.length; j++)
{
if (entry.link[j].rel == "alternate")
{
var url = entry.link[j].href;
if (url && url.length > 0 && title && title.length > 0)
{
var liE = document.createElement("li");
var a1E = document.createElement("a");
var postImage = document.createElement("img");
a1E.href = url;
a1E.textContent = title;
postImage.src = imageThumb;
liE.appendChild(a1E);
liE.appendChild(postImage);
//elmt.appendChild(liE);
allResults.push(liE);
}
break;
}
}
}
if (feed.entry.length >= maxResults)
{
startIndex += maxResults;
sendQuery12();
} else {
printArrayResults();
}
}
}
sendQuery12();
<div>
<ul id="postList12"></ul>
</div>
This creates stuff you can style with CSS. For example:
#postList12 li {
border: 1px solid blue;
}
Use the inspector in your browser to see what it makes. If you want to change the order of elements or add new ones you’ll have to edit the script to do that.
I have this in html
<div id="content">
<h1 class="entry-title">"Homepage SlideShow"</h1>
</div>
I also have this in js
var content = document.getElementById("content");
var entryTitle = content.getElementsByClassName('entry-title')[0];
var str = entryTitle.innerHTML;
var newTitle = "";
for (var i = 0; i < str.length; i++) {
if (str[i] == 'e') {
newTitle += str.charAt(i).fontcolor("red");
}
else {
newTitle += str[i];
}
}
entryTitle.innerHTML = newTitle;
I added a color on the targeted letter but I don't have an idea how to add a margin. I want to add margin on the targeted letter like margin = -20px;. I'm new to javascript and I'm hoping someone could help. Thanks
Here's my JSFiddle
Edit:
I have this font that doesn't look good on letter spacing. I don't want to use a span class in my html since I don't want to do it manually on every single page or post that I make.
For example: I want to move all i's to the left since it has the same spacing in any word.
Append with some span element.Then apply the style for that span element using inline style or class name with css
var entryTitle = document.getElementsByClassName('entry-title')[0];
var str = entryTitle.innerHTML;
var newTitle = "";
for (var i = 0; i < str.length; i++) {
if (str[i] == 'e') {
newTitle += '<span class="add">' + str[i] + '</span>'
} else {
newTitle += str[i];
}
}
entryTitle.innerHTML = newTitle;
.add{
/*add your style here*/
color:red;
margin:-20px;
}
<h1 class="entry-title">"Homepage SlideShow"</h1>
var content = document.getElementById("content");
var entryTitle = content.getElementsByClassName('entry-title')[0];
var str = entryTitle.innerHTML;
var newTitle = "";
for (var i = 0; i < str.length; i++) {
if (str[i] == 'e') {
newTitle += "<span style='margin: 20px;'>" + str.charAt(i).fontcolor("red") + "</span>";
} else {
newTitle += str[i];
}
}
entryTitle.innerHTML = newTitle;
<div id="content">
<h1 class="entry-title">"Homepage SlideShow"</h1>
</div>
You can accomplish this with the CSS property letter-spacing apply on a <span> markup.
Here my jsfiddle bro --> http://jsfiddle.net/f6zn0svk/
.letter-spacing { letter-spacing: 10px; }
<h1 class="entry-title">"Hom<span class="letter-spacing">ep</span>age SlideShow"</h1>