Modify shadow root on css - javascript

I'm trying with a thousand different css rules, but I can't find any that do what I require.
I have a desire to edit a custom element in my css file after it is placed in the dom, but I can't, how can I do?
If there is already a question asked, I apologize and please link it to me
class GacInput extends HTMLElement {
constructor() {
super();
this.root = this.attachShadow({
mode: 'open'
});
this.root.innerHTML = `
<style>
:host {
display: flex;
width: min-content;
}
input {
display: block;
}
</style>
<label></label>
<input type="text">
`;
}
static get observedAttributes() {
return ['label', 'align'];
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'label') {
this.root.querySelector('label').innerText = newValue;
}
if (name === 'align') {
switch (newValue) {
case "right":
this.root.host.style.flexDirection = "row-reverse";
break;
case "top":
this.root.host.style.flexDirection = "column";
break;
case "bottom":
this.root.host.style.flexDirection = "column-reverse";
break;
default:
this.root.host.style.flexDirection = "row";
}
}
}
}
customElements.define('gac-input', GacInput);
gac-input::shadow label {
background-color: blue;
}
gac-input /deep/ label {
background-color: blue;
}
:host(gac-input) label {
background-color: blue;
}
<gac-input label="nome" align="top"></gac-input>

Not sure if this will help with your specific case,
But my go-to for editing a css-property after the DOM is loaded is using variables.
For example:
:root {
--custom-color: #000000;
--flex-direction: column;
}
.element {
background-color: var(--custom-color);
flex-direction: var(--flex-direction);
}
And to change it via javascript:
const root = document.querySelector(':root');
root.style.setAttribute('--custom-color', '#999999');

Related

How can I receive focus and select event in my HTML custom element

I am building a custom HTML element.
The custom HTML element extends a table cell element.
I have included an input textbox in this custom element.
When the custom element got a focus or select event, I want the input text box to get these events.
Here is my code:
class DateCell extends HTMLTableCellElement {
constructor() {
super();
this.textBox = document.createElement("input");
this.textBox.type = "text";
this.appendChild(this.textBox);
$(this).addClass("borderCell");
$(this).addClass("dateCell");
}
focus(e)
{
this.textBox.focus();
}
select(e)
{
this.textBox.select();
}
set textContent(t)
{
this.textBox.value = t;
}
get textContent()
{
return this.textBox.value ;
}
set value(v)
{
this.textBox.value = v;
switch (v)
{
case "a":
this.textBox.className="aShiftColor";
break;
case "b":
this.textBox.className="bShiftColor";
break;
case "c":
this.textBox.className="cShiftColor";
break;
}
}
get value() {
return this.textBox.value;
}
}
customElements.define('datacell-string',
DateCell, {
extends: 'td'
});
$(document).ready(function() {
var t = document.createElement("table");
var row = t.insertRow(t.rows);
var cell1 = new DateCell();
var cell2 = new DateCell();
var cell3 = new DateCell();
row.appendChild(cell1);
row.appendChild(cell2);
row.appendChild(cell3);
$(cell1).val("a");
cell2.value = "c";
cell2.select();
$(cell3).val("b");
$(cell3).focus();
$(document.body).append(t);
$("td").each(function(){
console.log(this.value);
});
});
td input[type="text"]
{
//color:white;
border:none;
//border:1px solid black;
height:100%;
width:100%;
text-align:center;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
td input[type="text"]:focus
{
outline: none;
}
table
{
border-spacing: 0;
border-collapse: collapse;
}
.aShiftColor
{
background-color:#ff99cc;
}
.borderCell
{
border:1px solid #e0e0e0;
}
.bShiftColor
{
background-color:#ffffcc;
}
.cShiftColor
{
background-color:#ccffcc;
}
.dateCell
{
margin:0px;
width:25px;
padding: 0px;
text-align: center;
font-size:17px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Unfortunately, none of these input boxes is selected or on focus.
After several trials, I found that because of all DateCells are not connected to attached to DOM, so the "select" and "focus" effect is not shown.
Therefore, I changed the following code:
..............
cell2.select();
$(cell3).val("b");
$(cell3).focus();
$(document.body).append(t);
to
..............
$(cell3).val("b");
$(document.body).append(t);
cell2.select();
$(cell3).focus();
, then it works!

How do I change the background dynamically?

I am creating a weather App and I want to change the background dynamically according to the fetched data from the API.
I have created a variable and an if statement but I was having trouble assigning the variable because I was using module.scss and I'm not sure of the syntax.
render() {
let bgColorClass = 'App'; // very-warm, warm, normal, cold, very-cold
if (this.state.main === "rain") {
bgColorClass = 'rain';
}
else if (this.state.main === "thunderstorm") {
bgColorClass = 'thunder';
}
else if (this.state.main === "drizzle") {
bgColorClass = 'drizzle';
}
else if (this.state.main === "Snow") {
bgColorClass = 'snow';
}
else if (this.state.main === "Clear") {
bgColorClass = 'sun';
}
else if (this.state.main === "Clouds") {
bgColorClass = 'clouds';
} else {
bgColorClass = 'else'
}
return (
<div className={Styles.App} style={{bgColorClass}}>
<Header />
<Form
getWeather={this.getWeather} />
<Weather
temperature={this.state.temperature}
city={this.state.city}
country={this.state.country}
description={this.state.description}
main={this.state.main}
Right now it's not working. I have defined the css files as this:
$sun: #ffc600;
$rain: #94AF10;
$drizzle: #06799F;
$thunder: #233884;
$snow: #707ba5;
$clouds: #686b77;
$else: #842343;
.App {
text-align: center;
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
background-color: $drizzle;
//background: linear-gradient(0deg, rgb(66, 61, 160) 0%, rgba(0,212,255,1) 100%);
color: white;
height: 100vh;
&.sun{ background-color: $sun; }
&.rain { background-color: $rain; }
&.drizzle { background-color: $drizzle; }
&.thunder { background-color: $thunder; }
&.snow { background-color: $snow; }
&.clouds { background-color: $clouds; }
&.else { background-color: $else; }
}
Right now you are echoing a single word into the inline style attribute, which isn't valid CSS. You will need to add the bgColorClass to the className attribute of your div.
BTW you're using tons of if statements. You also can use a switch statement
switch (this.state.main) {
case "rain":
bgColorClass = "rain";
break;
case "drizzle":
bgColorClass = "drizzle";
break;
// and so on…
default:
bgColorClass = "else";
break;
}
or even better: Rename all your CSS classes to the possible state values and directly insert the value as the class:
<div className={"App " + this.state.main}>
// e.g. if this.state.main is 'rain', then the output would be
<div class="App rain">
With this trick you can omit the conditional if or switch statements
add bgColorClass in your className
example:
<div className={"App "+ bgColorClass}>

How to add to html article class variable from js

I have 6 styles in css and i want to use this code to apply them randomly:
<script>
function getRandom(max) {
return "style" + Math.floor(Math.random() * max);
}
document.getElementById('XXX').innerHTML = getRandom(6);
</script>
And I need to add XXX to article class
<article class="XXX">
This code doesn't work :(
First set a ID to the article tag
<article class="XXX" id="someId">
Then to set class to article use below code
var element = document.getElementById("someId");
element.className=getRandom(6);
Hope this helps!
//randomize plugin
(function($) {
$.rand = function(arg) {
if ($.isArray(arg)) {
return arg[$.rand(arg.length)];
} else if (typeof arg === "number") {
return Math.floor(Math.random() * arg);
} else {
return 4; // chosen by fair dice roll
}
};
})(jQuery);
//your list of classes
var items = ["class-1", "class-2", "class-3", "class-4", "class-5"];
//executes on page load
$("#addRandom").removeClass().addClass(jQuery.rand(items));
//button to inject random class
$("#randomize").click(function() {
var item = jQuery.rand(items);
$("#addRandom").removeClass().addClass(item);
});
#addRandom {
display:block;
width: 100px;
height: 100px;
margin: 10px
}
.class-1 {
background-color: purple;
}
.class-2 {
background-color: blue;
}
.class-3 {
background-color: green;
}
.class-4 {
background-color: yellow;
}
.class-5 {
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="addRandom" class="">
</div>
<button id="randomize">randomize</button>
If you just need to add a CSS class to your element, the answer is plain easy:
document.getElementById("your-element").classList.add("your-class");
For more information, see classList.
Thanks to all! Here is a code that works as needed:
<script>
const elements = document.querySelectorAll('article');
elements.forEach(element => {
function getRandom(max) {
return "style" + Math.floor(Math.random() * max);
}
element.classList.add(getRandom(6));
});</script>

User interaction with javascript?

I have the following code which allows a user to interact with a table to create a game of tic-tac-toe, how do I alter it to replace the 'X' and 'O' text with images instead?
so that when the user clicks on a square an image is displayed instead of plain text ?
<!DOCTYPE html>
<html>
<head>
<title>tic-tac-toe</title>
<style>
td { border: 1px solid black;
width: 2em;
height: 2em;
margin: 0em;
text-align: center;
vertical-align: middle;
}
div.RedBG { background-color: #f00; }
td.BlueBG { background-color: white; }
</style>
</head>
<body>
<center><table id="t1"></table></center>
<div id="m1"></div>
<script>
var board = var board = [[0,0,0],[0,0,0],[0,0,0]];
var free = 9;
var turn = 0;
function numToLetter(num) {
switch (num) {
case 0: return " "
case 1: return "O"
case 2: return "X"
}
}
function clearMessage() {
m1 = document.getElementById("m1");
m1.style.display = "none";
}
function showMessage(message,style) {
m1 = document.getElementById("m1");
m1.innerHTML = message;
m1.style.display = "block";
m1.className = style;
}
...
alter the numToLetter function to return a source for an image contained in td or to assign the source to the image...
i think returning the source would be easier and cleaner.
In that case: in the numToLetter calling code assign the source to the appropriate grid square...
function numToSource(num) {
switch (num) {
case 0: return "path/to/blank.png";
case 1: return "path/to/O.png";
case 2: return "path/to/X.png";
}
}
function assignImageSource(gridId, num){
var element = document.getElementById(gridId);
var source = numberToSource(num);
element.src = source;
}

jQuery: Toggling between 3 classes (initially)

I've seen several posts here on SO but they are too specific in functionality and structure, and what I'm looking for is something more universal that I or anyone can use anywhere.
All I need is to have a button that when clicked can cycle between 3 classes. But if the case arises to have to cycle through 4, 5 or more classes, that the script can be easily scaled.
As of this moment I am able to 'cycle' between two classes which is basically more "toggling" than cycling, so for that I have:
HTML:
Toggle classes
<div class="class1">...</div>
jQuery:
$('.toggle').click(function () {
$('div').toggleClass('class1 class2');
});
Here's a simple fiddle of this.
Now, you would (well, I) think that adding a third class to the method would work, but it doesn't:
$('div').toggleClass('class1 class2 class3');
What happens is that the toggling starts happening between class1 and class3 only.
So this is where I have my initial problem: How to have the Toggle button cycle sequentially through 3 classes?
And then: What if someone needs to cycle to 4, 5 or more classes?
You can do this :
$('.toggle').click(function () {
var classes = ['class1','class2','class3'];
$('div').each(function(){
this.className = classes[($.inArray(this.className, classes)+1)%classes.length];
});
});
Demonstration
Here is another approach:
if ($(this).hasClass('one')) {
$(this).removeClass('one').addClass('two');
} else if ($(this).hasClass('two')) {
$(this).removeClass('two').addClass('three');
} else if ($(this).hasClass('three')) {
$(this).removeClass('three').addClass('one');
}
var classes = ['class1', 'class2', 'class3'],
currentClass = 0;
$('.toggle').click(function () {
$('div').removeClass(classes[currentClass]);
if (currentClass + 1 < classes.length)
{
currentClass += 1;
}
else
{
currentClass = 0;
}
$('div').addClass(classes[currentClass]);
});
Something like that should work OK :)
Tinker IO link - https://tinker.io/1048b
This worked for me and I can stack as many as I want, then wrap around easily.
switch($('div.sel_object table').attr('class'))
{
case "A": $('div.sel_object table').toggleClass('A B'); break;
case "B": $('div.sel_object table').toggleClass('B C'); break;
case "C": $('div.sel_object table').toggleClass('C D'); break;
case "D": $('div.sel_object table').toggleClass('D A'); break;
}
Cycles through the index of classes and toggles from one to ther other.
var classes = ['border-top','border-right','border-bottom','border-left'];
var border = 'border-top';
var index = 0;
var timer = setInterval( function() {
var callback = function(response) {
index = ( ++index == 4 ? 0 : index );
$(element).html("text").toggleClass( border + " " + classes[index] );
border = classes[index];
};
}, 1000 );
I converted user3353523's answer into a jQuery plugin.
(function() {
$.fn.rotateClass = function(cls1, cls2, cls3) {
if ($(this).hasClass(cls1)) {
return $(this).removeClass(cls1).addClass(cls2);
} else if ($(this).hasClass(cls2)) {
return $(this).removeClass(cls2).addClass(cls3);
} else if ($(this).hasClass(cls3)) {
return $(this).removeClass(cls3).addClass(cls1);
} else {
return $(this).toggleClass(cls1); // Default case.
}
}
})(jQuery);
$('#click-me').on('click', function(e) {
$(this).rotateClass('cls-1', 'cls-2', 'cls-3');
});
#click-me {
width: 5em;
height: 5em;
line-height: 5em;
text-align: center;
border: thin solid #777;
margin: calc(49vh - 2.4em) auto;
cursor: pointer;
}
.unselectable {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.cls-1 { background: #FFAAAA; }
.cls-2 { background: #AAFFAA; }
.cls-3 { background: #AAAAFF; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="click-me" class="unselectable">Click Me!</div>
Dynamic Approach
(function() {
$.fn.rotateClass = function() {
let $this = this,
clsList = arguments.length > 1 ? [].slice.call(arguments) : arguments[0];
if (clsList.length === 0) {
return $this;
}
if (typeof clsList === 'string') {
clsList = clsList.indexOf(' ') > -1 ? clsList.split(/\s+/) : [ clsList ];
}
if (clsList.length > 1) {
for (let idx = 0; idx < clsList.length; idx++) {
if ($this.hasClass(clsList[idx])) {
let nextIdx = (idx + 1) % clsList.length,
nextCls = clsList.splice(nextIdx, 1);
return $this.removeClass(clsList.join(' ')).addClass(nextCls[0]);
}
}
}
return $this.toggleClass(clsList[0]);
}
})(jQuery);
$('#click-me').on('click', function(e) {
$(this).rotateClass('cls-1', 'cls-2', 'cls-3'); // Parameters
//$(this).rotateClass(['cls-1', 'cls-2', 'cls-3']); // Array
//$(this).rotateClass('cls-1 cls-2 cls-3'); // String
});
#click-me {
width: 5em;
height: 5em;
line-height: 5em;
text-align: center;
border: thin solid #777;
margin: calc(49vh - 2.4em) auto;
cursor: pointer;
}
.unselectable {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.cls-1 { background: #FFAAAA; }
.cls-2 { background: #AAFFAA; }
.cls-3 { background: #AAAAFF; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="click-me" class="unselectable">Click Me!</div>
HTML:
<div id="example" class="red">color sample</div>
CSS:
.red {
background-color: red;
}
.yellow {
background-color: yellow;
}
.green {
background-color: green;
}
JS:
$(document).ready(function() {
var colors = ['red', 'yellow', 'green'];
var tmp;
setInterval(function(){
tmp && $('#example').removeClass(tmp);
tmp = colors.pop();
$('#example').addClass(tmp);
colors.unshift(tmp);
}, 1000);
});
DEMO
Another version that uses classList replace. Not supported by all browsers yet.
var classes = ["class1", "class2", "class3"];
var index = 0;
var classList = document.querySelector("div").classList;
const len = classes.length;
$('.toggle').click(function() {
classList.replace(classes[index++ % len], classes[index % len]);
});
.class1 {
background: yellow;
}
.class2 {
background: orange;
}
.class3 {
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Toggle classes
<div class="class1">
look at me!
</div>

Categories