Dynamically Created HTML object not having CSS applied to it - javascript

Final product: Web page that is filled in by data on a word document which is fed into a recurring HTML structure.
Problem: When ran, the HTML elements are created, but the CSS classes are not applied until the window is resized.
Javascrip:
for (i=0; i<=timeline_data.length; i++){
var newParent = document.getElementById('wgt-timeline-bdy-wrap-id');
var newItem = document.createElement('div');
newParent.appendChild(newItem);
newItem.setAttribute('class','wgt-timeline-bdy-item');
var newText = document.createElement('p');
newItem.appendChild(newText);
newText.setAttribute('class','timeline-new-text');
newText.id="timeline-" + timeline_data[i].id + "-text";
}
CSS:
.wgt-timeline-bdy-item {
display: inline-block;
font-size: 20px;
position: relative;
text-align: center;
vertical-align: middle;
width: 100%;
}
.timeline-new-text{
font-size: 30px;
position: relative;
top:40px;
}
Nothing unexpected in the HTML, wgt-timeline-bdy-wrap-id is a div.
Thank you in advance for your help

try appending to the DOM as the last thing you do in the loop (i.e after you have set the class). Also, most places I've done this through element.className = 'xxx' rather than using the setAttribute() function; not sure that matters, though.

Try writing a jQuery function to apply the CSS styles once the for loop is done executing. Something like this:
for{...}
styleelements();
function styleelements(){
$(".wgt-timeline-bdy-item").css({...});
$(".timeline-new-text").css({...});
}

Related

CSS pseudo class disappears after variable value update via JS

I would like to be able to update a CSS variable via JS, but when I make the variable update the CSS pseudo element get's destroyed (i.e. just disappears).
Here's the SCSS code:
:root {
--test-thing: "";
}
.folder-1-open span::after {
width: 90%;
height: 85%;
bottom: 0;
left: 5%;
background-color: #fff;
z-index: 3;
content: var(--test-thing);
}
I'm trying to manipulate the variable thusly:
const root = document.documentElement
root.style.setProperty('--test-thing', "Hello World")
The CSS above works perfectly fine on the element (a label) that it's applied to, basically just a white square, but as soon as I try and update the CSS variable --test-thing to add a string via the content prop, the whole thing just disappears.
Is it not possible to do this with a pseudo element or class?
From researching related posts on SO, my understanding was that this was possible using CSS variables.
For context, I’m working off this example of a pure CSS interactive folder (when it’s open is when I’d like to update content proper dynamically).
Ok, I figured out why this is happening, sort of. Still not 100% sure why, but it has something to do with the fact that the new value isn't in quotes. Just put the value in quotes and it works fine.
const root = document.documentElement
root.style.setProperty('--test', "'Hello World'") // <-- this needs to be in quotes
:root {
--test: "";
}
#test {
height: 100px;
width: 100px;
background: #ccc;
}
#test:after {
content: var(--test);
min-width: 100px;
background: #000;
min-height: 30px;
color: #fff;
}
<div id="test">
</div>

JS Hover Over One Item to Make Another Move

I've got a simple text button with an image of an arrow next to it. I'm wanting the arrow image to move when someone hovers over the button.
I currently have this working in one instance with JS 'document.getElementById...', but I have several buttons across my site that I'd like to have the same behavior. My first thought would be to use a class instead of an id, and use the same functions.
For whatever reason, document.getElementsByClassName doesn't work - even in one instance.
Here's a simpler version to demonstrate - View on Codepen: https://codepen.io/sdorr/pen/JxYNpg
HTML
<HTML>
hover over me
<div id="block"></div>
hover over me
<div class="block"></div>
CSS
* {
margin: 0;
padding: 0;
}
.button {
color: #000000;
text-decoration: none;
background-color: cyan;
margin: 0;
display: block;
width: 300px;
padding: 20px;
text-align: center;
}
#block {
width: 30px;
height: 30px;
background-color: red;
}
.block {
width: 30px;
height: 30px;
background-color: green;
}
JS
function move() {
document.getElementById("block").style.marginLeft = "35px";
}
function moveBack() {
document.getElementById("block").style.marginLeft = "0px";
}
function moveAlt() {
document.getElementsByClassName("block").style.marginLeft =
"35px";
}
function moveBackAlt() {
document.getElementsByClassName("block").style.marginLeft =
"0px";
}
First off, why isn't the behavior with a class working but an id works fine?
Secondly, would a class solve this issue and be scalable across all buttons with the same two functions (onmouseover / onmouseout)?
If not, any ideas on a solution? I currently have a solution I found using jQuery that does work, but when hovering over one button, all arrow images move across the site. I don't necessarily mind this behavior because only one button is really in view at a time - but I'm trying to learn JS and solve problems with my own solutions!
I greatly appreciate your desire to learn on your own and not rely on premade solutions. Keep that spirit and you will go places!
When it comes to getElementsById, we know this should work for one element, since the function returns a single Element.
However, what does getElementsByClassName return?
(see: https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName)
It returns an HTMLCollection which you can iterate over to change an single element's style.
So, to get this to work with JavaScript you need to write a function that will be able to identify the particular div.block you want to move. But, this puts you back to where you started, needing some particular identifier, like an id or a dataset value to pass to the function.
Alternately, based on the HTML structure you provide, you could look for nextElementSibling on the a that get's clicked. But I would set up an eventListener rather than adding a JS function as a value to the onmouseenter property.
const btns = document.getElementsByTagName('a');
/*** UPDATE forEach is a NodeList method, and will fail on HTMLCollection ***/
/* this fails -> Sorry! ~~btns.forEach(button=>{~~
/* the following will work
/**********/
for (let i = 0; i < btns.length; i++){
btns[i].addEventListener('mouseenter', function(e) {
//we pass e to the function to get the event and to be able to access this
const block = this.nextElementSibling;
block.style.marginLeft = "35px";
})
btns[i].addEventListener('mouseleave', function(e) {
const block = this.nextElementSibling;
block.style.marginLeft = "0";
})
}
But with siblings, there is a CSS-only solution.
We can use the Adjacent Sibling Selector combined with the :hover state selector and no JavaScript is needed, if we are just moving back and forth.
.button:hover+.block {
margin-left: 35px;
}
See the Snipped Below
* {
margin: 0;
padding: 0;
}
.button {
color: #000000;
text-decoration: none;
background-color: cyan;
margin: 0;
display: block;
width: 300px;
padding: 20px;
text-align: center;
}
.block {
width: 30px;
height: 30px;
background-color: green;
}
.button:hover+.block {
margin-left: 35px;
}
hover over me
<div class="block"></div>
hover over me
<div class="block"></div>
As Vecta mentioned, getElementsByClassName returns an array-like. You'll need to do something like this to get the first element:
function moveAlt() {
document.getElementsByClassName("block")[0].style.marginLeft = "35px";
}
function moveBackAlt() {
document.getElementsByClassName("block")[0].style.marginLeft = "0px";
}
However a better solution might be to use document.querySelector, which operates similarly to jQuery's $() syntax:
function moveAlt() {
document.querySelector(".block").style.marginLeft = "35px";
}
function moveBackAlt() {
document.querySelector(".block").style.marginLeft = "0px";
}

Create and Display a Div using JQuery without distorting other elements

I am trying to create a div and show a timeout message in there. But it actually distorts other parts of Page. For eg see below. Session Timed out is the div with the message.
Now I don't want this to happen. PFB the JQuery code I am using to create this Div
function ShowSessionTimeOutDiv() {
var styler = document.createElement("div");
styler.setAttribute("style","font-size:15px;width:auto;height:auto;top:50%;left:40%;color:red;");
styler.innerHTML = "<b><i>Session TimedOut, Please refresh the Page</i></b>";
document.body.appendChild(styler);
var currentDiv = $('#GoToRequestControl1_UpdatePanel1').get(0);
currentDiv.parentNode.insertBefore(styler,currentDiv) ;
}
Am I missing something here? The Part in which this div is being displayed is coming from Master Page.
Have you tried the position:fixed styling on it in css, i did that on one of my websites and it didn't distort anything.
A page has a natural flow of its elements based on the default display rules specified by the W3C. When you add a div in between other elements it naturally affects the layout of the page; the positions of the other elements.
In order to drop in a new element without it affecting other elements you have to either reserve space for it, or take it out of the normal page flow.
There are a couple of ways to take an element out of the flow — you can float it, float:left or float:right, which is great, for example, to stack blocks on the left (instead of top-down) and let them wrap to new rows as available width changes. Using a flex layout gives you a lot of control also. But in this case of one thing popping up, changing the positioning of the new element is the most straightforward and can let you put the block exactly where you want it.
I have a demonstration and full explanation in a fiddle showing several examples along the way to getting what you want.
Basically, styling is needed to reposition the timeout message element that you're inserting. Styling is better done with CSS styles, compared to adding a bunch of inline styles. If I put my timeout popup message in a "messagebox" I can make a class for it.
/* Your styles, plus a couple extra to make the example stand out better */
div.messagebox {
font-size: 16px;
width: auto;
height: auto;
top: 40%;
left: 30%;
background-color: white;
border: 2px solid black;
}
Likewise, style the message itself with a class, instead of using inline styles and the deprecated presentational tags <b> and <i>.
/* I want the message in a messagebox to be bold-italic-red text. */
div.messagebox .message {
color: red;
font-style: italic;
font-weight: bold;
}
The big difference is that we will change the positioning of the element from the default static to instead use absolute positioning:
/* I don't really recommend a class called "positioned".
A class should describe the kind of thing the element *is*
not how it *looks*
*/
div.messagebox.positioned {
position: absolute;
width: 40%;
padding: 1.5em;
}
/* The container of the positioned element also has to be positioned.
We position it "relative" but don't move it from its natural position.
*/
section#hasposition {
position: relative;
}
The term "absolute" is tricky to learn ... the element being positioned is given an absolute position within its container, in a sense it's positioned relative to its container... but what position:relative means is relative to its own natural position, so it's easy to get confused at first over whether you want absolute or relative positioning.
Putting it all together, we have some basic HTML that represents major portions of a page — a real page will have far more, but those should be contained within some top-level containers. This shows only those top-level containers.
Then we have some javascript that will add the new element at the appropriate time. Here I just call the function to add it after a delay created with setTimeout(). I'm using full-on jQuery since you're using some in your example, and it makes the javascript more portable and more concise.
function ShowSessionTimeoutStyled() {
var styler = $('<div>').addClass('messagebox').addClass('positioned');
styler.html('<span class="message">The Session Timed Out</span>');
$('#hasposition .above').after(styler);
}
// wait 6 seconds then add the new div
setTimeout(ShowSessionTimeoutStyled, 6000);
div.messagebox {
font-size: 16px;
width: auto;
height: auto;
top: 20%;
left: 20%;
background-color: white;
border: 2px solid black;
}
div.messagebox .message {
color: red;
font-style: italic;
font-weight: bold;
}
div.messagebox.positioned {
position: absolute;
width: 40%;
padding: 1.5em;
}
section#hasposition {
position: relative;
}
/* also style some of the basic parts so you can see them better in the demonstration */
section.explanation {
margin: 1em 0.5em;
padding: 0.5em;
border: 1px solid gray;
}
.demonstration {
margin-left: 1em;
padding: 1em;
background-color: #e0e0e0;
}
.demonstration .above {
background-color: #fff0f0;
}
.demonstration .middle {
background-color: #f0fff0;
}
.demonstration .below {
background-color: #f0f0ff;
}
.demonstration footer {
background-color: white;
}
p {
margin-top: 0;
padding-top: 0;
}
section {
font-family: sans-serif;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="explanation">
<p>Here, a div is added dynamically, after the "basic part above", but the added div is <em>positioned</em>. You can see the other content isn't affected.</p>
<section class="demonstration" id="hasposition">
<div class="above">Basic part above</div>
<div class="middle">Middle part</div>
<div class="below">Part Below</div>
<footer>This is the page footer</footer>
</section>
</section>
I highly recommend the site Position Is Everything for articles and tutorials on positioning. Some of its other content is outdated — who needs to make PNGs to do drop-shadows any more? — but the way positioning works hasn't changed.

alignment issue of div tag

I am trying to create a web page where on click of a button I can add div tags. What I thought to do was that I'll create two div tags within a single div so that over all presentation will be uniform and similar to a table having two columns and multiple rows and the first column contains only label's and second column will contain textbox.
Here is the JS file:
var counter = 0;
function create_div(type){
var dynDiv = document.createElement("div");
dynDiv.id = "divid_"+counter;
dynDiv.class="main";
document.body.appendChild(dynDiv);
question();
if(type == 'ADDTEXTBOX'){
ADDTEXTBOX();
}
counter=counter+1;
}
function question(){
var question_div = document.createElement("div");
question_div.class="question";
question_div.id = "question_div_"+counter;
var Question = prompt("Enter The Question here:", "");
var node=document.createTextNode(Question);
question_div.appendChild(node);
var element=document.getElementById("divid_"+counter);
element.appendChild(question_div);
}
function ADDTEXTBOX(){
var answer_div = document.createElement("div");
answer_div.class="answer";
answer_div.id = "answer_div_"+counter;
var answer_tag = document.createElement("input");
answer_tag.id = "answer_tag_"+counter;
answer_tag.setAttribute("type", "text");
answer_tag.setAttribute("name", "textbox");
answer_div.appendChild(answer_tag);
var element=document.getElementById("divid_"+counter);
element.appendChild(answer_div);
}
Here is the css file:
.question
{
width: 40%;
height: auto;
float: left;
display: inline-block;
text-align: justify;
word-wrap:break-word;
}
.answer
{
padding-left:10%;
width: 40%;
height: auto;
float: left;
overflow: auto;
word-wrap:break-word;
}
.main
{
width: auto;
background-color:gray;
height: auto;
overflow: auto;
word-wrap:break-word;
}
My problem is that the code is working properly but both the divisions are not coming in a straight line. after the first div prints on the screen the second divisions comes in another line. How can I make both the div's come in the same line?
PS: should I stick with the current idea of using div or should I try some other approach? like tables?
The reason its in diffrent lines lies in your JS code, try setting your class like following:
//question_div.class="question";
question_div.setAttribute("class", "question") ;
and
//answer_div.class="answer";
answer_div.setAttribute("class", "answer");
and also this:
//dynDiv.class="main";
dynDiv.setAttribute("class", "main");
Your divs have not class attribute set properly. I recommend chrome in-built tools for developers or FireBug add-on if you use Firefox to check whether elements you built are like you design them to be.
You may check code here: http://jsfiddle.net/Nnwbs/2/
var counter = 0;
function create_div(type){
var dynDiv = document.createElement("div");
dynDiv.id = "divid_"+counter;
//dynDiv.class="main";
dynDiv.setAttribute("class", "main");
document.body.appendChild(dynDiv);
question();
if(type == 'ADDTEXTBOX'){
ADDTEXTBOX();
}
counter=counter+1;
}
function question(){
var question_div = document.createElement("div");
//question_div.class="question";
question_div.setAttribute("class", "question") ;
question_div.id = "question_div_"+counter;
var Question = prompt("Enter The Question here:", "");
var node=document.createTextNode(Question);
question_div.appendChild(node);
var element=document.getElementById("divid_"+counter);
element.appendChild(question_div);
}
function ADDTEXTBOX(){
var answer_div = document.createElement("div");
//answer_div.class="answer";
answer_div.setAttribute("class", "answer");
answer_div.id = "answer_div_"+counter;
var answer_tag = document.createElement("input");
answer_tag.id = "answer_tag_"+counter;
answer_tag.setAttribute("type", "text");
answer_tag.setAttribute("name", "textbox");
answer_div.appendChild(answer_tag);
var element=document.getElementById("divid_"+counter);
element.appendChild(answer_div);
}
create_div("ADDTEXTBOX");
​And about that aproach I mean div or tables, you are correct to use div, its generaly recommended to do so.
Also after you correct your JS code fix also a bit your css styles as you like.
If you are using chrome using inspect element and find the corresponding 'div' tag and try to adjust the style(position)
Try to position both Divs with absolute inside a main div that could be relative. something like
#mainDiv {
position:absolute; /* or relative depends how you have it*/
width:80%;
height:100%;
left:10%;
}
#div1 {
position:absolute;
width: 40%;
height:100%;
left:0px;
top:0px;
}
#div2 {
position:absolute;
width: 40%;
height:100%;
right:0px;
top:0px;
}
It's simple. To line up both div's, give the position of of the two div's as display:inline-block;
display:inline-block;
Note: BOTH div's have to have this property for them to appear in a line.

javascript: insert large CSS string in one go, into every DOM element

This is a two part question - first I need to get every element that is a child (or subchild, etc) of a parent element, and then I need to reset it's style. As such, I'm looking to do something like the following:
var everything = parent.getEveryElementBelowThisOne();
for (i=0; i<everything.length; i++)
everything[i].css = "font: 100%/100% Verdana,Arial,Helvetica,sans-serif; color: rgb(0, 0, o); margin: 0px; padding: 0px; border-collapse: collapse; border-width: 0px; border-spacing: 0px; text-align: left; outline: 0pt none; text-transform: none; vertical-align: middle; background-color: transparent; table-layout: auto; min-width: 0px; min-height: 0px;"
So my questions are as follows:
Is there a javascript function that will effectively walk through the DOM below a given element?
Is there a javascript function that will let me set a CSS string like that? Or do I have to have a whole bunch of entries like:
everything[i].style.font = ...;
everything[i].style.color = ...;
[...]
everything[i].style.min-height: ...;
jQuery is not an option.
Instead of a string, I would use an object, much more readable and maintainable:
var new_css = {
font: '100%/100% Verdana,Arial,Helvetica,sans-serif',
color: 'rgb(0, 0, o)',
margin: '0px',
padding: '0px',
borderCollapse: 'collapse'
/* rest here ... */
}
Then use a helper function, something like:
function setStyle (element, style) {
for (var n in style) {
element[n] = style[n];
}
}
and into your for loop:
for (i=0; i<everything.length; i++) setStyle(everything[i],new_css);
A note about the setStyle function (before people downvote me for this like last time), I purposely did not use a hasOwnProperty to check the elements of style because in this case, and in most cases we are using an object not inherited from anything. If you construct your new_css object any other way or if you use a library (prototype, I'm looking at you) that modify Object's prototype which may cause problems then feel free to add the hasOwnProperty check. Anyway, setting nonexistent style values are mostly harmless. And without a hasOwnProperty check you can use inheritence to compose style objects.
Use myElement.style.cssText:
var everything = parent.getEveryElementBelowThisOne();
for (i=0; i<everything.length; i++)
everything[i].style.cssText = "font: 100%/100% Verdana,Arial,Helvetica,sans-serif; color: rgb(0, 0, o); margin: 0px; padding: 0px; border-collapse: collapse; border-width: 0px; border-spacing: 0px; text-align: left; outline: 0pt none; text-transform: none; vertical-align: middle; background-color: transparent; table-layout: auto; min-width: 0px; min-height: 0px;"
But note that this will override any inline style attributes already applied. To append extra inline css you should use:
myElement.style.cssText += '; color:red; ...'; // note the initial ";"
Its slightly offbeat, as when you talk of parent, we assume you would be considering its children at some point. But when you say, every element below this one then they may be DOM elements after the concerned element. Yours may be either of the case.
I assume you want to change style of next element siblings.
Using raw javascript, you can traverse in a generic looping way, as
nS = parent.nextElementSibling
while(nS){
nS.style.width = '100%';
// Change the desired style here
// You can also further loop on nS's children using `nS.childNodes`,
// if you want to change their styles too
nS = nS.nextElementSibling;
}
As you can see with raw javascript, the way to change styles is quite repelling.
On the other hand, jQuery gives good DOM feature.. including easy traversing, even styling.
Like, the same thing in jQuery would be.
$(parent).nextAll().each(function(){
$(this).css({'width': '100%', 'other': 'rules', 'as': 'one-dict'});
// Change the desired style here
// You can also further loop nS's children using `$(this).children()`,
// if you want to change their styles too
});
Hope this helps.

Categories