This is my code. Im new to JavaScript so idk what I'm really doing. Basically, every time the button is clicked, a new Van Gogh detail/image should fill the background. I feel like many images are repeated and sometimes the button doesn't work (a new image doesn't appear on each click). Ideally, I would like a new image with each click. For now, I only have 10 images, but may add more. Thank you for your help.
HTML
<!DOCTYPE html>
<html>
<head>
<title>VG java project</title>
<link rel="stylesheet" type="text/css" href="assets/main.css">
<script src="assets/jquery-3.5.1.min.js"></script>
<script type="text/javascript" src="assets/main.js"></script>
</head>
<body>
<div class="container1"></div>
<div class="container">
<div class="button">
Do you like Van Gogh?
</div>
</div>
</body>
</html>
CSS
body {
font-family: courier new;
padding: 3rem;
z-index: 200;
background: url(gogh4.jpg);
}
.container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.item {
max-width: 960px;
text-align: center;
}
.button {
position: absolute;
left: 50px;
top: 50px;
border: 7px double;
border-color: black;
padding: 20px;
font-size: 40px;
background-color: rgb(225, 186, 253);
opacity: 80%;
}
.button:hover {
background-color: rgb(197, 103, 247);
color: white;
cursor: pointer;
opacity: 90%;
}
.gogh1 {
background: url(gogh1.jpg);
}
.gogh2 {
background: url(gogh3.jpg);
}
.gogh3 {
background: url(gogh3.jpg);
}
.gogh4 {
background: url(gogh4.jpg);
}
.gogh5 {
background: url(gogh5.jpg);
}
.gogh6 {
background: url(gogh6.jpg);
}
.gogh7 {
background: url(gogh7.jpg);
}
.gogh8 {
background: url(gogh8.jpg);
}
.gogh9 {
background: url(gogh9.jpg);
}
.gogh10 {
background: url(gogh10.jpg);
}
.highlight {
font-size: 200px;
}
JavaScript ~ I'm using jQuery btw
$(function() {
$(".button").click(function(){
let goghs = ["gogh1", "gogh2", "gogh3", "gogh4",
"gogh5", "gogh6", "gogh7", "gogh8",
"gogh9", "gogh10"]
let i = Math.floor(Math.random()* goghs.length - Math.random() + 2 );
$("body").toggleClass(goghs[i]);
});
});
Since You asked for Javascript help.
Here's a problem you had in your code:
Edited:
$(function () {
$(".button").click(function () {
let goghs = ["gogh1", "gogh2", "gogh3", "gogh4",
"gogh5", "gogh6", "gogh7", "gogh8",
"gogh9", "gogh10"
]
let i = Math.floor(Math.random() * goghs.length); //There was no need to add + Random plus 2 to it. You already Selecting a random index from an array(sometimes 'i' value was 10 -> undefined).
console.log(i, goghs[i]); //logging helps you notice that is nothing wrong with other parts and function runs. only the code itself has some problems.
$("body").toggleClass(goghs[i]);
});
});
If "i" is 2 the first time around then "gogh2" get added as the class.
If "i" is 3 the second time around the "gogh3" will be 'added' to the class list. "gogh2" will still be there.
Then, if "i" is 2 the third time around, then it will remove "gogh2" and you'll just be left with "gogh3".
Try:
$("body").removeClass();
$("body").addClass(goghs[i]);
and do away with your toggleClass line.
toggleClass will add the class to the list if it's not there and remove it if it is.
I have an ID named TIMZ I am trying to position each of my digital times in this ID separately but instead they are all conjoined. I partially understand this is due to the style but how I would I correct my code so that I can position each TimZ separately instead of being together as they are showed in the image. Thanks!
Image of TIMZ ID and what does:
HTML CODE FOR ID:
<div id="timZ" class="row" style="width: 90%;">
</div>
<script>
// window.localStorage.removeItem('time');
var s=window.localStorage.getItem('time');
var s=JSON.parse(s);
// console.log(s);
s.forEach(function(time, index) {
$('<div/>', {
"class": 'timZonM col',
'data-timezone': `${time.offset}`,
}).appendTo('#timZ');
CSS Code:
div.timZonM { /* military time */
/* width: 3em; */
/* margin:.3em; */
color: white;
border: 4px solid crimson;
font-size: 110px;
font-family: 'Monserrat';
/* letter-spacing: .05em; */
}
div.timZonM::after {
content: attr(data-seconds);
color:white;
}
I'm wondering if it's possible to on each appendTo make the new div unique but still use the same jquery.
As you can see in the mark-up below, each new div shares the same jquery so doesn't work independently.
Within my Javascript i'm selecting the ID to fire each function.
I've tried just adding + 1 etc to the end of each ID, but with that it changes the name of the ID making the new created DIV not function.
I've thought of using DataAttribues, but i'd still have the same issue having to create multiple functions all doing the same job.
Any ideas?
Thanks
$(function() {
var test = $('#p_test');
var i = $('#p_test .upl_drop').length + 1;
$('#addtest').on('click', function() {
$('<div class="file-input"><div class="input-file-container upl_drop"><label for="p_test" class="input-file-trigger">Select a file...<input type="file" id="p_test" name="p_test_' + i + '" value=""class="input-file"></label></div><span class="remtest">Remove</span><p class="file-return"></p></div>').appendTo(test);
i++;
});
$('body').on('click', '.remtest', function(e) {
if (i > 2) {
$(this).closest('.file-input').remove();
i--;
}
});
});
var input = document.getElementById( 'file-upload' );
var infoArea = document.getElementById( 'file-upload-filename' );
input.addEventListener( 'change', showFileName );
function showFileName( event ) {
// the change event gives us the input it occurred in
var input = event.srcElement;
// the input has an array of files in the `files` property, each one has a name that you can use. We're just using the name here.
var fileName = input.files[0].name;
// use fileName however fits your app best, i.e. add it into a div
textContent = 'File name: ' + fileName;
$("#input-file-trigger").text(function () {
return $(this).text().replace("Select a file...", textContent);
});
}
/*
#### Drag & Drop Box ####
*/
.p_test{
display: inline-block;
}
.upl_drop{
border: 2px dashed #000;
margin: 0px 0px 15px 0px;
}
.btn--add p{
cursor: pointer;
}
.input-file-container {
position: relative;
width: auto;
}
.input-file-trigger {
display: block;
padding: 14px 45px;
background: #ffffff;
color: #1899cd;
font-size: 1em;
cursor: pointer;
}
.input-file {
position: absolute;
top: 0; left: 0;
width: 225px;
opacity: 0;
padding: 14px 0;
cursor: pointer;
}
.input-file:hover + .input-file-trigger,
.input-file:focus + .input-file-trigger,
.input-file-trigger:hover,
.input-file-trigger:focus {
background: #1899cd;
color: #ffffff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div class="p_test" id="p_test">
<div class="file-input">
<div class="input-file-container upl_drop">
<input class="input-file" id="file-upload" type="file">
<label tabindex="0" for="file-upload" id="input-file-trigger" class="input-file-trigger">Select a file...</label>
</div>
<div id="file-upload-filename"></div>
</div>
<button class="btn--add" id="addtest">
Add
</button>
</div>
I'd advise against using incremental id attributes. They become a pain to maintain and also make the logic much more complicated than it needs to be.
The better alternative is to use common classes along with DOM traversal to relate the elements to each other, based on the one which raised any given event.
In your case, you can use closest() to get the parent .file-input container, then find() any element within that by its class. Something like this:
$(function() {
var $test = $('#p_test');
$('#addtest').on('click', function() {
var $lastGroup = $test.find('.file-input:last');
var $clone = $lastGroup.clone();
$clone.find('.input-file-trigger').text('Select a file...');
$clone.insertAfter($lastGroup);
});
$test.on('click', '.remtest', function(e) {
if ($('.file-input').length > 1)
$(this).closest('.file-input').remove();
}).on('change', '.input-file', function(e) {
if (!this.files)
return;
var $container = $(this).closest('.file-input');
$container.find(".input-file-trigger").text('File name: ' + this.files[0].name);
});
});
.p_test {
display: inline-block;
}
.upl_drop {
border: 2px dashed #000;
margin: 0px 0px 15px 0px;
}
.btn--add p {
cursor: pointer;
}
.input-file-container {
position: relative;
width: auto;
}
.input-file-trigger {
display: block;
padding: 14px 45px;
background: #ffffff;
color: #1899cd;
font-size: 1em;
cursor: pointer;
}
.input-file {
position: absolute;
top: 0;
left: 0;
width: 225px;
opacity: 0;
padding: 14px 0;
cursor: pointer;
}
.input-file:hover+.input-file-trigger,
.input-file:focus+.input-file-trigger,
.input-file-trigger:hover,
.input-file-trigger:focus {
background: #1899cd;
color: #ffffff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div class="p_test" id="p_test">
<div class="file-input">
<div class="input-file-container upl_drop">
<input class="input-file" type="file">
<label tabindex="0" for="file-upload" class="input-file-trigger">Select a file...</label>
</div>
<div class="file-upload-filename"></div>
</div>
<button class="btn--add" id="addtest">Add</button>
</div>
Note that I've made a couple of other optimisations to the code. Firstly it now makes a clone() of the last available .file-input container when the Add button is clicked. This is preferred over writing the HTML in the JS file as it keeps the two completely separate. For example, if you need to update the UI, you don't need to worry about updating the JS now, as long as the classes remain the same.
Also note that you were originally mixing plain JS and jQuery event handlers. It's best to use one or the other. As you've already included jQuery in the page, I used that as it makes the code easier to write and more succinct.
Finally, note that you didn't need to provide a function to text() as you're completely over-writing the existing value. Just providing the new string is fine.
I need to build inline rating for tv shows for example. Max rating I put in jQuery code, current rating in html document. This is how I found the way to do this.
$(document).ready(function() {
var maxRating = $('.rate-line').width();
var maxRating = 6; //max-rating
var currentRatingFirst = $('.first-rd').text();
var calc = (currentRatingFirst / maxRating) * 100 + "%";
$('.first-rl span.fill').width(calc);
});
.rate-line {
border: 1px solid #bababa;
background: #fff;
position: relative;
vertical-align: middle;
margin-right: 1.25em;
overflow: hidden;
width: 50%;
height: 20px;
}
.rate-line, .rate-data, .fill {
display:inline-block;
}
.fill {
background: #ff6292;
height: 22px;
position: absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div>
<span class="rate-line first-rl">
<span class="fill"></span>
</span>
<span class="rate-data first-rd">4.56</span>
</div>
But, I need to create 6 rating lines for this month, then 6 for next and so on. And every time I must give new unique classes to make it work. And code becomes huge. And one more, all this rating nested to bootstrap carousel items and when I duplicate it nothing works .I'm not good in JavaScript at all and I'm asking your help. Would you please tell me how to make it work correctly and make it easier?
In this case it makes sense to create basin custom plugin, so you can easily reuse it without duplicating code.
Here is a very basic example of how you can extend jQuery prototype with a new method:
$.fn.rating = function(options) {
return this.each(function() {
var maxRating = $(this).find('.rate-line').width();
var maxRating = 6;
var currentRatingFirst = $(this).find('.first-rd').text();
var calc = (currentRatingFirst / maxRating) * 100 + "%";
$(this).find('.first-rl span.fill').width(calc);
});
};
$(document).ready(function () {
$('.rating').rating();
});
.rate-line {
border: 1px solid #bababa;
background: #fff;
position: relative;
vertical-align: middle;
margin-right: 1.25em;
overflow: hidden;
width: 50%;
height: 20px;
}
.rate-line, .rate-data, .fill {
display:inline-block;
}
.fill {
background: #ff6292;
height: 22px;
position: absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="rating">
<span class="rate-line first-rl">
<span class="fill"></span>
</span>
<span class="rate-data first-rd">4.56</span>
</div>
<div class="rating">
<span class="rate-line first-rl">
<span class="fill"></span>
</span>
<span class="rate-data first-rd">3.21</span>
</div>
I have a web app with a number of textareas and the ability to add more if you wish.
When you shift focus from one textarea to another, the one in focus animates to a larger size, and the rest shrink down.
When the page loads it handles the animation perfectly for the initial four boxes in the html file, but when you click on the button to add more textareas the animation fails to accomodate these new elements... that is, unless you place the initial queries in a function, and call that function from the addelement function tied to the button.
But!, when you do this it queries as many times as you add a new element. So, if you quickly add, say 10, new textareas, the next time you lay focus on any textarea the query runs 10 times.
Is the issue in my design, or jQueries implementation? If the former, how better can I design it, if it is the latter, how can I work around it?
I've tried to chop the code down to the relevant bits... I've tried everything from focus and blur, to keypresses, the latest is on click.
html::
<html>
<head>
<link rel="stylesheet" type="text/css" href="./sty/sty.css" />
<script src="./jquery.js"></script>
<script>
$().ready(function() {
var $scrollingDiv = $("#scrollingDiv");
$(window).scroll(function(){
$scrollingDiv
.stop()
//.animate({"marginTop": ($(window).scrollTop() + 30) + "px"}, "slow" );
.animate({"marginTop": ($(window).scrollTop() + 30) + "px"}, "fast" );
});
});
</script>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>boxdforstacks</title>
</head>
<body>
<div class="grid">
<div class="col-left" id="left">
<div class="module" id="scrollingDiv">
<input type="button" value="add" onclick="addele()" />
<input type="button" value="rem" onclick="remele()" />
<p class="display">The value of the text input is: </p>
</div>
</div> <!--div class="col-left"-->
<div class="col-midd">
<div class="module" id="top">
<p>boxa</p>
<textarea class="tecksd" placeholder="begin typing here..." id="boxa" ></textarea>
<p>boxb</p>
<textarea class="tecksd" placeholder="begin typing here..." id="boxb"></textarea>
<p>boxc</p>
<textarea class="tecksd" placeholder="begin typing here..." id="boxc"></textarea>
<p>boxd</p>
<textarea class="tecksd" placeholder="begin typing here..." id="boxd"></textarea>
</div>
</div> <!--div class="col-midd"-->
</div> <!--div class="grid"-->
</body>
</html>
<script type="text/javascript" src="boxd.js"></script>
js:
function onit(){
$('textarea').on('keyup change', function() {
$('p.display').text('The value of the text input is: ' + $(this).val());
});
}
$('textarea').on("click",function(){
//alert(this.id.substring(0,3));
if ( this.id.substring(0,3) == 'box' ){
$('textarea').animate({ height: "51" }, 1000);
$(this).animate({ height: "409" }, 1000);
} else {
$('textarea').animate({ height: "51" }, 1000);
}
}
);
var boxfoc="";
var olebox="";
var numb = 0;
onit();
function addele() {
var tops = document.getElementById('top');
var num = numb + 1;
var romu = romanise(num);
var newbox = document.createElement('textarea');
var newboxid = 'box'+num;
newbox.setAttribute('id',newboxid);
newbox.setAttribute('class','tecksd');
newbox.setAttribute('placeholder','('+romu+')');
tops.appendChild(newbox);
numb = num;
onit();
} //addele(), add element
function remele(){
var tops = document.getElementById('top');
var boxdone = document.getElementById(boxfoc);
tops.removeChild(boxdone);
} // remele(), remove element
function romanise (num) {
if (!+num)
return false;
var digits = String(+num).split(""),
key = ["","c","cc","ccc","cd","d","dc","dcc","dccc","cm",
"","x","xx","xxx","xl","l","lx","lxx","lxxx","xc",
"","i","ii","iii","iv","v","vi","vii","viii","ix"],
roman = "",
i = 3;
while (i--)
roman = (key[+digits.pop() + (i * 10)] || "") + roman;
return Array(+digits.join("") + 1).join("M") + roman;
} // romanise(), turn numbers into roman numerals
css :
.tecksd {
width: 97%;
height: 51;
resize: none;
outline: none;
border: none;
font-family: "Lucida Console", Monaco, monospace;
font-weight: 100;
font-size: 70%;
background: white;
/* box-shadow: 1px 2px 7px 1px #0044FF;*/
}
.tecksded {
width: 97%;
resize: none;
outline: none;
border: none;
overflow: auto;
position: relative;
font-family: "Lucida Console", Monaco, monospace;
font-weight: 100;
font-size: 70%;
background: white;
/* box-shadow: 1px 2px 7px #FFDD00;*/
}
/*#postcomp {
width: 500px;
}*/
* {
#include box-sizing(border-box);
}
$pad: 20px;
.grid {
background: white;
margin: 0 0 $pad 0;
&:after {
/* Or #extend clearfix */
content: "";
display: table;
clear: both;
}
}
[class*='col-'] {
float: left;
padding-right: $pad;
.grid &:last-of-type {
padding-right: 0;
}
}
.col-left {
width: 13%;
}
.col-midd {
width: 43%;
}
.col-rght {
width: 43%;
}
.module {
padding: $pad;
}
/* Opt-in outside padding */
.grid-pad {
padding: $pad 0 $pad $pad;
[class*='col-']:last-of-type {
padding-right: $pad;
}
}
body {
padding: 10px 50px 200px;
background: #FFFFFF;
background-image: url('./backgrid.png');
}
h1 {
color: black;
font-size: 11px;
font-family: "Lucida Console", Monaco, monospace;
font-weight: 100;
}
p {
color: white;
font-size: 11px;
font-family: "Lucida Console", Monaco, monospace;
font-weight: 100;
}
You should use the following:
// New way (jQuery 1.7+) - .on(events, selector, handler)
$(document).on("click", "textarea", function () {
event.preventDefault();
alert('testlink');
});
Since the textarea is added dynamically, you need to use event delegation to register the event handler.
Try
$(document).on('click', 'textarea', function() {
// do something
});
The issue is you are binding the textareas only on the page load. I made a JSFiddle with working code: http://jsfiddle.net/VpABC/
Here's what I changed:
I wrapped:
$('textarea').on("click", function () {
//alert(this.id.substring(0,3));
if (this.id.substring(0, 3) == 'box') {
$('textarea').animate({
height: "51"
}, 1000);
$(this).animate({
height: "409"
}, 1000);
} else {
$('textarea').animate({
height: "51"
}, 1000);
}
});
in a function so it looked like this:
function bindTextAreas() {
$('textarea').unbind("click");
$('textarea').on("click", function () {
//alert(this.id.substring(0,3));
if (this.id.substring(0, 3) == 'box') {
$('textarea').animate({
height: "51"
}, 1000);
$(this).animate({
height: "409"
}, 1000);
} else {
$('textarea').animate({
height: "51"
}, 1000);
}
});
}
bindTextAreas();
What this does is it allows you to call this function, bindTextAreas, whenever you create a new textarea. This will unbind all the current events than rebind them. This will make it so your new textarea is has the click handler setup.
An place where this function is called is in the addele function like this:
function addele() {
var tops = document.getElementById('top');
var num = numb + 1;
var romu = romanise(num);
var newbox = document.createElement('textarea');
var newboxid = 'box' + num;
newbox.setAttribute('id', newboxid);
newbox.setAttribute('class', 'tecksd');
newbox.setAttribute('placeholder', '(' + romu + ')');
tops.appendChild(newbox);
numb = num;
onit();
bindTextAreas();
} //addele(), add element
Notice the bindTextAreas(); line near the bottom. This reloads all the click handlers.