Retaining CSS when changing text dynamically with javascript - javascript

I've been trying to randomize a number with a button, but every time I clicked the button, the number randomizes, but the text loses it's CSS style.
CSS
.numberStyle {
padding: 10px 10px 10px 10px;
color: blue;
}
.numberStyle span {
font-size: 100px;
}
Html
<class id="number1" class="numberStyle"><span>1</span></class>
<input type="button" value="MATCH!" style="font-size:50px;"></input>
Javascript
function randomize() {
no1 = Math.ceil(Math.random() * 3);
}
function print() {
$("#number1").text(no1);
}
$().ready(function() {
$(":input").click(function() {
randomize()
print()
alert("Change")
})
})
my JSFiddle link : https://jsfiddle.net/he4rtbr0ken/9jfud4nz/2/

You want to change the text within the span rather than #number1
function print() {
$("span").text(no1);
}

You are targeting the parent of the <span> element and then changing its text which is essentially removing the span and replacing it with only the number. You can fix this by targeting the span or including the span in the text you are adding.

Thanks for the answer!
I've targeted <span> element and it works.
replaced print() function with the codes below.
function print() {
$("#number1 > span").text(no1);
}

Related

Get content based on CSS pseudo class

I have a CSS declaration as follows:
span.boshbashbosh:nth-child(1):active:after {
content: 'FC';
}
I am trying to access the content (FC) it by using:
var content = window.getComputedStyle(document.getElementsByClassName("boshbashbosh:nth")[0], '::active').getPropertyValue('content');
alert(content);
However, all the alert does is show normal or none
Any advice on how to do this in plain JS? If I had 1000 of these, I wouldn't want to click/hover each one, is there a way I could dump some code into the developer console to do this?
There are a few issues here, the main one being that the CSS selector will only return an active element during a click interaction by the user, seeing that a click interaction causes the target element to become :active.
With that in mind, you could wrap your login in a mousedown element as shown below to extract the expected content value while the corresponding span element is :active as shown:
document.addEventListener("mousedown", () => {
/* When mouse down occours, look for the element that we want to read
pseudo content from */
var element = document.querySelector(".boshbashbosh:nth-child(1):active");
if (element) {
/* If the target element is active, read the content of the ::after
pseudo element */
var content = window.getComputedStyle(element, ":after")
.getPropertyValue("content");
alert(content);
}
})
span.boshbashbosh:nth-child(1):active:after {
content: 'FC';
}
/* Added for clarity/usability of snippet */
span {
background: pink;
margin: 1rem 0;
padding: 1rem;
display: block;
height: 1rem;
}
span.boshbashbosh:active {
background: yellow;
}
<p>Clicking first box alerts the ::after content</p>
<div>
<span class="boshbashbosh"></span>
<span class="boshbashbosh"></span>
<span class="boshbashbosh"></span>
</div>
I've also replaced the getElementsByClassName() call with querySelector() to simplify the code. Hope that helps!
Update
To access the content of multiple pseduo elements, you could adapt the snippet above as follows:
document.querySelectorAll(".boshbashbosh").forEach((element) => {
var content = window.getComputedStyle(element, ":after")
.getPropertyValue("content");
console.log(content);
});
span.boshbashbosh:nth-child(1):after {
content: 'FC';
}
span.boshbashbosh:nth-child(2):after {
content: 'EB';
}
span.boshbashbosh:nth-child(3):after {
content: 'DA';
}
<div>
<span class="boshbashbosh"></span>
<span class="boshbashbosh"></span>
<span class="boshbashbosh"></span>
</div>

Place a button and its div with one command

Currently, I have a button class which lets me place a clickable button inside a sentence, and a div class which lets me add content to the button which I placed at the end of the paragraph containing the sentence.
This is an example of how I use them
Try to click <button class="col">THIS</button> and see what happens.
<div class="con">nice!</div>
Did you try?
When this text is displayed on the page, the two sentences are placed inside two different paragraphs, so the div object is placed between them.
Here is a snippet with the css classes and the javascript.
( function() {
coll = document.getElementsByClassName("col");
conn = document.getElementsByClassName("con");
var i;
for (i = 0; i < coll.length; i++) {
coll[i].setAttribute('data-id', 'con' + i);
conn[i].setAttribute('id', 'con' + i);
coll[i].addEventListener("click", function() {
this.classList.toggle("active");
var content = document.getElementById(this.getAttribute('data-id'));
if (content.style.maxHeight) {
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
});
}
} )();
.col {
cursor: help;
border-radius: 0;
border: none;
outline: none;
background: none;
padding: 0;
font-size: 1em;
color: red;
}
.con {
padding: 0 1em;
max-height: 0;
overflow: hidden;
transition: .3s ease;
background-color: yellow;
}
Try to click <button class="col">THIS</button> and see what happens.
<div class="con">nice!</div>
Did you try?
I wonder if it is possible to implement a shortcut to place the two objects with one command, that is to obtain the previous example by using something like this
Try to click [[THIS|nice!]] and see what happens.
Did you try?
What I mean is that the command [[THIS|nice!]] should place the object <button class="col">THIS</button> in the same position and the object <div class="con">nice!</div> at the end of the paragraph containing the command.
Is it possible to implement such a command (or a similar one)?
EDIT
I forgot to say that the content of the button, ie what is written inside the div, should also be possible to be a wordpress shortcode, which is a shortcut/macro for a longer piece of code or text.
Using jQuery, closest() find the nearest <p> element and add <div class="con">nice!</div> after <p> element. To toggle you can use class active and add or remove .con element.
$('.col').click(function(){
let traget = $(this).closest('p');
if(traget.hasClass('active')) {
traget.removeClass('active');
traget.next('.con').remove();
} else {
traget.addClass('active');
traget.after(`<div class="con">${$(this).data('message')}</div>`);
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Try to click <button class="col" data-message="Hello">THIS</button> and see what happens.</p>
<p>Did you try?</p>
You usually dont use div to type text. you use it to define areas or group items. you could obtain what youre asking for in a 1 sentence like this:
html
<h1> some random text <a class="btnID">button</> some more text<h1>
css
.btnID {
color: red;
}

Replace text inside HTML leaving other HTML intact with vanilla javascript

I'm trying to write pure javascript function to replace the text "Passed" to "Completed". The HTML inside the div#prompt should remain in tact and is variable. Here is the HTML -
<div id="prompt">
Passed
Take a survey
<button type="button" data-behavior="hide.prompt"></button>
</div>
I tried replacing text but that doesn't seem to be working
var text = document.getElementById('prompt').textContent;
text.replace("Passed", "Completed");
Also tried this -
var text = document.getElementById('prompt').innerHTML;
text.replace("Passed", "Completed");
What am I doing wrong? Appreciate the help!
replace does not mutate the string, it returns a new one. Strings are immutable.
var text = document.getElementById('prompt');
text.textContent = text.textContent.replace("Passed", "Completed");
Actually your element contains a text node that you can override:
document.getElementById('prompt').childNodes[0].textContent = "Completed";
Instead of replacing text, how about toggle a class on the outer div.
With that you can also customize its HTML as well.
Stack snippet
.prompt::before {
content: 'Passed';
}
.prompt.hidden::before {
content: 'Completed';
}
.prompt.hidden button {
display: none;
}
/* demo styles */
.prompt button { padding: 5px 20px; }
hr { margin: 20px 0; }
<div class="prompt">
Take a survey
<button type="button" data-behavior="hide.prompt"></button>
</div>
<hr>
<div class="prompt hidden">
Take a survey
<button type="button" data-behavior="hide.prompt"></button>
</div>

Dynamic mouseenter

I appended a few divs with inside img tags. Every tag has own unique id = "theImg"+i where "i" is number. I want to mouseover on specific img and show the content of span (which also have specific id with number). Here is my code so far but not working.
var j;
document.onmouseover = function(r) {
console.log(r.target.id);
j = r.target.id;
}
$(document).on({
mouseover: function(e){
$("span").show();
},
mouseleave: function(e){
$("span").hide();
}
}, "img#"+j);
If you have a span after every img, maybe it's a good idea to not use JavaScript at all? ;-)
You could use :hover pseudoclass in CSS, making your thing always work reliably.
Consider the following example:
img + span {
display: none;
}
img:hover + span {
display: block;
}
/*/ Optional styles /*/
div {
position: relative;
float: left;
}
div img + span {
position: absolute;
color: #fff;
background: #27ae60;
border: solid 1px #2ecc71;
border-radius: 50px;
z-index: 1;
bottom: 1em;
width: 80%;
left: 50%;
margin-left: -43%;
padding: 2% 3%;
text-align: center;
}
<div>
<img src="https://placehold.it/400x200">
<span>This is an image of a gray rectangle!</span>
</div>
<div>
<img src="https://placehold.it/200x200">
<span>This is an image of a gray square!</span>
</div>
<div>
<img src="https://placekitten.com/g/400/200">
<span>This is an image of a cute kitten inside a rectangle!</span>
</div>
<div>
<img src="https://placekitten.com/g/200/200">
<span>This is an image of even cuter kitten inside a square!</span>
</div>
So the issue is that you are trying to set your handler on a dynamic selector ("img#"+j) but this will not work. For one thing, that equation will be evaluated only once, on page load, when j is undefined.
So you want to do this instead:
target only img tags for your mouse over... Better yet, give your special images all the same css class so you can attach the event handlers only to those. That will be more efficient.
When an image is moused over or out of, grab it's id attribute, extract the number from it, then use that to build a selector for the appropriate span to show.
var get_span_from_image = function(image) {
var image_id = image.attr("id");
var matches = image_id.match(/theImg(\d+)/);
if(matches) return $("theSpan" + matches[1]);
return $(); // nothing found, return an empty jQuery selection
};
$("img").hover(
function() { // mouse over
get_span_from_image($(this)).show();
},
function() { // mouse out
get_span_from_image($(this)).hide();
}
);
Note: There are better ways to "link" two nodes together, but this is just to answer your question with the current structure you have.
UPDATE: Some ideas to link two nodes together
So instead of trying to extract a number from an id attribute, a better way would be to tell either one of the image or span about it's sibling. You could output your html like this, for instance:
<img id="theImg1" data-target="theSpan1" class="hoverable" src="..."/>
....
<span id="theSpan1">...</span>
Of course now your ideas could be anything - you don't have to use numbered values or anything.
Then your hover code becomes quite simply:
var get_span_from_image = function(image) {
var span_id = image.data("target");
return $("#" + span_id);
};
$("img").hover(
function() { // mouse over
get_span_from_image($(this)).show();
},
function() { // mouse out
get_span_from_image($(this)).hide();
}
);
Hope this helps!

In the ordered sequence of words: "Word1, Word2, Word3": how to have 1 and only 1 hyperlink on "Word1" & "Word3"? Thus, skip a word in a single link?

How to skip a word in a hyperlink?
Imagine a random ordered sequence of words:
... Word 1 Word 2 Word3 ...
How would it be possible to have 1 unifying (i.e. not 2 seperate links) hyperlink on Word 1 & Word 3?
I.e.: when one hovers either Word 1 or Word 3, the spectator can immediately notice that the hyperlink will lead to a page that covers the meaning of both these words (visible by whatever the CSS of a:hover is in a particular document).
The result would be:
... Word 1 Word 2 Word3 ...
CRUCIAL REMARK: But then instead of having 2 seperate (in this case bold-formatted hyperlinks), they would be unified into 1 single hyperlink. Again: this could e.g. be visualised in CSS by having a text-decoraiton:underline on a:hover, covering Word 1 and Word 3 simultaneously.
Optionally:
It would be good to also have the possibility to add a second, other hyperlink to Word 2.
Use-case example:
In the sentence:
"This does not need any open (Word 1) bladder (Word 2) surgeries (Word 3)."
It would be nice to have 1 unifying hyperlink on Word 1 and Word3. This example clarifies the usefulness of such a word-skipping-hyperlink: Word 2 certainly shouldn't be included in the first unifying link, since the urinary bladder-Wikipedia han't got much to do with the open surgeries-Wikipedia.
The result would be:
"This does not need any open bladder surgeries."
CRUCIAL REMARK: Instead that the hyperlink on open and surgeries should be unified into one single hyperlink.
Optionally:
It would be good to also have the possibility to add a second, other hyperlink to Word 2:
"This does not need any open bladder surgeries."
The CRUCIAL REMARK from above, also applies here.
You cannot have one link that spans two separate words.
You can have one link on each of the words point to the same location and use a little bit of JavaScript to highlight all the links that have the same destination when the user hovers over one.
For convenience I'm using jQuery here, but the same thing isn't difficult to do without it.
$(function () {
function getKey(element) {
return element.href;
}
function sameGroupAs(element) {
var key = getKey(element);
return function () {
return getKey(this) === key;
}
}
$(document)
.on("mouseenter", "a", function () {
$("a").filter(sameGroupAs(this)).addClass("active");
})
.on("mouseleave", "a", function () {
$("a").filter(sameGroupAs(this)).removeClass("active");
});
});
a.active {
background-color: #A8C5FF;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>"This does not need any open bladder surgeries."</p>
I've used the href as a grouping key, but you can use any other method of groping. Just modify the getKey() function.
Here's a pure HTML + CSS method. The trick is applying a negative z-index to the second word. That makes it unclickable:
a {
text-decoration: none;
}
a span:nth-child(1), a span:nth-child(3) {
font-weight: bold;
}
a:hover span:nth-child(1), a:hover span:nth-child(3) {
text-decoration: underline;
}
a span:nth-child(2) {
position: relative;
z-index: -1;
}
This does not need any
<a href="">
<span>open</span>
<span>bladder</span>
<span>surgeries</span>
</a>
.
If you want the second word to have a different link, I think you need to duplicate the HTML, making the first instance position: absolute, and the second word of the second instance position: relative. You can then change formatting based on hover:
a {
text-decoration: none;
font-weight: bold;
}
#a1 {
position: absolute;
}
#a2 span:nth-child(2) {
position: relative;
}
#a1:hover span:nth-child(1), #a1:hover span:nth-child(3) {
text-decoration: underline;
}
#a2:hover span:nth-child(2) {
text-decoration: underline;
}
This does not need any
<a id="a1" href="http://en.wikipedia.org/wiki/Invasiveness_of_surgical_procedures#Open_surgery">
<span>open</span>
<span>bladder</span>
<span>surgeries</span>
</a>
<a id="a2" href="http://en.wikipedia.org/wiki/Urinary_bladder">
<span>open</span>
<span>bladder</span>
<span>surgeries</span>
</a>
.
With Javascript it's easy - create a span for each word, style the two outer spans to look like links, and attach a single click function to both spans.
HTML
<span id = "one">one,</span>
<span id = "two">two,</span>
<span id = "three">three</span>
CSS
#one, #three {
cursor:pointer;
}
jQuery
$('#one, #three').click(function() {
location.href = 'http://www.google.com';
});
$('#one, #three').hover(function() {
$('#one, #three').css('text-decoration', 'underline');}, function(){
$('#one, #three').css('text-decoration', 'none');
});
using pure CSS, you can have one link that spans multiple words, and have only some of them clickable.
(and you can make it look nicer than my demo using some more CSS)
This answer doesn't fully meet the OP needs because it doesn't allow a different link within the context of the first link, but it's still worth mentioning.
In order to have one link only that spans multiple words, and also have a nested element that points to another link, we'd have to allow anchor tag nesting, but it's not supported, the best way to achieve the same behavior is to split the "big" anchor tag to pieces (manually or with JS like suggested in other answers)].
a span
{
color: black;
pointer-events: none;
}
first <span>second</span> third
The simplest way to go is maybe this css rule:
a {
text-decoration:none;
color:red;
}
span {
color:black;
cursor:default;
}
and a short inline js onclick event where you don't want the event propagated:
<span onclick="return false;"> Word2 </span>
jsFiddle example
But don't do that in production.
It's pointless and ugly.
If you want the second link inside the first one, for the sake of simplicity, i would do this:
<span onclick="document.location.href = 'YOUR_2ND_LINK_HERE'; return false;"> Word2 </span>
updated jsFiddle
Here you go then
new fiddle with visual hint
If this is what you want to achieve then:
Html:
<a href="http://www.wikipedia.org">
<span class="d">Link 1</span>
<span class="b">Link 2</span>
<span class="d">Link 1</span>
<span class="b">Link 2</span>
<span class="d">Link 1</span>
<span class="b">Link 2</span>
</a>
Css
a {
text-decoration:none;
}
.d {
color:blue;
text-decoration:underline;
}
.d.fake-hover {
background:blue;
color:#fff;
text-decoration:none;
}
.b {
color:darkRed;
text-decoration:underline;
}
.b.fake-hover {
background:darkRed;
color:#fff;
text-decoration:none;
}
Javascript:
var elems = document.getElementsByClassName('d');
var otherElems = document.getElementsByClassName('b');
var allElems = document.getElementsByTagName('span');
var _href = 'http://stackoverflow.com';
function fakeIt(what, el) {
var els = (el.classList.contains('d')) ? elems : otherElems;
for (var i = 0, x = els.length; i < x; i++) {
(what == 'hover') ? els[i].classList.add('fake-hover') : els[i].classList.remove('fake-hover');
}
}
function addCustomLink(e) {
e.preventDefault();
location.href = _href;
}
for (var i = 0, x = allElems.length; i < x; i++) {
var el = allElems[i];
el.addEventListener('mouseover', function(e) {
fakeIt('hover', e.target);
});
el.addEventListener('mouseout', function(e) {
fakeIt('out', e.target);
});
if (el.className == 'b') {
el.addEventListener('click', function(e) {
addCustomLink(e);
});
}
};
In jsFiddle apparently I can't use document.location.href so you have to manually edit the addCustomLink function.
Fiddle here

Categories