Set value of div with contenteditable=true - javascript

Given a div with contenteditable=true, how can I add text to the element?
<div aria-autocomplete="list" contenteditable="true" role="textbox" spellcheck="true">
</div>
I've tried document.activeElement.value, but since it's a div I can't set the value

With the other answers about innerHTML, I am afraid if innerHTML without sanitization might give attackers a chance to run unwanted malicious code.
I would rather go with textContent because the OP wants to add text.
HTML:
<div id="content" aria-autocomplete="list" contenteditable="true" role="textbox" spellcheck="true">
</div>
JAVASCRIPT:
document.getElementById('content').textContent = 'My text';
If you want to render HTML tags too you need a sanitization callback to filter tags like SCRIPT tag as an example.

You can just change the innerHTML of the div. So for example:
document.activeElement.innerHTML = "Changed text";
You can also get the current contents of the div by getting the same property, for example:
alert("User entered text: " + document.activeElement.innerHTML);

A React ref version answer of this question:
// set the init value to it
const initText = "123\n123123\n123123123";
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
if (ref && ref.current) {
ref.current.innerText = initText;
}
}, []);
const handleInput = (e: ChangeEvent<HTMLDivElement>) => {
console.log("input:", e.target.innerText);
};
notice that we are using innerText here,
for innerHtml, textContent they won't give a default line-change for \n with the code below
<div
ref={ref}
contentEditable={true}
onInput={handleInput}
style={{
height: 200,
width: 200,
border: "1px solid black",
display: "table-cell",
verticalAlign: "middle",
textAlign: "left",
padding: 8
}}
></div>
additionally, we can use CSS :empty to let the initial cursor keep at the vertical center as well
.InputField {
height: 200px; // initial height, real size could auto increase
...
}
.InputField:empty {
line-height: 200px; // the same initial height's value as above
}

I've found that the best way to set the content is:
target.firstChild.data = "<some-new-value>";
..where the firstChild is the textNode.

Related

How to set focus on an image on page load

Is there a way to set the focus on an on page load? I have found documentation stating to use the autofocus attribute but the documentation says that attribute only applies to input, button, textarea, and select.
Thanks.
You can try scrollIntoView method on window onload
window.onload=function(){
document.getElementById("ID_OF_IMAGE").scrollIntoView();
}
I think you looking for something like that:
window.addEventListener('load', function() {
document.querySelector(".classFromImage").focus();
})
What you could do is search for the img element with the autofocus attribute and set the focus after the DOM is read. You also need to set the tabindex to get that working.
I would only search for img[autofocus] so that you don't mess too much around with the default behavior.
window.addEventListener('DOMContentLoaded', function() {
let elm = document.querySelector("img[autofocus]")
if (elm) {
elm.focus()
}
})
img {
width: 100px;
height: 100px;
display: inline-block;
}
:focus {
border: 4px solid red;
}
<img autofocus tabindex="0">
You can focus a nonfocusable element by adding tabindex="0" attribute to the tag and use focus() method with js.
<img class="focusable" tabindex="0" src="#"/>
window.addEventListener('load', function() {
document.querySelector(".focusable").focus();
})

How can I change the background color of element in an array

I have an array of 5 divs
`<div id="cap-left2"</div>`
`<div id="cap-left1"</div>`
`<div id="cap-base"</div>`
`<div id="cap-right1"></div>`
`<div id="cap-right2"</div>`
all these divs have a background .
In my javascript I have :
let items = [capBase,capLeft1,capLeft2,capRight1,capRight2];
this works :
`var tom = items[Math.floor(Math.random()*items.length)]
console.log(tom)`
and this works
`var tom = items[Math.floor(Math.random()*items.length)]`
`console.log(tom.style)`
but I want the backgroundColor and neither of these work:
`var tom = items[Math.floor(Math.random()*items.length)]`
`console.log(tom.style.background)`
`var tom = items[Math.floor(Math.random()*items.length)]`
`console.log(tom.style.backgroundColor)`
what I am trying to do is lets say i have 5 swatches represented by 5 elements in an array . i want to be able to have a button that allows me to randomize what colors fill each element
any help would be appreciated
element.style represent style of the element, it will only be populated if style attribute is present (aka in-line style), CSS style will not affect that object.
So, element.style.backgroundColor will be empty, unless element has style="background-color: red;" as an attribute.
If you need get actual rendered style of an element, use
window.getComputedStyle(element).backgroundColor
document.querySelectorAll("div").forEach( div =>
{
console.log("style: " + div.style.backgroundColor, "final: " + window.getComputedStyle(div).backgroundColor, div);
});
body > div[id]
{
width: 1em;
height: 1em;
background-color: green;
border: 1px solid black;
}
<div id="cap-left2"></div>
<div id="cap-left1" style="background-color: red;"></div>
<div id="cap-base"></div>
<div id="cap-right1"></div>
<div id="cap-right2"></div>
const xx = window.getComputedStyle(searchBtn).getPropertyValue('background-color')
console.log(xx)
you can access only inline css proprty values via styleproperty. You need getComputedStyle

how to pass style using dangerouslySetInnerHTML in React

I'm injecting html in my react component using dangerouslySetInnerHTML in a format like this :
<div
className="mt-2 col variant-attr-cell p-0"
dangerouslySetInnerHTML = { {
__html: JSON.parse(attrs[i].snippet).snippet.replace("{text}",
attrs[i].choices[j].visualization_data)
} }
>
</div>
and it works fine but I'm trying to pass style to the injected html at the same time but don't know how!
I'm trying to add different styles to the injected html based on the api I get, something like this:
height: 12px;
width: 12px;
border-radius: 50%;
display: inline-block;
margin: 0 4px;
FYI the injected html is something like this mostly:
<span></span>
and the styles must be added to this and not the container div!
Any solution is appreciated,
thanks.
You can still add the desired style. Just add another props style:
const styleObj = {
color: 'white',
backgroundColor: 'red'
};
<div
className="mt-2 col variant-attr-cell p-0"
dangerouslySetInnerHTML = {
{ __html: JSON.parse(attrs[i].snippet).snippet
.replace("{text}", attrs[i].choices[j].visualization_data)
}
}
style={styleObj}
>
</div>
If you're trying to add style inside the element that resides in the html, then you should have their styles there in the html itself.
I managed to do this by adding a ref to the container and using the useLayoutEffect hook.
const elRef = useRef();
useLayoutEffect(()=>{
if (elRef.current){
elRef.current.firstElementChild.style.height = '12px';
// set other style attributes
...
}
});
return <div
ref={elRef}
dangerouslySetInnerHTML={yourHTML}
/>
This assumes you only want to style the first child of your container, but you could use a similar approach for multiple children.
Since I get the HTML from API, I set the style attribute for the HTML with a static value in the database and replaced the static value from API in my component!
You can easily style element in dangerousHTML like this style='background-color:red' instead style={{backgroundColor:'red'}}

Retrieve CSS value, not inline-style value

In Javascript, can I retrieve the CSS values of an element without taking account of its inline style?
example:
body { font-size: 15px; }
<body style="font-size: 20px;">
Is there a way I can retrieve "15px" and not "20px"?
Yes, of course! Just get rid of the style attribute, use getComputedStyle(), and add the style attribute back:
//Get the body's style attribute:
var bodyStyle = document.body.getAttribute("style");
//Now, get rid of it:
document.body.removeAttribute("style");
//Now use getComputedStyle() to compute the font size of the body and output it to the screen:
document.write( getComputedStyle(document.body).fontSize );
//Now add the style attribute back:
document.body.setAttribute("style", bodyStyle);
body { font-size: 15px; }
<body style="font-size: 20px;">
</body>
var a = document.getElementsByTagName('body');
console.log (a[0].attributes.style); // returns the current inline style
a[0].setAttribute('style','font-size : 15px'); // change it as required

The CSS input[value=whatever] selector doesn't seem to match against input.value. What am I missing?

N.B.: I should note that the proper solution to this is to just use the 'placeholder' attribute of an input, but the question still stands.
Another N.B.: Since, as Quentin explains below, the "value" attribute stores the default value, and the input.value IDL attribute stores the current value, the JavaScript I used to "fix" the problem in my below example is non-conforming, as it uses the (non-IDL) value attribute to store current, rather than default, values. Besides, it involves DOM access on every key press, so it was always just a flawed demo of the problem I was having. It's actually quite terrible code and shouldn't be used ever.
CSS selectors made me think that I could make an input with a label that acts as a preview without any JS. I absolutely position the input at 0,0 inside the label (which is displayed as an inline-block) and give it a background of "none", but only if it's got a value of "" and isn't focussed, otherwise it has a background colour, which obscures the label text.
The HTML5 spec says that input.value reflects the current value of an input, but even though input.value updates as you type into an input, CSS using the input[value=somestring] selector applies based only on what was explicitly typed into the document, or set in the DOM by the JavaScript setAttribute method (and perhaps by other DOM-altering means).
I made a jsFiddle representing this.
Just in case that is down, here is an HTML document containing the relevant code:
<!doctype html>
<head>
<meta charset="utf-8" />
<title>The CSS Attribute selector behaves all funny</title>
<style>
label {
display: inline-block;
height: 25px;
line-height: 25px;
position: relative;
text-indent: 5px;
min-width: 120px;
}
label input[value=""] {
background: none;
}
label input, label input:focus {
background: #fff;
border: 1px solid #666;
height: 23px;
left: 0px;
padding: 0px;
position: absolute;
text-indent: 5px;
width: 100%;
}
</style>
</head>
<body>
<form method="post">
<p><label>name <input required value=""></label></p>
</form>
<p><button id="js-fixThis">JS PLEASE MAKE IT BETTER</button></p>
<script>
var inputs = document.getElementsByTagName('input');
var jsFixOn = false;
for (i = 0; i < inputs.length; i++) {
if (inputs[i].parentNode.tagName == 'LABEL') { //only inputs inside a label counts as preview inputs according to my CSS
var input = inputs[i];
inputs[i].onkeyup= function () {
if (jsFixOn) input.setAttribute('value', input.value);
};
}
}
document.getElementById('js-fixThis').onclick = function () {
if (jsFixOn) {
this.innerHTML = 'JS PLEASE MAKE IT BETTER';
jsFixOn = false;
} else {
this.innerHTML = 'No, actually, break it again for a moment.';
jsFixOn = true;
}
};
</script>
</body>
</html>
I could be missing something, but I don't know what.
The value attribute sets the default value for the field.
The value property sets the current value for the field. Typing in the field also sets the current value.
Updating the current value does not change the value attribute.
Attribute selectors only match on attribute values.
There are new pseudo classes for matching a number of properties of an input element
:valid
:invalid
:in-range
:out-of-range
:required
A required element with no value set to it will match against :invalid. If you insist on using the value instead of placeholder, you could simply add a pattern or a customValidity function to force your initial value to be counted as invalid.

Categories

Resources