I want to change the background color of an HTML element whose ID is foo. I have this code at present:
var hexcode = new Array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f');
// this chooses a random value from the array hexcode
var ranval = function() {
return hexcode[Math.floor(Math.random()*hexcode.length)];
}
// six ranval() are put together to get color
var colorname = "#" + ranval() + ranval() + ranval() + ranval() + ranval() + ranval();
// trying to put the value on the background of element with "foo" ID.
document.getElementById("foo").style.color = colorname;
This code is throwing this error:
Uncaught TypeError: Cannot read property 'style' of null
I'm sure that ID foo exists.
Your error occurs because you're trying to access your element before the DOM is ready. Wait for the window to load before accessing it:
// Credit: http://paulirish.com/2009/random-hex-color-code-snippets/
function random_color() {
return '#' + ('00000' + (Math.random() * 16777216 << 0).toString(16)).substr(-6);
}
window.onload = function() {
document.getElementById("foo").style.backgroundColor = random_color();
};
Demo: http://jsfiddle.net/Blender/xQure/1/
The simple way to fix your code is:
var random_color = function() {
function randomHex() {
return Math.floor(Math.random() * 15).toString(16);
}
var str = '#';
for(var i = 6; i--;) {
str += randomHex();
}
return str;
}
window.onload = function() {
// For your body background color
document.body.style.backgroundColor = random_color();
// For your foo element TEXT color
document.getElementById("foo").style.color = random_color();
// For your foo element BACKGROUND color
document.getElementById("foo").style.backgroundColor = random_color();
};
Related
I have an object set up like so:
let xVal = 0;
const myObj = {
infoText: "The value of x is: " + xVal
}
This infoText is referenced later to display somewhat of a tooltip when hovering over an element.
function showTooltip(obj) {
targetEl = document.getElementById('targetId');
targetEl.innerHTML = obj.infoText;
}
The value of xVal can change. The issue I'm running into is that despite whether or not that value has changed, when I hover over my element, it will always display the initial value of xVal. I assume this is because myObj.infoText is established when it's initiated and pulls the initial value of xVal. How can I get myObj.infoText to show the current xVal and keep up with the changes?
EDIT - Here is a better example of my code, I realize I offered a poor sample originally.
let count = 0;
let clickVal = 1;
const myObj = {
cost: 10,
infoText: `This displays the current value of your click <br />
Current click = ` + clickVal
};
function cardContent(obj) {
targetEl = document.getElementById('targetId');
targetEl.innerHTML = obj.infoText;
}
cardContent(myObj); // initialize card content
function handleClick() {
count += clickVal;
}
function upgradeClick() {
count -= myObj.cost;
clickVal += 1;
cardContent(myObj) // attempting to update the text to reflect new value
}
There is a button that invokes handleClick and one that invokes upgradeClick. Using CSS, the following div is hidden and shows when hovering over the upgradeClick button.
<div id='targetId'></div> This is where the infoText shows.
You can use something like a getter
let xVal = 0;
const myObj = {
get infoText() {return "The value of x is: " + xVal;}
}
function showTooltip(obj) {
console.log(obj.infoText);
}
showTooltip(myObj);
xVal = 29;
showTooltip(myObj);
xVal = 794;
showTooltip(myObj);
Creating the object everytime inside of the showTooltip should work
let xVal = 0;
function showTooltip() {
const myObj = {
infoText: "The value of x is: " + xVal
}
console.log(myObj.infoText);
}
showTooltip();
xVal = 50;
showTooltip();
The problem is, no matter what control you're on, it will just affect the blue color.
I'm guessing it might have something to do with the fact that I'm declaring the controls and assigning their handlers in a loop, but I honestly don't know what I'm doing wrong or if the solution is to just do that manually, one by one.
Here's a copy of the project.
let
// This one will contain all the elements
picker = document.createElement("div")
// And this one the color controls
, values = document.createElement("form")
// This' the color preview
, preview = document.createElement("div")
// The preview initializes and updates based on this values
, colors = { red : 200, green : 0, blue : 0 }
// This validates if a value is between 0 and 255
, vv = { min : 0, max : 255 }
, validVal = (n) => vv.min <= n && n <= vv.max
// And this' just a style string
, style = ""
;
// This one changes preview's bg color and shows the
// value inside it
function updatePreview() {
let rgbString =
"rgb("
+ [colors.red, colors.green, colors.blue].join(",")
+ ")";
preview.style["background-color"] = rgbString;
preview.innerHTML = rgbString;
}
// Now we define the elements' class names
picker.className += " color-picker";
values.className += " rgb-values";
preview.className += " preview";
// And their appearance
style += "display : inline-block;";
values.style = style;
style += "width: 200px; height: 200px; border: 1px solid #000;";
preview.style = style;
// Then we add'em to the screen
picker.appendChild(values);
picker.appendChild(preview);
document.body.appendChild(picker);
// And, "finally", we add the controls and their handlers
// One for each color
for (var color in colors) {
// This are text and slide controls
let
label = document.createElement("label")
, span = document.createElement("span")
, slide = document.createElement("input")
, text = document.createElement("input")
;
// We define their general attributes
label.style = "display: block";
slide.name = color + "-slide";
slide.type = "range";
slide.min = vv.min;
slide.max = vv.max;
slide.step = "1";
text.name = color + "-text";
text.type = "text";
text.size = "3";
span.innerHTML = " " + color;
// And set their initial values
slide.value = text.value = colors[color];
// We add'em to screen also
label.appendChild(slide);
label.appendChild(text);
label.appendChild(span);
values.appendChild(label);
// And now the handlers
/*
This is the tricky part.
I must be doing something wrong here. I guess.
Pls, help!
*/
function slideHandler(e) {
text.value = slide.value;
colors[color] = slide.value;
updatePreview();
}
slide.oninput = slideHandler;
function textHandler(e) {
if (validVal(text.value)) slide.value = text.value;
colors[color] = slide.value;
updatePreview();
}
text.onchange = textHandler;
}
// And... Showtime!
updatePreview();
Change the var color for slide.name.split('-')[0]
CODE:
function slideHandler(e) {(
text.value = slide.value;
colors[slide.name.split('-')[0]] = slide.value;
updatePreview();)}
(function() {
window.onload = function() {
let
// This one will contain all the elements
picker = document.createElement("div")
// And this one the color controls
,
values = document.createElement("form")
// This' the color preview
,
preview = document.createElement("div")
// The preview initializes and updates based on this values
,
colors = {
red: 200,
green: 0,
blue: 0
}
// This validates if a value is between 0 and 255
,
vv = {
min: 0,
max: 255
},
validVal = (n) => vv.min <= n && n <= vv.max
// And this' just a style string
,
style = "";
// This one changes preview's bg color and shows the
// value inside it
function updatePreview() {
let rgbString =
"rgb(" +
[colors.red, colors.green, colors.blue].join(",") +
")";
preview.style["background-color"] = rgbString;
preview.innerHTML = rgbString;
}
// Now we define the elements' class names
picker.className += " color-picker";
values.className += " rgb-values";
preview.className += " preview";
// And their appearance
style += "display : inline-block;";
values.style = style;
style += "width: 200px; height: 200px; border: 1px solid #000;";
preview.style = style;
// Then we add'em to the screen
picker.appendChild(values);
picker.appendChild(preview);
document.body.appendChild(picker);
// And, "finally", we add the controls and their handlers
// One for each color
for (var color in colors) {
// This are text and slide controls
let
label = document.createElement("label"),
span = document.createElement("span"),
slide = document.createElement("input"),
text = document.createElement("input");
// We define their general attributes
label.style = "display: block";
slide.name = color + "-slide";
slide.type = "range";
slide.min = vv.min;
slide.max = vv.max;
slide.step = "1";
text.name = color + "-text";
text.type = "text";
text.size = "3";
span.innerHTML = " " + color;
// And set their initial values
slide.value = text.value = colors[color];
// We add'em to screen also
label.appendChild(slide);
label.appendChild(text);
label.appendChild(span);
values.appendChild(label);
// And now the handlers
/*
This is the tricky part.
I must be doing something wrong here. I guess.
Pls, help!
*/
function slideHandler(e) {
text.value = slide.value;
colors[slide.name.split('-')[0]] = slide.value;
updatePreview();
}
slide.oninput = slideHandler;
function textHandler(e) {
if (validVal(text.value)) slide.value = text.value;
colors[slide.name.split('-')[0]] = slide.value;
updatePreview();
}
text.onchange = textHandler;
}
// And... Showtime!
updatePreview();
};
})();
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
</body>
After a couple of hours struggling with the first part I finally made it work.
However I would like to nest two additional functions, the first one to generate a random color and the second one to set the random color into a div with id #gradient that represents the background.
Here is the code so far, can you help me please?
$(document).ready(function() {
$("#btn").on("click", function() {
$.getJSON("http://api.forismatic.com/api/1.0/?method=getQuote&lang=en&format=jsonp&jsonp=?", function(json) {
var quote = json.quoteText;
var author = json.quoteAuthor;
$(".quoteText").text("'" + quote + "'");
$(".quoteAuthor").text("-" + author + "-");
function RandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
function changeColor() {
$("#gradient").css("background-color", RandomColor()));}});});});
JQuery docs:
jQuery.getJSON( url [, data ] [, success ] )
Looking at your code, you got that down. You are sending a function callback when you call $.getJSON(). To start debugging it, I would first tidy up the code (don't do that to yourself or future coders, your editor most likely has a "reformat code" option to add appropriate indentations. Debugging untidy code like that will give you headaches in the future.)
Your code turns into this once you tidy it up and fix some closing/openings that are wrong.
$(document).ready(function () {
$("#btn").on("click", function () {
$.getJSON("http://api.forismatic.com/api/1.0/?method=getQuote&lang=en&format=jsonp&jsonp=?", function (json) {
var quote = json.quoteText;
var author = json.quoteAuthor;
$(".quoteText").text("'" + quote + "'");
$(".quoteAuthor").text("-" + author + "-");
function RandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
function changeColor() {
$("#gradient").css("background-color", RandomColor());
}
});
});
});
First problem
function changeColor() {
$("#gradient").css("background-color", RandomColor());
}
That function will never get called. You are merely declaring it, not calling it. Just take what's inside out of it, and you've got it. I would also take the function RandomColor() (I didn't check if it works or not...) outside of that scope, in case you want to reuse it.
You end up with this:
$(document).ready(function () {
$("#btn").on("click", function () {
$.getJSON("http://api.forismatic.com/api/1.0/?method=getQuote&lang=en&format=jsonp&jsonp=?", function (json) {
var quote = json.quoteText;
var author = json.quoteAuthor;
$(".quoteText").text("'" + quote + "'");
$(".quoteAuthor").text("-" + author + "-");
$("#gradient").css("background-color", RandomColor());
});
});
});
function RandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
In addition, you will only be changing the color of the divupon success. If you want to do something upon failure, use the following:
The Promise interface in jQuery 1.5 also allows jQuery's Ajax methods, including $.getJSON(), to chain multiple .done(), .always(), and .fail() callbacks on a single request, and even to assign these callbacks after the request may have completed. If the request is already complete, the callback is fired immediately.
$.getJSON("...", function (json) {
...
}).fail(function() {
console.log( "error" );
});
Hope that helped.
I might have missed something obvious here, apologies in advance if so...
Using ajax-solr and implementing my own version of their Current Search widget example/tutorial - https://github.com/evolvingweb/ajax-solr/wiki/Reuters-tutorial%3A-step-5 I have a code snippet which looks like this:
(function($) {
AjaxSolr.CurrentSearchWidget = AjaxSolr.AbstractWidget.extend({
start: 0,
afterRequest: function() {
var self = this;
var links = [];
var q = self.manager.store.get('q').val();
var qText = q;
if (q != null && q != '*:*') {
if (q.split(':').length == 2) {
qText = q.split(':')[1];
}
links.push($('')
.text('search: ' + qText + ' (remove)').click(function() {
localStorage.removeItem("query");
localStorage.setItem("query", "*");
self.manager.store.get('q').val('*:*');
self.doRequest();
return false;
}));
}
var fq = self.manager.store.values('fq');
var prettyText = "";
for (var i = 0, l = fq.length; i < l; i++) {
//string manipulation for user-facing text
links.push($('')
.text(prettyText + ' (remove)').click(self.removeFacet(fq[i])));
//local storage stuff
}
if (links.length > 1) {
links.unshift($('')
.text('remove all').click(function() {
localStorage.clear();
localStorage.setItem("query", "*");
self.manager.store.get('q').val('*');
self.manager.store.remove('fq');
self.doRequest();
return false;
}));
}
//update DOM
},
I've stripped out the unecessary code, but the above works fine. However, if I change
links.push($('')
.text(prettyText + ' (remove)')
.click(self.removeFacet(fq[i])));
to use a function as per the examples above it and below, like
links.push($('')
.text(prettyText + ' (remove)')
.click(function () {
self.removeFacet(fq[i]);
}));
so that I can add additional code there, it no longer runs removeFacet when the anchor is clicked. Thanks for any help on what I'm missing!
This seems to be a problem with function scope. This is not pointing to your object anymore. I would suggest binding your "self" object like so.
links.push($('')
.text(prettyText + ' (remove)')
.click(function () {
var self = this;
self.removeFacet(fq[i]);
}).bind(self));
please see if changing to this works
links.push($('')
.text(prettyText + ' (remove)')
.on('click', function () {
self.removeFacet(fq[i]);
}));
The problem you ran into - you have inner functions (the anonymous click function) that is not executed immediately, therefore the iterator gets "lost". Taking the following example
var i, colors = ['green', 'blue', 'red'];
for (i = 0; i < colors.length; i++) {
var color = colors[i];
setTimeout(function() {
console.log(color);
}, i * 1000);
}
// red, red, red
would log 3 times red, because the code of the function (here inside the timeout) is executed outside the loop, the iterator is at its last position.
Using this variant the value would be captured at each iteration into an argument to a function, which does create a scope, which would produce
the output green, blue, and red
var i, colors = ['green', 'blue', 'red'];
for (i = 0; i < colors.length; i++) {
(function(color) {
setTimeout(function() {
console.log(color);
}, i * 1000);
})(colors[i]);
}
// green, blue, red
In your case something like this should work:
links.push($('')
.text(prettyText + ' (remove)')
.click((function(instance, facet) {
// your code here
// and delete
instance.removeFacet(facet);
})(self, fq[i]));
It's always better to use the on function. Try something like this...
$(window, "a.cur-search", function () {
var self = this;
self.removeFacet(fq[i]);
});
You might need to put fq[i] in data or something to make it available.
I am trying to change the background gradient color. This is my code. Browser reflects that getColor is undefined.color1, color2 and color 3 are inputs that i get from the user. They work but i am still unable to change the background gradient color.
<script>
function getColor(){
var color1 = document.getElementById('color1').value;
var color2 = document.getElementById('color2').value;
var color3 = document.getElementById('color3').value;
function getCssValuePrefix()
{
var rtrnVal = '';//default to standard syntax
var prefixes = ['-o-', '-ms-', '-moz-', '-webkit-'];
// Create a temporary DOM object for testing
var dom = document.createElement('div');
for (var i = 0; i < prefixes.length; i++)
{
// Attempt to set the style
dom.style.background = prefixes[i] + 'liner-gradient(#000000, #ffffff)';
// Detect if the style was successfully set
if (dom.style.background)
{
rtrnVal = prefixes[i];
}
}
dom = null;
delete dom;
return rtrnVal;
}
document.getElementsByTagName("body")[0].style.background = getCssValuePrefix() + 'linear-gradient('+ '38deg' + ', ' + color1 + ', '+ color2 + ',' + color3 +')';
</script>
In html i have a button as follows:
<button onclick="getColor">Change Background Color</button>
Browser reflects that getColor is undefined
The probable problem is that your script is not placed in window.onload. So, the HTML onclick handler tries getColor before it's loaded.
Note: You have liner-gradient in your code. That's a typo.