how to convert object to valid css styles in javascript? - javascript

i have an object and need to convert it into css, ex:
const options = {
style: {
base: {
background: 'red',
':hover': {
background: 'green',
},
},
},
};
i used package jso-to-css works fine but in case nested object like hover return [Object]
base{background:red;:hover:[object Object]}
instead of
base{background:red;}
base:hover{background: green;}
also, any suggestion compatible with react is welcomed.

If you change yor data structure - you can create style rules easily frm an object or JSON etc.
Knowing the anatomy of a style rule has three parts - selector / property and value - you can create a data structure to allow for these to be parsed into strings and then inserted either into an existing style sheet - or you can create an entirely new stylesheet, append it to the document head and then insert the rules.
You will need to create a plan to allow the code to know about nesting - for example - I am using pseudostates as a child array to allow the styling of the base element - and iterate over the pseudostates array and for each - pass it to the same createStyle function as the original base element, and create their style rules... you can do this to any depth and with any type of styling - you jsut need to plan for it and update the structure of the data to match the planned styling.
In the following - i am setting the background color and text color of the p element and then changing both on the hover. You could extend this to have the type of selector (id or class) - but will leave that for further development. This includes the "#" or the "." in the selector.
const options = [{
selector: '.base',
declarations: [{
property: 'background',
value: 'red',
},{
property: 'color',
value: 'white',
}],
pseudoStates:[{
selector: ':hover',
declarations: [{
property: 'background',
value: 'green'
},{
property: 'color',
value: 'orange'
},{
property: 'cursor',
value: 'pointer'
}]
}]
}, {
selector: '#extra',
declarations: [{
property: 'background',
value: 'aqua',
},{
property: 'color',
value: 'black',
}],
pseudoStates:[{
selector: ':hover',
declarations: [{
property: 'background',
value: 'blue'
},{
property: 'color',
value: 'white'
}]
}]
}]
options.forEach(function(option){
createStyleRule(option.selector, option.declarations);
option.pseudoStates.forEach(function(pS){
createStyleRule(option.selector + pS.selector, pS.declarations);
})
});
function createStyleRule(selector, declarations){
let styleDeclarations = [];
declarations.forEach(function(dec){
styleDeclarations.push( dec.property +": " + dec.value);
})
let styleRule = selector + " {" + styleDeclarations.join("; ") + "}";
document.styleSheets[0].insertRule(styleRule, 0);
}
<p class="base">This is the base element</p>
<p id="extra">This is the extra element</p>

Related

How to bind function in vue js v-model?

I asked a question which might be unclear to someone. So, I deleted that question and ask again with new approach. I have an API response something like this:
{
id: 2,
name: 'Item 1',
items: [
{
slug: 'Phase 1',
values: [
{
highValue: '12',
lowValue: '8',
color: 'red'
},
{
highValue: '15',
lowValue: '5',
color: 'green'
}
]
},
{
slug: 'Phase 2',
values: [
{
highValue: '14',
lowValue: '6',
color: 'red'
},
{
highValue: '15',
lowValue: '5',
color: 'green'
}
]
}
]
},
{
id: 3,
name: 'Item 2',
items: [
{
slug: 'CBC',
values: [
{
highValue: '10',
lowValue: '7',
color: 'green'
},
{
highValue: '12',
lowValue: '3',
color: 'red'
}
]
}
]
}
I have static block for High Value, Low Value, Red & Green in my HTML. So, for those static blocks, I need to pick appropriate value from the response. For example, for High Value & Red block, I need to pick highValue from the response when color: 'red'. So, I write four function for example:
redHigh (item) {
const res = item.filter(obj => {
return obj.color === 'red'
})
return res[0].highValue
}
Now, I tried to bind the function in v-model like this way:
<v-text-field
outlined
:v-model="redHigh(sub.values)"
placeholder="High"
></v-text-field>
But, that was not working. If I wrote :value instead of :v-model, that would work. But, in that case I don't get the changed value after clicking save button.
save (formIndex) {
console.log(this.items[formIndex])
}
How to solve that?
Codepen Demo
v-model is not for a function; it's for a Vue's data property.
However, I understand your app requirement.
You just need to create Vue computed properties, that can generate a dynamic array using a custom function bind input event from your text field
you can read $emit or v-bind documentation about it
I just read the API of v-text-field component here https://vuetifyjs.com/en/api/v-text-field/#props.
Just need to update it to use value prop and bind change event
Which is would be like this
<div v-for="(sub, index) in item.items" :key="sub.slug">
<v-text-field
outlined
:value="redHigh(sub.values)"
#change="updateSubValue(index, 'red', 'high')"
placeholder="High"
></v-text-field>
updateSubValue(index, color, value) {
// find current sub by index
// find current value's key by color and value
// update vue data
}
It might index first, been a long time I don't develop the Vue app
<div v-for="(index, sub) in item.items" :key="sub.slug">
Or you can find the current sub by slug, no need to add index

How do I find a certain value and replace it in and push all the values in a new array?

I have a very basic knowledge of Javascript. I am writing a plugin to search for some predefined colors and replace them with new colors. So far I am able to get an array containing colors, name and styles as an object inside the array.
Now I want to search for a certain color like - eb40a2 and replace it with ffffff and push this new value to a new array.
var ref=[];
....
ref.push({ name: styleName, color: styleColor, parent: styleParent, styles: styleId });
which is giving me the following array:
0: {name: "pink_theme/dark/fill/active", color: "eb40a2", styles: "S:5bebabedaa118ab6d135df59d7ba8861c05992a0,5:1"}
1: {name: "green_theme/light/fill/product", color: "c85200", styles: "S:380f15d999c08d9d97725c9915f479e52c1a343c,244:13"}
2: {name: "green_theme/light/fill/active", color: "00880d", styles: "S:b2aecc5927c659d7fba7d021b092bc90618043a5,189:0"}
3: {name: "green_theme/light/fill/product", color: "0081a0", styles: "S:1f28c38bfa1b10ca61aeaf706ac2a71fa6425950,244:11"}
You can map over the array and conditionally update the colors you want. Check the code snippet below:
const arr = [
{
name: 'pink_theme/dark/fill/active',
color: 'eb40a2',
styles: 'S:5bebabedaa118ab6d135df59d7ba8861c05992a0,5:1',
},
{
name: 'green_theme/light/fill/product',
color: 'c85200',
styles: 'S:380f15d999c08d9d97725c9915f479e52c1a343c,244:13',
},
{
name: 'green_theme/light/fill/active',
color: '00880d',
styles: 'S:b2aecc5927c659d7fba7d021b092bc90618043a5,189:0',
},
{
name: 'green_theme/light/fill/product',
color: '0081a0',
styles: 'S:1f28c38bfa1b10ca61aeaf706ac2a71fa6425950,244:11',
},
];
const newArr = arr.map(el => el.color === "eb40a2" ? {...el, color: "ffffff"}: el)
console.log(newArr)

Is it possible to both select and create the same value in react-select?

I'm trying to have a multi Creatable in which the user can both select a preset value, and "create" the same value by himself, both in the same interaction.
For example, my render look
import CreatableSelect from 'react-select/creatable';
function test(){
render(
<CreatableSelect
isMulti
onChange={this.handleChange}
options = [{ value: 'Blue', label: 'Blue'}, { value: 'Red', label: 'Red'}]
/>
);)
}
I want to let the user both choose 'Blue' as an option, and create the value 'Blue' as well. Namely, I want to output of handleChange to be:
[{ value: 'Blue', label: 'Blue'}, { value: 'Blue', label: 'Blue', __isNew__: true}]
It's not a UI problem for me, as I'm coloring selected values differently based on whether it was created or selected from the list.
Is it possible? I tried having isValidNewOption={() => true} as a prop, but it didn't work.
Found a workaround, which I would not prefer to use if there's a better way:
I can add a special character (or a string) as a prefix to all values (leaving the labels aas is). For example- transforming [{ value: 'Blue', label: 'Blue'}, { value: 'Red', label: 'Red'}]
into [{ value: '$Blue', label: 'Blue'}, { value: '$Red', label: 'Red'}]
Now, it lets my create a new value "Blue", and selecting the value "$Blue". As the label of "$Blue" is still "Blue", the user won't notice the difference.
Lastly, I need to remove the prefix in my onChange function.
It's not a very elegant solution, but better than nothing.

Can I dynamically change the selection options of my inspector in jointJS - Rappid

In my inspector.js I have declared this select box with name tr_rules which has 2 select options :
'tr_rules': { type: 'select', options: ['option1', 'option2'], group: 'attributes', label: 'Rule', index: 3 },
Is there any way I can define my inspector properly so that the array options will be initially empty and:
I will fill the options dynamically with the content of a var?
For example with the var optionsVariable which a specific time will be:
var optionsVariable = [myDynamicOption1, myDynamicOption2, myDynamicOption3];
For each link we will get random values for the marker-source.fill attribute:
This is the part of the KitchenSink demo application (http://resources.jointjs.com/demos/kitchensink)
createInspector: function(cell) {
var props = App.config.inspector[cell.get('type')];
if (cell.isLink()) {
var a = {
inputs: {
attrs: {
'.marker-source': {
transform: {
type: 'select',
options: [Math.round(Math.random() * 100), Math.round(Math.random() * 100), Math.round(Math.random() * 100)],
}
}
}
}
};
_.merge(props, a);
}
return joint.ui.Inspector.create('.inspector-container', _.extend({
cell: cell
}, props));
},
the App.config.inspector has definitions for the Inspector in separate file
App.config.inspector = {
'app.Link': {
inputs: {
attrs: {
'.marker-source': {
transform: {
ty pe: 'select',
group: 'marker-source',
label: 'Source arrowhead',
index: 1
},
fill: {
type: 'color-palette',
options: options.colorPalette,
group: 'marker-source',
label: 'Color',
when: { ne: { 'attrs/.marker-source/transform': 'scale(0.001)'}},
index: 2
}
},
'.marker-target': {
transform: {
type: 'select',
options: options.arrowheadSize,
group: 'marker-target',
label: 'Target arrowhead',
// ...
In inspector set your options to the variable you want.
if you want to display the option using a dependency you can also do this with the when propriety for example
var dynamicOptions = [
{ value: 'Alegreya Sans', content: '<span style="font-family: Alegreya Sans">Alegreya Sans</span>' },
{ value: 'Averia Libre', content: '<span style="font-family: Averia Libre">Averia Libre</span>' },
{ value: 'Roboto Condensed', content: '<span style="font-family: Roboto Condensed">Roboto Condensed</span>' }
]
text: {
type: 'content-editable',
label: 'Text',
group: 'text',
index: 1
},
'font-family': {
type: 'select-box',
options: dynamicOptions,
label: 'Font family',
group: 'text',
when: { ne: { 'attrs/text/text': '' }},
index: 3
},
will only display the input font-family select box when the Text box has a non empty value. The options that are on the dynamicOptions must be valid for the input type.
After struggling for ages I finally came up with a way to make it work and it's quite simple quick indeed.
This is how I can create an selectbox with values which change dynamically according to the content of array ruleInspectorArray(which is filled in a different part of my code):
When a new link is created and its inspector is created as well I set inside function createInspector the options of selectbox to be the content of ruleInspectorArray:
cell.set('myArrayOfOptions', ruleInspectorArray);
In order to make it work we also have to set the path of ouf selectbox options being this ruleInspectorArray by doing so:
'tr_rules': { type: 'select', options: 'myArrayOfOptions', group: 'attributes', label: 'Rule', index: 3 },
Yes, Yes, Yes.... :)

Using Cytoscape.js in REPL environment

I'm trying to explore the cytoscape graph core object and I want to access its properties in runtime. Can I use Node.js interpreter to instantiate the cy object and run methods on the elements ? If this is an option, I also don't understand where 're real graphics going to be displayed. Is Node.js will open a browser window ?
Node.js REPL represents JavaScript interpreter, but it has no relation to DOM. From the examples on how to use cytoscape, the DOM is required:
var cy = cytoscape({
container: document.getElementById('cy') // container to render in
});
So it seems you can't use cytoscape's visual features with REPL. However, the docs says that:
container : A HTML DOM element in which the graph should be rendered.
This is unspecified if Cytoscape.js is run headlessly.
But I think you can use REPL to run Cytoscape headlessly.
Actually i just find how to run Cytoscape in a REPL environment. still didnt find a way to display it graphically, but i can interact with the object to explore its properties :
$ node
>var cytoscape = require('cytoscape');
>var cy = cytoscape({
container: document.getElementById('cy'), // container to render in
elements: [ // list of graph elements to start with
{ // node a
data: { id: 'a' }
},
{ // node b
data: { id: 'b' }
},
{ // edge ab
data: { id: 'ab', source: 'a', target: 'b' }
}
],
style: [ // the stylesheet for the graph
{
selector: 'node',
style: {
'background-color': '#666',
'label': 'data(id)'
}
},
{
selector: 'edge',
style: {
'width': 3,
'line-color': '#ccc',
'target-arrow-color': '#ccc',
'target-arrow-shape': 'triangle'
}
}
],
layout: {
name: 'grid',
rows: 1
}
});
After i instantiate the cy object, i can interact with it by typing :
> cy.
cy.__defineGetter__ cy.__defineSetter__
cy.__lookupGetter__ cy.__lookupSetter__
cy.__proto__ cy.constructor
cy.hasOwnProperty cy.isPrototypeOf
cy.propertyIsEnumerable cy.toLocaleString
cy.toString cy.valueOf
> cy.elements().forEach(function(e){ console.log(e.data())});
{ id: 'a' }
{ id: 'b' }
{ id: 'ab', source: 'a', target: 'b' }

Categories