Saving a reference to .innerHTML - javascript

This works:
var button = $A("#aba_but_del")[0];
button.innerHTML = Su.Ani.flipPane.p1;
But this does not work
var button_text = $A("#aba_but_del")[0].innerHTML;
button_text = Su.Ani.flipPane.p1;
Why?
According to https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Operator_Precedence, the . has highest precedence. Does this mean that .innerHTML is being applied to [0]?

All primitives in javascript are immutable. This means that the following code just changes a different instance of a string:
button_text = Su.Ani.flipPane.p1;
In the first case button is an object referencing a DOM element. So when changing the innerHTML property value you are changing the DOM element itself.

button_text = ... replaces the variable with the value.
button.innerHTML = ... replaces the property of the object, which in turn affects the displayed HTML because of how the setter function works for that property.

You can't have a reference to a property.
When you do like this:
var button = $A("#aba_but_del")[0];
you get a reference to the element, so later on you can use that reference to access members of the element.
When you do like this:
var button = $A("#aba_but_del")[0].innerHTML;
you get the value of the property, not a reference to the property. The value is a string taht you assign to the button variable, and assigning a different string to the variable doesn't change the first string, and not the object where that string was copied from.
"The . has highest precedence. Does this mean that .innerHTML is being
applied to [0]?"
No. The [] operator has the same precedence as the . operator, as they are actually the same operator, so they are evaluated from left to right. Using obj['name'] is the same as obj.name, but the . operator can't be used with a property name that doesn't follow the rules of an identifier, like a numeric index.

1)
button_text is a string, no longer bound to the button DOM object.
So changing it will not impact the button element.
2)
Does this mean that .innerHTML is being applied to [0]? Yes. "." and "[]" have the same priority going from left to right.

JavaScript has no pointers or such stuff. If you assign something to a variable, you overwrite the previous value. You want to assign to the innerHTML property of the DOM object, changing the page rendering.

Related

Javascript getComputedStyle - copy object without reference

I want to change the color of an input field border. But yet before changing, I need to save the initial CSS via getComputedStyle so that I can set all the initial CSS of the input field back.
The problem is that the object of getComputedStyle is not fixed and changes dynamically.
I tried to copy the object into a new one without reference, but then I cannot use the property getPropertyValue because it is a different type of object.
Is there any way how I could retrieve back the initial CSS of the input field?
My code is the following:
const input_element = document.getElementById('text-id');
let computedStyle_fixed;
function change_color() {
// get computed style
const computedStyle = window.getComputedStyle(input_element);
// copy computed style into new object without reference
computedStyle_fixed = JSON.parse(JSON.stringify(computedStyle));
// change the border color of the input field
input_element.style.borderColor = 'red';
}
function retrieve_color() {
Array.from(computedStyle_fixed).forEach(
key => element.style.setProperty(key, computedStyle_fixed.getPropertyValue(key), 'important')
)
}
<input type='text' id='text-id'>
<button onclick='change_color()'>Change color</button>
<button onclick='retrieve_color()'>Retrieve color</button>
from what I understood is that you need all the css properties of a element and store in an object.
you can use spread operator to do so.
const computedStyle = {...window.getComputedStyle(input_element)};
you can now use this like a normal object.
ex : console.log(computedStyle.backgroundColor);
There are a number of issues in your code. Firstly in this line:
const computedStyle = window.getComputedStyle(input_element);
window.getComputedStyle returns a CSSStyleDeclaration object. When copied using:
computedStyle_fixed = JSON.parse(JSON.stringify(computedStyle));
the object assigned to computedStyle_fixed is a plain object, not a CSSStyleDeclaration object. This has consequences in the retrieve_color function explained further down.
Then in:
Array.from(computedStyle_fixed)
Array.from expects the argument to be an array–like object with a length property or an iterable object. computedStyle_fixed is neither so the result is an empty array and the following forEach does nothing (because length is 0).
Within the forEach callback, there is:
computedStyle_fixed.getPropertyValue(key)
the computedStyle_fixed object doesn't have a getPropertyValue method (see above), so if that line is executed the result will be a type error.
To iterate the properties of the computedStyle_fixed object, use Object.keys and access properties using square bracket notation, not the (missing) getPropertyValue method, e.g.
Object.keys(computedStyle_fixed).forEach(key =>
element.style.setProperty(key, computedStyle_fixed[key], 'important')
);
Other notes
Creating implicit globals like computedStyle_fixed is not recommended, declare them or set them as object properties.
Using JSON.stringify to create a shallow copy of an object is also not a good idea, it's much better to use Object.assign:
let computedStyle_fixed = Object.assign({}, computedStyle);
This also creates a plain object, not a CSSStyleDeclaration object.
I have solved it, I have just change a little the retrieve_color() function.
But I thought that it would set the style of the input border exactly as it used to be initialy.
If you look at the code at jsfiddle and click on change_color and then click on retrieve_color, you will see that the input does not look as it was (the border are different).
Do you have any idea how I could get it back exactly as it was?
// the code
https://jsfiddle.net/gfxjn4se/

Why doesn't DOM style object set CSS variables directly?

My understanding is there are two equivalent ways to set CSS rules via JavaScript:
#1: element.style.setProperty(propertyName, value)
#2: element.style.propertyName = value
I have always favored the second, shorter method.
When it comes to CSS variables, I find I have to use an explicit setProperty call:
element.style.setProperty('--varName', value)
This approach has no effect on variables:
element.style['--varName'] = value
Why is this?
It's because DOM's Style function only understands HTML properties and not CSS properties. Defining CSS properties are listed in style's setProperty Function.
The .style[propertyName] expects a property name inside but does not support a custom property like .setProperty() does. If you pass --varName, you are passing the value assigned to the brackets.
For example, if --varName: 'blue', by saying .style['--varName'] = value, you are saying change the blue property to value. Since blue is not a property, it will not work.
You need to retrieve it from getComputedStyle
see : https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties#Values_in_JavaScript
To use the values of custom properties in JavaScript, it is just like standard properties.
// get variable from inline style
element.style.getPropertyValue("--my-var");
// get variable from wherever
getComputedStyle(element).getPropertyValue("--my-var");
// set variable on inline style
element.style.setProperty("--my-var", jsVar + 4);
document.body.style.setProperty('--varName', 'see i got stored even i`m a useless value');
let root = window.getComputedStyle(document.body );
let varNameValue= root.getPropertyValue('--varName');
console.log(varNameValue);

attach string variable to document object

I have a variable called current_slide which contains a string called "default"
Now I have a object called document.referencemap:
How can I attach the "default" string from current_slide to the object document.referencemap so that I will get
document.referncemap.default ?
What is the best way to attach a string to the object?
At the moment I am calling the object property manually like:
document.referncemap.default.
Can anybody give me a hint so I can solve this issue?
My code looks like this
Because the current slide is always changing i need to load the object from the value of current_slide.
You can use this:
temp0 = document.referencemap[current_slide.slide];
Explanation:
There are two ways to get values from Javascript objects,
using property notation: temp0 = document.referencemap.welcome;
using dictionary notation: temp0 = document.referencemap["welcome"];
This will get the exact same item from the object. Note however that 2. uses a string key. Because of that you can also use a variable that contains a string, in this case: temp0 = document.referencemap[current_slide.slide];
use:
document.referencemap[current_slide] = booBar
make sure current_slide is of type string. Read the Property accessors
docs for more information.

Get a direct reference to a JavaScript property

After answering this question about using the style.top property of a div in jQuery's $.animate(), I started to wonder if there was a way to do it more in line with what the OP had thought (s)he could do.
The question is: can we get a direct reference to an object's property when that property is a primitive type?
For example, if you had an object called myDiv, you could get a reference to its style property, because that's an object, but is there any way to get a reference to the top property of style so that when this changes, you don't have to retrieve it again and again? (Note: I'm not saying this retrieval is computationally significant. This is just a question about what's possible, not what's good practice.)
var myDiv = document.getElementById('myDiv');
myDiv.style.top = "100px";
var myDivStyle = myDiv.style;
var myDivStyleTop = myDiv.style.top;
myDiv.style.top = "200px";
console.log(myDivStyle.top); // will print "200px"
console.log(myDivStyleTop); // will obviously print "100px"
Is there a way to reference that top property directly without going through style? My instinct is no, but JS has surprised me before, so I just wanted to make sure.
No. A variable are just simple container that can hold a value. Assigning a new value to a variable can never change the value of another variable or property.
In this regard, it doesn't matter whether the variable holds a primitive values or an object, that's just how variables work.
No there isn't. Primitives are immutable and never stored by reference.
From MDN
object reference
A link to an object. Object references can be used as if they were the objects they link to. The concept of object references arises when assigning the same object to more than one property. Each assigned property does not hold a copy of the object. Instead, they hold object references that link to the same object. In practice, this means that if the object is modified, all properties referring to the object reflect the modification.
primitive, primitive value
A data that is not an object and does not have any methods. JavaScript has 5 primitive datatypes: string, number, boolean, null, undefined. With the exception of null and undefined, all primitives values have object equivalents which wrap around the primitive values, e.g. a String object wraps around a string primitive. All primitives are immutable.

Reference to a javascript variable in an HTML tag

I am trying to "link" a tag value to a javascript variable (and ideally to a function, but well a variable is a good start), by reference.
I know I can do a myDom.value = myVar but then if the value of myVar change the tag will not be modified.
Is it possible to do this (not using events, because it would be so heavy)?
Thank you :)
No.
You can fake references by assigning objects to things, but only if the property you assign the object to is expecting an object and knows to pull data out of it instead of stringifying it and using it directly.
You could use a closure function around the variable. So instead of attaching the value, you attach a function which will return the variable:
myDom.valueAccessor = function(){ return value }
After this you can access the result as:
myDom.valueAccessor()
This will track the value in value as it changes. Obviously you could choose a snappier name for your function. This seems to work for me in Firefox.

Categories

Resources