I have the following situation:
There are css rules inside of my JS var which looks like this:
"floating_icons": {
"main_color": "",
"phone_color": "",
"mail_color": "",
"whatsapp_color": ""
}
},
"style_css": ".pad-t { padding: 0 20px 0 20px;} .grey-t { color: rgba(127.765849375934, 127.765849375934, 127.765849375934, 0.217430264}"
}
},
"entity": {
"data": {
"data": {
And I need to apply 'style_css' it in my VueJS application. Unfortunatelly I didn't find any propriate solution for it.
Could you please help me out with it?
Binding Inline Styles guide for the Vuejs v2
The object syntax for v-bind:style is pretty straightforward - it looks almost like CSS, except it’s a JavaScript object. You can use either camelCase or kebab-case (use quotes with kebab-case) for the CSS property names:
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data: {
activeColor: 'red',
fontSize: 30
}
It is often a good idea to bind to a style object directly so that the template is cleaner:
<div v-bind:style="styleObject"></div>
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
Again, the object syntax is often used in conjunction with computed properties that return objects.
Array Syntax
The array syntax for v-bind:style allows you to apply multiple style objects to the same element:
<div v-bind:style="[baseStyles, overridingStyles]"></div>
You should read the full guide at https://v2.vuejs.org/v2/guide/class-and-style.html
Related
Our team is facing a problem with too much logics in template file which causes colleagues hard to debug.
I am thinking a proper way to increase the readability of the template file without losing performance.
Our team often include inline bitwise logic for dynamic class, style, etc. to fulfill the business logic under component template.
[Inline bitwise example]
<template> <!--Inline bitwise way-->
<div class="listContainer">
<div :class="`listItem ${_item.type == '1' ? 'itemTypeOne' : ''} ${_item.type == '2' ? 'itemTypeTwo' : ''}`" v-for="_item in list" :key="_item.key">
<div class="itemBg" :style="{top: _item.type == '1' ? '10px' : '20px'}"></div>
</div>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
list: [{key: "1", type: "1", value: "Value 1"}, { key: "2", type: "2", value: "Value 2"}],
};
},
methods: {},
computed: {},
}
</script>
To reduce these kind of logic code, I thought of using computed approach but I think it would cause computation overhead (Just in my opinion, feel free to correct me if I was wrong:)). It is because we cannot avoid using parameters with computed which lose the advantage of cache handled by vue itself. By using computed property with parameter approach, the parametrize anonymous function inside computed is keep being called which would potentially cause lower performance.
[Parametrized computed example]
<template>
<div class="listContainer">
<div :class="`listItem ${getItemClass(_item.type)}`" v-for="_item in list" :key="_item.key">
<div class="itemBg" :style="getItemBgStyle(_item.type)"></div>
</div>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
list: [{key: "1", type: "1", value: "Value 1"}, { key: "2", type: "2", value: "Value 2"}],
};
},
methods: {},
computed: {
getItemClass: function(){
return function($itemType){
console.log("getItemClass called"); /* Keep being called even _item.key didnt changed */
if($itemType == '1'){
return 'itemTypeOne'
}
if($itemType == '2'){
return 'itemTypeTwo'
}
}
},
getItemBgStyle: function(){
return function($itemType){
console.log("getItemClass called"); /* Same as getItemClass */
return {
top: $itemType == '1' ? '10px' : '20px'
}
}
}
},
}
</script>
Same with parametrized computed approach, parametrized method approach also cause this drawback. To keep this question in short, I'm not showing method approach here since it basically same with the computed approach. Here is the reference post that I studied: Can I pass parameters in computed properties in Vue.Js
My question is, is there a proper way to meet my aim (to keep template shorts without losing performance)?
Additionally, could anyone share with us the performance comparison between [Inline bitwise approach] vs [Parametrized computed approach] vs [Parametrized method approach].
I'm using Go.js to create a canvas a user can draw straight lines on. From the documentation, I've been able to create nodes. Node creation code looks like:
const node = this.goMake(go.Node, 'Horizontal',
{ position: new go.Point(point[0], point[1]) }, // set the Node.position
this.goMake(go.Shape, 'Circle', { width: 10, height: 10, fill: 'lightblue' })
);
As I understand the documentation, in order to create a line (non-directional link) between the two nodes, I need to use their key values like so:
this.myDiagram.model.addLinkData({ from: node1.key, to: node2.key });
When logging out my nodes, I see that key value is an empty string.
Question: When creating my nodes using the first snippet above, how do I inject the key value so the second code snippet properly links the two? Creating unique values for all points is not an issue, I just can't figure out how to attach the unique value to the node's key property.
keys are a property of Model data, where the model has an array of node data and link data. Keys are not properties of the Nodes themselves exactly. node.key is just a convenience for node.data.key.
So when you write:
myDiagram.model.addNodeData( { key: 'a' });
It is making a copy of the myDiagram.nodeTemplate, and assigning that Node the node.data of { key: 'a' }, so that node's key is 'a'
In other words, you can only relate these things by the model, not by the Node that you are creating.
If you are using models, you should be creating node templates on the Diagram, not stand-alone nodes, as it appears you are doing. So something like:
myDiagram.nodeTemplate = this.goMake(go.Node, 'Horizontal',
{ position: new go.Point(point[0], point[1]) }, // set the Node.position
this.goMake(go.Shape, 'Circle', { width: 10, height: 10, fill: 'lightblue' })
);
or if you have multiple templates:
myDiagram.nodeTemplateMap.add('newTemplate', this.goMake(go.Node, 'Horizontal',
{ position: new go.Point(point[0], point[1]) }, // set the Node.position
this.goMake(go.Shape, 'Circle', { width: 10, height: 10, fill: 'lightblue' })
));
First of all let me introduce you to my project. I am desining a web application that will show some data about devices scattered around a country. To create this I used Vue.js and HighCharts (HighMaps for the map part). This is the result I have achieved now.
What I want to add now is the possibility for the end-user to click on a marked region and show all of the devices in that region. To do that I need the region's "ID", called code in HighMaps, to send a ajax request to my db and I would also like to make this new "div" a component so that I can use it freely in my application. I'll put a sketch image of what I mean (excuse me for my really bad paint skills :D):
The black lines are not important, what I would like to achieve is to show a new component besides the map (or wherever really). Next is my current code, I am using the one page, one component style so both template and script tags are in the same file and I omitted in the script tag all the unecessary things. Right now I just set up a div with curly brackets to update a variable on change, just to debug more easily. My main problem is that, in the plotOptions.series.point.events.click when I try to reference the this.foo variable it doesn't set it since the div doesn't update. I think that might be a scope issue but I wouldn't know where to start looking.
<template>
<div id="canvasContainer">
<highmaps :options="chartOptions"></highmaps>
<app-componentForDevices><app-componentForDevices>
<div>{{foo}}</div>
</div>
</template>
<script>
import HighCharts from 'vue-highcharts';
import json from '../map.json'
export default {
data: function () {
return {
foo: 'NO',
/* Map */
chartOptions: {
chart: {
map: json, // The map data is taken from the .json file imported above
},
plotOptions: {
series: {
point: {
events: {
click: function () {
this.foo='OK'
}
}
}
},
map: {
joinBy: ['hc-key', 'code'],
allAreas: false,
tooltip: {
headerFormat: '',
pointFormat: '{point.name}: <b>{series.name}</b>'
},
}
},
/* Zoom and move */
mapNavigation: {
enabled: true,
buttonOptions: {
verticalAlign: 'bottom'
}
},
series: [
{
allAreas: true,
showInLegend: false,
},
{
borderColor: '#a0451c',
cursor: 'pointer',
name: 'ERROR',
color: "red",
data: ['it-na', 'it-mi', 'it-mo', 'it-ud'].map(function (code) {
return {code: code};
}),
},
{
borderColor: '#a09e21',
cursor: 'pointer',
name: 'WARNING',
color: "yellow",
data: ['it-ts', 'it-av', 'it-ri'].map(function (code) {
return {code: code};
}),
},
{
borderColor: '#4ea02a',
cursor: 'pointer',
name: "OK",
color: "lightgreen",
data: ['it-pa', 'it-ve', 'it-bo', 'it-ta', 'it-pn'].map(function (code) {
return {code: code};
}),
},
],
}
}
}
}
</script>
<style scoped>
svg{
align-items: center;
}
Thanks in advance for the help. Cheers!
EDIT
I have just tried #icecream_hobbit 's suggestion and using a ECMA6 arrow function helped since now I can access the variable store in Vue but now I lost the access to the local arguments like this.name which made possibile for me to print the selected region. Any ideas? Am I missing something?
EDITv2
Thanks to #icecream_hobbit I have found a way to do what I wanted. You just need to add an object inside the parenthesis so that you can use this for the global variable and e for your mouse click event.
events: {
click: (e) => {
this.foo = 'OK'
this.foo = e.point.name
}
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Until arrow functions, every new function defined its own this value
(a new object in the case of a constructor, undefined in strict mode
function calls, the base object if the function is called as an
"object method", etc.)
The this you were accessing did not belong to the Vue instance. You can use an arrow function () => {/*function body*/} to inherit the this of the Vue instance.
An arrow function expression has a shorter syntax than a function
expression and does not have its own this, arguments, super, or
new.target.
EDIT: For the added question of how do I do I get the Vue instance, and the object instance at the same time you can use a closure.
click: function(VueInstance){
return function() {
VueInstance.Foo = 'OK';
}(this)
}
In the view I need to generate the following classes:
<div class="comp comp--lock comp--red">Foo</div>
The lock and red are based on state, where the following values for color are possible:
comp--red, comp--yellow, comp--blue, and many other possible colors
Until now I was using a computed method to concatenate the class name based on data:
getCompClassName(){
return `comp ${this.isLock ? 'comp--lock' : ''} comp--${this.color}`
}
Looking at Vuejs documentation I see there is v-bind:class that should resolve this in a better way, the problem I have is how to solve the color interpolation, since I would need to declare all possible colors.
data: {
classObject: {
'comp--lock': this.isLock,
'comp--red': this.color === 'red',
'comp--blue': this.color === 'blue',
'comp--yellow': this.color === 'yellow'
}
}
Is there any way to solve this using v-bind:class that scales better without having to list all possibilities or should I use the computed method to interpolate the class name?
Could you not just use a computed?
computed: {
classObject() {
return {
'comp--lock': this.isLock,
[`comp--${this.color}`]: true
}
}
}
JSfiddle: https://jsfiddle.net/5sknyauz/5/
EDIT: you could actually do the same thing in data:
data() {
return {
classObject: {
'comp--lock': this.isLock,
[`comp--${this.color}`]: true
}
}
}
I have a somewhat complex case where I need to apply custom formatting to a JavaScript expression that calculates the value of a field inside a Grid.
<Grid records:bind="$page.data"
columns={[
{
field: 'seatbeltViolations',
header: 'Seatbelt Violations',
format:'n;0',
aggregate: 'sum',
aggregateField: 'seatbelts',
align: 'right'
},{
field: "distance",
header: "Distance",
format: "n;0",
aggregate: "sum",
aggregateField: "distance",
align: "right"
},{
field: 'seatbeltViolationsPer100Km',
header: 'Seatbelts per 100km',
format: 'n;1',
footer: {
expr: '0.1 * Math.round(10.0 * {$group.seatbelts}/{$group.distance})'
},
align: 'right'
}]} />
Is there a way to use custom global functions, that perform the given operation, within the expression? Something like this:
// this does not work
expr: 'Format.value({$group.seatbelts}/{$group.distance}, "n;1")'
I hope my question was clear enough :)
I think the easiest way would be to use computable here instead of an expression. Something along the lines of:
...
footer: computable("$group.seatbelts", "$group.distance", (p, q) =>
{
return q != 0 ? Format.value(100.0 * p / q, "n;1") : '--';
}),
...
This way you can have footers as complex as you like, and you can easily abstract the logic away into a generic factory function returning anything you want. For an example of this, take a look at this fiddle:
https://cxjs.io/fiddle/?f=xWw8ob40
There's also an undocumented feature of using expressions within string templates:
footer: {
tpl: '{[{$group.seatbelts} != 0 ? {$group.distance}/{$group.seatbelts} : null]:n;1}'
}