How to v-bind background? - vue.js

Im trying to do something like this:
<div class="seller_image" :style="{background: url(' + user_credentials.avatar +'); background-size: cover !important; display:block;}">
but i get this error:
Invalid expression. Generated function body: {background:scope.url('
+ user_credentials.avatar +');scope.background-scope.size:scope.cover!scope.important;scope.display:scope.block;}
Any suggestion?
Like this it working but i want to use it like background image:
<img v-bind:src="user_credentials.avatar" alt="Avatar" />

It's easier to put this together inside a computed and use that instead:
new Vue({
el: '#app',
computed: {
getBackground() {
return 'background: url(' + this.user_credentials.avatar + '); background-size: cover display:block;';
}
},
data: {
user_credentials: {
avatar: 'avatar.png'
}
}
})
Then you can use it like so:
<div :style="getBackground"></div>
Here's the JSFiddle:
https://jsfiddle.net/w6agzuen/

The error you are getting is because you need the background value to be a string. Any additional inline styles need to be comma delimited then as well because you are passing an object. Lastly I believe styles like background-size that contain a hyphen need to be camel-cased when binding them so then the final changes to your inline styles should look like this:
<div class="seller_image" :style="{background: 'url(' + user_credentials.avatar +')', backgroundSize: 'cover !important', display: 'block'}">

Related

Define a variable used in js and css

For example, I want to define a global color a = '#FFF', and reference it in js and css to make sure that there is only one color named a in the project. then when the value of a changed, a in js and css also changed. is that possible in vue?
Hmm... I was thinking about watchers watch in combination with CSS variables.
Maybe something like this?
Whenever a changes, the CSS variable --a changes aswell.
You can actually type in any color format you want. Hex, rgb, rgba...
let v = new Vue({
el: "#app",
data: {
a: "red"
},
watch: {
a(val){
document.documentElement.style.setProperty("--a", val);
}
}
})
:root {
--a: red;
}
#app {
height: 100px;
width:100%;
background: var(--a);
transition: background 500ms;
}
p {
background: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<p>Color: {{a}}</p>
<input v-model="a">
</div>

Button with v-on:click that switches between the classes btn-primary and btn-primary-outline not working

Im working on a button that opens a modal. By default it should have the btn-primary-outline class (Blue text, transparent background, blue border), when clicked it should have the btn-primary class (White text, blue background, blue border). But its not working, the button stays trasparent, the text blue, and all its doing is toggling the blue button border on and off.
HTML:
<button v-on:click="settingsButtonIsActive = !settingsButtonIsActive"
class="btn margin-top-half center-block col-xs-12"
:class="[settingsButtonIsActive ? 'btn-primary' : '', 'btn-primary-outline']">
<strong>{{labels.lblButtonConfiguration}}</strong>
</button>
Controller:
data = {
settingsButtonIsActive: false
}
I feel like the button doesnt like not having any of those 2 clases defined, but i cant think of any other way to do it.
Your "mistake" you use an array syntax but the logic of "else" is empty '' (If settingsButtonIsActive is false render => '') + always render btn-primary-outline (The (ternary) operator inside 0 index - btn-primary-outline on 1 index).
For example this:
:class="[settingsButtonIsActive ? 'btn-primary' : '', 'btn-primary-outline', 'hello', 'world']">
render:
<button class="btn-primary btn-primary-outline hello world">
Not in "vue" this is your logic:
var element = document.getElementById("myDIV");
if(settingsButtonIsActive){
element.classList.add("btn-primary");
}
else{
element.classList.add("");
}
element.classList.add("btn-primary-outline");
This is the correct markup (For -or- a -or- b) - shortcut for "if else":
class="settingsButtonIsActive ? 'btn-primary' : 'btn-primary-outline'">
No need her for array syntax: https://v2.vuejs.org/v2/guide/class-and-style.html#Array-Syntax
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator
var app = new Vue({
el: '#app',
data: {
msg: "settingsButtonIsActive",
settingsButtonIsActive: true,
isActive: "btn-primary",
hasError: "btn-primary-outline"
}
})
button{
padding: 5px;
cursor: pointer;
}
.btn-primary{
background: red;
border: 1px solid red;
}
.btn-primary-outline{
background: transparent;
border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>
<div id="app">
<button v-on:click="settingsButtonIsActive = !settingsButtonIsActive"
:class="settingsButtonIsActive ? 'btn-primary' : 'btn-primary-outline'">
<strong>{{msg}}</strong>: {{settingsButtonIsActive}}
</button>
</div>
I would recommend rewriting the code a bit.
First of all, you can write the class name switch as a computed property:
// ... beginning of your .js code
computed: {
isButtonActive () {
return this.settingsButtonIsActive ? 'btn-primary' : 'btn-outline-primary'
}
}
// ... rest of your .js code
then you can merge both class attributes into one and bind it like this:
<button v-on:click="settingsButtonIsActive = !settingsButtonIsActive"
:class="['btn', 'margin-top-half', 'center-block', 'col-xs-12', isButtonActiveClass">
<strong>{{labels.lblButtonConfiguration}}</strong>
</button>
There is also another option, but because you change between two classes, I think a computed property is a much cleaner solution. However, you can achieve same result also with this code:
<button v-on:click="settingsButtonIsActive = !settingsButtonIsActive"
:class="['btn', 'margin-top-half', 'center-block', 'col-xs-12', {'btn-primary': isButtonActiveClass}, {'btn-outline-primary': !isButtonActiveClass}">
<strong>{{labels.lblButtonConfiguration}}</strong>
</button>
Note that when I want to change classes dynamically I'm passing an object into the array.
More can be found on https://v2.vuejs.org/v2/guide/class-and-style.html.
I fixed it by using the object syntax instead of the array syntax.
<button v-on:click="settingsButtonIsActive = !settingsButtonIsActive"
class="btn margin-top-half center-block col-xs-12"
:class="{'btn-primary' : settingsButtonIsActive === true, 'btn-primary-outline' : settingsButtonIsActive === false}">
<strong>{{labels.lblButtonConfiguration}}</strong>
</button>

Vue.js How to define (override) css style in a Component?

The default style for the p tag on my page has some bottom margin. My component uses p tags, and accordingly, the p tags in my component text show the corresponding bottom margin. How can I override/define new css style for the p tags in my component. I define my component like this:
Vue.component ('activity-component', {
props: {
customer_id:{},
is_admin:{},
isAdmin:{},
isKitsActionplan:{},
....
template:
`<div
class="row msDashboard-box"
style="cursor:default;padding-top:12px;
padding-bottom:12px;"
>
...
<p> ... </p>
});
Maybe u can try this approach,
Pass a variable with the class name to the component
<my-component v-bind:class="variable with class name"></my-component>
Then apply a rule to all p elements inside it, something like this i guess:
.test p{
your styles
}
U can see more here: vue api class and style bindings
I dont know for sure if this was what you wanted, but i gave it a shot :)
You have several options - choose your own adventure:
Use a global utility style
Somewhere globally, define a utility class like:
.u-margin-reset {
margin: 0;
}
Then in your template:
<p class="u-margin-reset">hello</p>
Use scoped CSS
If you are using single file components, you can use scoped css:
<template>
<p class="special-p">hello</p>
</template>
<style scoped>
.special-p {
margin: 0;
}
</style>
Use inline styles
Vue.component('activity-component', {
template: `<p style="margin:0;"></p>`,
});
or
Vue.component('activity-component', {
computed: {
myStyle() {
return {
margin: 0,
};
},
},
template: `<p :style="myStyle"></p>`,
});
As an aside, I'd recommend using a CSS reset that globally resets the margins of all elements to 0. Then each component should set the margins as needed for its child elements/components. This may not be reasonable if you already have a large codebase, however.

Referring to properties passes as props in Vue.js components

I've started working on a board game prototype and decided to go with Vue.js. I have some experience with JavaScript and everything was going fine ... until I tried to access a property passed with 'props' in a component.
Here's the whole code:
<!DOCTYPE HTML>
<html>
<head>
<title>Board</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style type="text/css">
#board {
width: 600px;
}
.square { width: 100px; height: 100px; margin: 1px; border: 1px solid grey; display: inline-block; float: left; }
</style>
</head>
<body>
<div id="board">
<square v-for="square in squares"></square>
</div>
<script>
var app = new Vue({
el: '#board',
data: {
squares: []
}
})
const rows = 5
const cols = 5
const reservedLocation = { row: 2, col: 2 }
Vue.component('square', {
props: [
'row',
'col',
'type',
],
template: '<div class="square" v-on:click="logLocation"></div>',
methods: {
logLocation: function() {
console.log(this)
console.log("Location: " + this.col + "x" + this.row )
},
},
})
for (var row=0; row<rows; row++) {
for (var col=0; col<cols; col++) {
const type = (row == reservedLocation.row && col == reservedLocation.col) ? 'reserved' : 'empty'
app.squares.push({ row: row, col: col, type: type })
}
}
</script>
</body>
</html>
What's happening there is the "board" div is filled with the "square" components. Each square component has the 'row', 'col' and 'type' properties, passed to it as 'props'. When the user click on a square, the 'logLocation' function of the corresponding component is called and all that function does is, it logs the 'row' and 'col' properties.
Everything works fine except the message logged is: "Location: undefinedxundefined", in other words, both this.col and this.row seems to be undefined. I've checked 'this', and it seems to be the correct component.
I'm sure it's something obvious but I couldn't find an answer in either the official documentation, in tutorials or even here, on Stack Overflow itself – perhaps I'm not using the correct terms.
A bit of new info: the 'row' and 'col' properties are set on the component object and in the '$props' property but the value they return in 'undefined'. Am I, somehow, passing the parameters incorrectly?
Solution
Turns out, there is a section in the Vue.js documentation dedicated specifically to using 'v-for' with components: "v-for with a Component" and here's the relevant portion of the code:
<div id="board">
<square
v-for="square in squares"
:key="square.id"
:row="square.row"
:col="square.col"
:type="square.type"
></square>
</div>
Huge thanks to Stephen Thomas for pointing me in the right direction!
You've defined the props correctly, and you're accessing the props correctly, but you haven't actually set them to any value. The markup:
<square v-for="square in squares"></square>
doesn't pass the props to the component. Perhaps you want something like
<div v-for="row in rows" :key="row">
<div v-for="col in cols" :key="col">
<square :row="row" :col="col"></square>
</div>
</div>
Try to use
console.log("Location: " + this.$props.col + " x " + this.$props.row )

Vue inline conditional if?

I have the following piece of code:
<div
:id="'object' + object.id""
:style="'position:absolute !important; width:' + object.width + '% !important; height:' + object.height + '% !important;'">
<div
This works fine and renders nicely as it should.
I now want to add conditional stuff in there. Something like
if object.background == 'solid'
background-color: #ffffff;
endif
I tried achieving this via the Vue inline if, which gave me this:
[object.background == 'solid' ? background-color: #ffffff important; :
'']
But that just gave a lot of errors, which lead me to think I'm tackling this all wrong.
What would the correct approach be for me to achieve having short conditional statements in my style?
I would use a computed property that returns a style object.
new Vue({
el: "#app",
data: {
width: '200px',
height: '200px',
background: 'solid',
},
computed: {
styleObj() {
return {
position: 'absolute !important',
width: `${this.width} !important`,
height: `${this.height} !important`,
background: this.background === 'solid' ? 'green' : 'yellow',
};
},
},
})
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.min.js"></script>
<div id="app">
<div :style="styleObj">
</div>
</div>
I don't know if this should be marked as a duplicate of this question: Condition in v-bind:Style
However, this method is documented only for classes binding, on https://v2.vuejs.org/v2/guide/class-and-style.html
That said, you ask:
What would the correct approach be for me to achieve having short conditional statements in my style?
I don't think this is a correct approach. I mean, the correct approach would be to write css classes and apply them conditionally, since those are the documented methods, leave this for cases when you have to apply direct styling to override all other styles that apply to the element in question.
Other correct approach would be to use data, props, or even a computed property or method.
Also, you can have both style and :style attributes and vue will mix them for you, so you can define base style on the normal attribute and "other stuff" on the style binding.
But as i say, leave this for extreme cases where you really need this on the style attribute.