I'm getting some weird behavior trying to implement a conditional for the style of items in Vuejs.
I have seen S.O. posts on how to implement a ternary, via both an interpolated string or a computed style object. I've tried both but neither works properly.
Given this div:
<div
:class="{'radar__container':true,'inactive':inactive}"
:style= "[inactive ? {getStyleRadarContainerInactive} : {getStyleRadarContainer}]"
>
I would implement this style:
computed: {
getStyleRadarContainer: function(){
let styleRadarContainer = {
left: this.radarItem.posX*100 + '%',
top: this.radarItem.posY*100 + '%',
transform: 'translate(-50%,-50%) scale(' + this.radarItem.scale + ')',
opacity: this.radarItem.opacity,
}
return styleRadarContainer;
},
getStyleRadarContainerInactive: function(){
let styleRadarContainerInactive= {
left: this.radarItem.posX*100 + '%',
top: this.radarItem.posY*100 + '%',
transform: 'translate(-50%,-50%) scale(0)',
opacity: this.radarItem.opacity,
}
return styleRadarContainerInactive;
},
}
This should make each of these items scale down (because of the scale(0) in opacity property),but instead the style attribute doesn't render at all. I also tried an inline ternary on the style prop (since that scale is the only thing that changes between the two properties:
transform: 'translate(-50%,-50%) ' + inactive ? 'scale(' + radarItem.scale + ')' : 'scale(0)',
What am I missing?
The style binding expects an object. By wrapping the ternary in square brackets, you're passing in an array containing an object, which is unnecessary. Also, you're wrapping the returned object on either side of the ternary in brackets, which is nesting them further. Removing those brackets will let the returned object can be handled in correctly:
<div
:class="{'radar__container':true,'inactive':inactive}"
:style= "inactive ? getStyleRadarContainerInactive : getStyleRadarContainer"
>
As a side note, if you add a variable containing an object to another object without specifying property name, the variable name is used as a property name.
var myObject = {
property: 'value'
};
$('#output').html(JSON.stringify({myObject}));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="output"></div>
try to use condition in V-bind:style
v-bind:style= "[condition ? {style_A} : {style_B}]"
https://v2.vuejs.org/v2/guide/class-and-style.html
There should work if you use spread operator like this:
:style= "[inactive ? {...getStyleRadarContainerInactive} : {...getStyleRadarContainer}]"
Your solution did not work because you produced double curly brackets
:style="[{ obj: { styleObject }}]" // This won't work
You can either have an array containing styleObjects or only a styleObject.
E.g.
:style="[ { color: 'blue' } ]"
:style="{ color: 'blue' }"
Related
So I want to create a dynamic key in a js object. I know I can create it like this but id doesn't fullfil my requirements
return {
[dynamicKey]: value
}
But the problem is I want something like this
return {
[dynamicKey]_id: value
}
but it doesn't let me, I tried concatenating but it didn't work.
return {
[dynamicKey] + '_id': value
}
I've also searched online for a solution but couldn't find any.
you need to put your _id string inside of the square brackets or as part of the dinamicKey var.
return {
[dinamicKey + '_id']: value
}
dinamicKey += '_id';
return {
[dinamicKey]: value
}
Any expression in the square braces will be executed just like a normal expression.
So how about this:
return {
[dinamicKey + '_id']: value
}
I want to convert my node style attribute value to a js object which contains all the CSS properties and its values.
Style attribute value
background-image:url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwgHBgoICAgLEhYLDhAVDhkVDhEQFhUYFxMZGBYVFhUdKysjHR0oHR0WJDUlKC0vMjIyGSI4PTcwPCsxMi8BCgsLDg0OHBAQHDsoIh0vLy87Ozs7Oy87LzsvLy8vNS8vLy8vLzUvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL//AABEIABAAGAMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAADBQEEBwD/xAAeEAABBAIDAQAAAAAAAAAAAAAAAQIDIQQSExQxEf/EABYBAQEBAAAAAAAAAAAAAAAAAAMEAv/EABoRAAICAwAAAAAAAAAAAAAAAAECACEDETH/2gAMAwEAAhEDEQA/ANTbnMkpAvZaxLE2DGv30uzsXQlU7E0UyrTdhJc1rqOFnGuxIqioZGaf/9k=);background-color:#00cc7e;background-size:cover;opacity:1;transition:opacity 500ms 500ms;position:absolute;left:0;top:0;width:100%;height:100%
Convert it to JS Object
{
backgroundImage: url(data;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwgHBgoICAgLEhYLDhAVDhkVDhEQFhUYFxMZGBYVFhUdKysjHR0oHR0WJDUlKC0vMjIyGSI4PTcwPCsxMi8BCgsLDg0OHBAQHDsoIh0vLy87Ozs7Oy87LzsvLy8vNS8vLy8vLzUvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL//AABEIABAAGAMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAADBQEEBwD/xAAeEAABBAIDAQAAAAAAAAAAAAAAAQIDIQQSExQxEf/EABYBAQEBAAAAAAAAAAAAAAAAAAMEAv/EABoRAAICAwAAAAAAAAAAAAAAAAECACEDETH/2gAMAwEAAhEDEQA/ANTbnMkpAvZaxLE2DGv30uzsXQlU7E0UyrTdhJc1rqOFnGuxIqioZGaf/9k=): undefined;
backgroundColor: #00cc7e;
backgroundSize: cover;
opacity: 1;
transition: opacity 500ms 500ms;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%
}
Any helpful answer will be appreciated.
You can try methods of CSSStyleDeclaration.
Here getStyles is of type CSSStyleDeclaration which will give list of inline style properties.
const getStyles = document.getElementById('img').style;
const properties = Array.from(getStyles).reduce((acc, curr) => {
acc[curr] = getStyles.getPropertyValue(curr)
return acc;
}, {})
console.log(properties)
<img id='img' style="background-image:url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwgHBgoICAgLEhYLDhAVDhkVDhEQFhUYFxMZGBYVFhUdKysjHR0oHR0WJDUlKC0vMjIyGSI4PTcwPCsxMi8BCgsLDg0OHBAQHDsoIh0vLy87Ozs7Oy87LzsvLy8vNS8vLy8vLzUvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL//AABEIABAAGAMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAADBQEEBwD/xAAeEAABBAIDAQAAAAAAAAAAAAAAAQIDIQQSExQxEf/EABYBAQEBAAAAAAAAAAAAAAAAAAMEAv/EABoRAAICAwAAAAAAAAAAAAAAAAECACEDETH/2gAMAwEAAhEDEQA/ANTbnMkpAvZaxLE2DGv30uzsXQlU7E0UyrTdhJc1rqOFnGuxIqioZGaf/9k=);background-color:#00cc7e;background-size:cover;opacity:1;transition:opacity 500ms 500ms;position:absolute;left:0;top:0;width:100%;height:100%">
Well you can definitely do that by:
let element = document.querySelector("your-selector-here")
console.log(element.style)
But let me warn you that you'll get a very big object of css properties because your element has more css properties than what you define in you style-sheet.
Why you wanna do so ?
If its style of an element you can grab it by first selecting the element in your js and then getting style using element.style ,you can slect element by various methods such as by its ID, class etc. Tho this will give you all the element's style including the default one's.
console.log(document.querySelector('#test').style)
<div id="test"></div>
This shall be used in worst case scenario until you can filter the default one's.
If you have the style as a sting with you, and you want to convert it to object, you can use JSON.parse ,but before that you will have to convert you styles into object format, replace ';' with ',' and convert each individual key and value to string. This might not be easy.
const test = 'background-color:#00cc7e;background-size:cover;opacity:1;transition:opacity 500ms 500ms;position:absolute;left:0;top:0;width:100%;height:100%';
var afterReplace = test.replaceAll(";", '","').replaceAll(":", '":"');
objectForm = JSON.parse('{"' + afterReplace + '"}')
console.log(objectForm)
Here add string value of the style in test from which we replace all ';' to '";"' and ':' to '":"' then we add {" and "} to both start and end, and finally parse it into a json object.
Though I would suggest you not to use it.
This answer is incorrect but I thought it was important to leave here. While it works fine in Chrome, it doesn't work in Firefox, where the CSS2Properties object they return don't have enumerable property.
This method goes through the computed style of the element, so it has some browser-specific values. element.style has all possible style attributes, so this filters out the empty ones and returns the balance as a javascript notation style object
let element = document.querySelector('#element');
let styleobj = Object.fromEntries(Object
.entries(element.style)
.filter(e => isNaN(e[0]) && e[1].trim())
)
let element = document.querySelector('#element');
let styleobj = Object.fromEntries(Object.entries(element.style).filter(e => isNaN(e[0]) && e[1].trim()))
console.log(styleobj)
<div id='element' style='background-image:url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwgHBgoICAgLEhYLDhAVDhkVDhEQFhUYFxMZGBYVFhUdKysjHR0oHR0WJDUlKC0vMjIyGSI4PTcwPCsxMi8BCgsLDg0OHBAQHDsoIh0vLy87Ozs7Oy87LzsvLy8vNS8vLy8vLzUvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL//AABEIABAAGAMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAADBQEEBwD/xAAeEAABBAIDAQAAAAAAAAAAAAAAAQIDIQQSExQxEf/EABYBAQEBAAAAAAAAAAAAAAAAAAMEAv/EABoRAAICAwAAAAAAAAAAAAAAAAECACEDETH/2gAMAwEAAhEDEQA/ANTbnMkpAvZaxLE2DGv30uzsXQlU7E0UyrTdhJc1rqOFnGuxIqioZGaf/9k=);background-color:#00cc7e;background-size:cover;opacity:1;transition:opacity 500ms 500ms;position:absolute;left:0;top:0;width:100%;height:100%'></div>
I'm trying to assign styles to an object. Initial code was
targetEl.style.top = `${top}px` ;
targetEl.style.display = 'block';
targetEl.style.background = `url(${this.props.imgSrc}) no-repeat`;
targetEl.style.backgroundSize = "1800px 900px";
I tried to use es6 destructuring and rewrote the code like this:
targetEl.style = {...targetEl.style,
top:`${top}px`,
display: 'block',
background: `url(${this.props.imgSrc}) no-repeat`,
backgroundSize: "1800px 900px" };
But for some reason it does not seem to work. What am I doing wrong?
You are not using destructuring, you are using experimental spread syntax in an object literal which creates a new object. You might be used to that when working with immutable data frameworks, but here you really want to assign properties of the targetEl.style CSS declaration object. You do not want to replace the whole .style object with a new one.
Try Object.assign with a plain literal:
Object.assign(targetEl.style, {
top: `${top}px`,
display: 'block',
background: `url(${this.props.imgSrc}) no-repeat`,
backgroundSize: '1800px 900px'
});
As a side note, it's a bit more efficient without Object.assign:
const s = targetEl.style;
s.top = `${top}px`;
s.display = 'block';
s.background = `url(${this.props.imgSrc}) no-repeat`;
s.backgroundSize = '1800px 900px';
but even more efficient to assign them all at once (How can I set multiple CSS styles in JavaScript?) :
targetEl.style.cssText += `; top = ${top}px, display = 'block',
background = url(${this.props.imgSrc}) no-repeat, backgroundSize = '1800px 900px'; `;
I read VueJs docs, It recommends to use computed property to calculate or toggle an element class, but I couldn't do it inside v-for loop. What I have done instead is this:
Template
<li v-bind:click="onClick(word)" v-bind:class="calculateClass(word)" v-for="word in words">{{ word.name }}</li>
Code
data: {
words : [{name:'ali', clicked : 1},{name:'sara', clicked : 0},{name:'marya', clicked : 1}]
},
methods: {
calculateClass : function (word) {
return {
"classA": word.clicked=== 1,
"classB" : word.clicked === 0,
'test' : true // allways return 'test' class
}
},
onClick: function (word) {
// changing the `clicked` property of related object in this.words array
for (var i in this.words) {
if (this.words[i].name === word.name) {
this.$set(this.words[i], 'clicked', 1)
break; //Stop this loop, we found it!
}
}
}
},
It is working, but is there a problem with this approach? I didn't see other examples using a method to calculate a class. Should I do this with computed? How? Is there a better way?
You are correct that a computed property cannot accept an argument and, as such, doesn't really fit in this case.
There is nothing wrong with using a method the way you are.
In an application where certain elements have custom CSS properties, is there any way to retrieve such a value via JavaScript?
e.g.
<div id="myDiv" style="color:#f00;-my-custom-property:upsidedown;" />
I can access the color attribute via these two methods:
document.getElementById('myDiv').style.getPropertyValue("color")
document.getElementById('myDiv').style.color
But these do not work for custom properties. Is this supported at all?
CSS values not understood by the browser are discarded, which explains why -my-custom-property was unavailable via .style.
In the past, you would have had to rely on storing the data with data attributes and dealing with inheritance yourself via JavaScript.
However, "custom properties", aka "CSS variables", have since been introduced into the standard and implemented by browsers, with ~92% support globally as of 2019-05-09. At a quick glance, Edge seems to have been the last major browser to implement, with version 16 on October 16, 2017.
Essentially, you need to set a custom property (eg, --my-custom-property: 'foobar';) on an element, and it can be accessed with something like getComputedStyle(your_el).getPropertyValue("--my-custom-property") which would return 'foobar' (with a leading space). Note the leading space and quotation marks. It will return the value exactly as it was provided.
Example:
console.log(getComputedStyle(document.getElementById("a")).getPropertyValue("--my-custom-property-1"))
console.log(getComputedStyle(document.getElementById("b")).getPropertyValue("--my-custom-property-2"))
#b-div { --my-custom-property-2: 'world' }
<div style="--my-custom-property-1: 'hello'"><h1 id="a">#a 'hello'</h1></div>
<div id="b-div"><h1 id="b">#b 'world'</h1></div>
Here's some testing using one and two leading hyphens, inheritance, and different methods of retrieving the value:
function log(computed, selector, prop, value) {
let method = computed ? "getComputedStyle(el)" : "el.style"
let method_id = computed ? "computed" : "raw"
// Build first level of list (tag name)
let first = document.querySelector("#" + selector)
if (!first) {
first = document.createElement("li")
first.appendChild(document.createTextNode(selector))
first.setAttribute("id", selector)
first.appendChild(document.createElement("ul"))
document.querySelector("ul").appendChild(first)
}
// Build second level of list (method of style retrieval)
let second = document.querySelector("#" + selector + "-" + method_id)
if (!second) {
second = document.createElement("li")
second.appendChild(document.createTextNode(method))
second.setAttribute("id", selector + "-" + method_id)
second.appendChild(document.createElement("ul"))
first.querySelector("ul").appendChild(second)
}
// Build third level of list (property accessed)
let third = document.querySelector("#" + selector + "-prop" + prop)
if (!third) {
third = document.createElement("li")
third.appendChild(document.createTextNode(prop + ": `" + value + "`"))
third.setAttribute("id", "prop" + prop)
second.querySelector("ul").appendChild(third)
if (value === "") {
third.classList.add("bad")
} else {
third.classList.add("good")
}
}
}
// Uses .style
function getStyleAttr(selector, prop) {
let value = document.querySelector(selector).style.getPropertyValue(prop)
log(false, selector, prop, value)
}
// Uses getComputedStyle()
function getStyleComputed(selector, prop) {
let value = getComputedStyle(document.querySelector(selector)).getPropertyValue(prop)
log(true, selector, prop, value)
}
// Loop through each property for each element and output the value
let selectors = ["article", "h1", "p"]
let props = ["--my-custom-property", "-my-custom-property"]
selectors.forEach(function(selector) {
props.forEach(function(prop) {
getStyleAttr(selector, prop)
getStyleComputed(selector, prop)
})
})
code {
background: #eee;
padding: .2em;
}
.bad {
color: #800;
}
.good {
color: #080;
}
<article class="custom-prop-inheritance" style="--my-custom-property: 'foobar'; -my-custom-property: 'foobar'">
<h1>Title</h1>
<p>Custom properties require two leading hyphens (<code>-my-custom-property</code> <em>never</em> works). Using <code>el.style</code> does not support inheritance. To support both inheritance and custom properties, you must use <code>getComputedStyle(<b>el</b>)</code> along with two leading hyphens on the custom property (eg, <code>--my-custom-property</code>).</p>
</article>
<ul></ul>
CSS:
:root {
--custom-property: #000000;
}
Javascript:
var custom_property = window.getComputedStyle(document.body).getPropertyValue('--custom-property').trim()
Non-recognised CSS properties will be ignored when put within the style attribute, or in the style.cssText property.
If you want to define a property at a specific element, I recommend data-attributes:
HTML:
<div id="myDiv" style="color:#f00;" data-custom-property="upsidedown" />
JavaScript:
//jQuery's method to retrieve value:
$("#myDiv").data("custom-property");
//jQuery, without parsing:
$("#myDiv").attr("data-custom-property");
// Modern browsers, native JS:
document.getElementById("myDiv").dataset["custom-property"];
// Older browsers, native JS:
document.getElementById("myDiv").getAttribute("data-custom-property");
This is actually now possible for all browsers using a specialized CSS hack via the CSS content tag. This article explains how to do it:
http://www.yearofmoo.com/2015/04/cross-browser-custom-css-properties.html
function getCustomCssProperty(elementID, propertyName){
var style = document.getElementById(elementID).getAttribute("style");
var entries = style.split(";");
for (var i=0; i<entries.length; i++){
var entry = entries[i].split(":");
if(entry[0] == propertyName){
return entry[1];
}
}
return null;
}
You can't use data-* attributes (html5)?
That would at least be valid and not a strange hack.