Vue adding dynamic class doesn't change current class - css

I have wrapper div with padding and I am dynamically adding items inside of it.
I don't want any padding on wrapper div when there is no item in it.
I have created computed method isEmpty to check if there are items or not and used it to add optional class :class={ className: isEmpty } but it doesn't work.
Here is the fiddle link: https://jsfiddle.net/2u9rtdmh/3/

You should wrap an expression for :class into ":
:class="{ className: isEmpty }"

You should read the console errors when trying to diagnose problems, i.e. your jsfiddle doesn't even have an #app element.
The correct syntax for your scenario would be :class="{ 'padding0' : isEmpty }"
Binding HTML Classes
Vue.config.productionTip = false;
Vue.config.devtools = false;
new Vue({
el: "#app",
data: {
},
computed: {
isEmpty() {
return true;
}
}
})
body {
background-color: black;
}
.my-wrapper {
padding: 32px;
background-color: white;
}
.padding0 {
padding: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div :class="{ 'padding0' : isEmpty }" class="my-wrapper">
<div>
<div>
</div>
</div>
</div>
</div>

Related

css3 transtion not working with v-for in vue2

I use transtion in vue2. I added transition in css. Vue template show two box. One way use v-for and array, another way is use variable. btn2 is effective but btn1 not.
<style lang="sass">
.item
width: 120px
height: 120px
background-color: bisque
transition: margin-left 500ms
</style>
<template>
<div>
<div class="item" v-for="item in list" :key="item.index" :style="{marginLeft: item.index + 'px'}">{{ item.value }}</div>
<div class="item" :style="{marginLeft: left + 'px'}">123</div>
<button #click="addone">btn1</button>
<button #click="addtwo">btn2</button>
</div>
</template>
<script>
export default {
name: 'Heap',
data() {
return {
left: 100,
list: [
{
value: 12,
index: 10
}
]
}
},
methods: {
addone() {
this.list[0]['index']+=10
},
addtwo() {
this.left+=10
}
}
}
</script>
You are using the code :key="item.index" on your first div. Your code then updates that same index.
When a key's value changes, the component it is attached to re-renders. You are not seeing the animation occur because instead of dynamically incrementing the CSS, you are effectively just re-rendering the element with the new CSS.
The purpose of a key is to help Vue keep track of the identity of a given node in a list. It lets Vue know which nodes it can keep and patch up and which ones need to be rendered again.
You should use a static, non-changing value as a key where possible. In the following example I have added an id property to your object and used that as the key.
<style lang="sass">
.item
width: 120px
height: 120px
background-color: bisque
transition: margin-left 500ms
</style>
<template>
<div>
<div
v-for="item in list"
:key="item.id"
class="item"
:style="{marginLeft: item.index.toString() + 'px'}"
>
{{ item.value }}
</div>
<div class="item" :style="{marginLeft: left.toString() + 'px'}">123</div>
<button #click="addone">btn1</button>
<button #click="addtwo">btn2</button>
</div>
</template>
<script>
export default {
name: 'Example',
data() {
return {
left: 100,
list: [
{
id: '1',
value: 12,
index: 10,
},
],
};
},
methods: {
addone() {
this.list[0].index += 10;
},
addtwo() {
this.left += 10;
},
},
};
</script>

Assign a dynamic Vuejs value to css

I have the following jsfiddle:
https://jsfiddle.net/6cu295sn/1/
new Vue({
el: '#cct',
lang: {
myText: "my text is",
}
});
.myCSS::after{
content: {{lang.myText}}; //this does not output anything
}
I am trying to assign the Vuejs dynamic value to the CSS (content), please can anyone advise how I can achieve this?
You can bind a css variable, to apply it as content of your pseudo class, as below:
new Vue({
el: '#cct',
data () {
return {
lang: "my text is"
}
}
})
.myCSS {
margin: 1rem 0;
border: 1px solid black;
}
.myCSS::after {
content: var(--myText);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>
<div id="cct">
<input v-model="lang">
<div class="myCSS" :style="`--myText: '${lang}'`"></div>
</div>

CSS Help - Remove blank space between Images (<img>)

Right now I am trying to make images stack side by side, vertically and horizontally, so that there is no white spaces between them. This is what my view currently looks like.
Ideally, there would be none of that blank, white space. I have inserted the ReactJS code below with my GifViewer component that holds the . Any ideas on how I can get this to work? And the code will not run due to the axios request, so it's just for visual effect right now.
img {
display: inline !important;
width: 20%;
vertical-align: top;
height: auto;
top: 0;
left: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
class GifViewer extends Component {
render() {
return (
<img
key={this.props.keyyer}
src={`https://i.giphy.com/${this.props.id}.gif`}
/>
);
}
}
class App extends Component {
constructor(props) {
super(props);
this.state = {
searchTerm: "",
counter: 0,
pastSearches: [],
data: null
};
this.handleChange = this.handleChange.bind(this);
}
componentDidUpdate() {
console.log("this.state.data", this.state.data);
}
componentDidMount() {
console.log("Mounted");
}
handleChange(event) {
this.setState({ searchTerm: event.target.value });
axios
.get(
`${BASE_URL}${config.apiKey}${QUERY}${this.state.searchTerm}${LIMITS}`
)
.then(result => {
this.setState({ data: result.data.data });
});
}
render() {
if (this.state.data) {
var GIFS = this.state.data.map(d => (
<GifViewer keyyer={d.embed_url} id={d.id} />
));
}
return (
<div className="container-fluid">
<div className="row py-5 bg-success">
<div className="col-8 offset-2">
<h3 className="text-center">LET'S BREAK THE INTER-WEBZ</h3>
<input
type="text"
className="form-control"
value={this.state.searchTerm}
onChange={this.handleChange}
placeholder="Search"
/>
</div>
</div>
{this.state.data ? GIFS : "Nothing yet"}
</div>
);
}
}
export default App;
My personal favorite way to resolve this is the css property object-fit: cover; (applied to your img rule).
There's a great article on the property here, but the gist (for your purpose) is that you can zoom the image to cover the whole space without stretching or distorting the image.

VueJS change border color of the input if input is already filled in

I need to change the border color of the input if the customer already filled in the field.
How can I do this using VueJS ?
<div class="some-basic-div", '#change' => 'checkForInput'>
<div class="dc-form-group ">
<input type='text' id='first_name' >
</div>
<div class="dc-form-group ">
<input type='text' id='last_name' >
</div>
<div class="dc-form-group ">
<input type='text' id='some_text' >
</div>
</end>
I have tried to use pure JavaScript.
checkForInput: function(e) {
let targetDiv = event.target;
if (targetDiv.value == "") {
targetDiv.classList.remove("mod-group-success");
} else {
targetDiv.classList.add("mod-group-success") ;
}
}
So when I am changing the input I need to change the style of the input which I filled in.
I've wrote this code for handling the issue:
Vue.config.productionTip = false
app = new Vue({
el: "#app",
data: {
testValue: ''
}
},
methods: {
checkForInput: function(e){
let input = event.target
if (input.value != "") {
input.classList.add("mod-group-success") ;
} else {
input.classList.remove("mod-group-success");
}
}
}
})
And putted on front end:
'#change' => 'checkForInput'
Uses Class & Styles binding,
below is one simple demo for class binding.
Vue.config.productionTip = false
app = new Vue({
el: "#app",
data: {
testValue: ''
},
computed: {
computedInputStyleEnable: function () { // or use one method instead of computed property
//apply your own logic at here to determinate if enable input-has-value-style
return this.testValue && this.testValue.length > 0
}
},
methods: {
applyInputStyle: function (targetInput) { // bind with one method and return Array
return [targetInput && targetInput.length > 0 ? 'input-has-value-style' : 'input-no-value-style']
}
}
})
.input-has-value-style {
border: 2px solid green;
background-color:lightgreen;
}
.input-no-value-style {
border: 2px solid red;
background-color:pink;
}
<script src="https://unpkg.com/vue#2.5.16/dist/vue.js"></script>
<div id="app">
<div>
<p>Already filled in {{testValue.length}} characters.</p>
<input type='text' v-model="testValue"
:class="{'input-has-value-style': computedInputStyleEnable}"
/>
</div>
<div>
<p>Already filled in {{testValue.length}} characters.</p>
<input type='text' v-model="testValue"
:class="applyInputStyle(testValue)"
/>
</div>
</div>

In vue.js component, how to use props in css?

I'm new to vue.js. Here is my problem:
In a *.vue file like this:
<template>
<div id="a">
</div>
</template>
<script>
export default {
name: 'SquareButton',
props: ['color']
}
</script>
<style scoped>
#a {
background-color: ?
}
<style>
How can I use the props color in background-color: (where is a ? now).
Thanks.
You actually can!
You should define the CSS variables in a Computed Property, then call the computed property as a style attribute to the element that will require the CSS variable, and finally you may use the variable within the tags at the bottom of your document.
new Vue({
el: '#app',
data: function() {
return {
baseFontSize: 1,
bgHoverColor: "#00cc00",
hoverContent: "Hovering!"
}
},
computed: {
cssProps() {
return {
'--hover-font-size': (this.baseFontSize * 2) + "em",
'--bg-hover-color': this.bgHoverColor,
'--hover-content': JSON.stringify(this.hoverContent)
}
}
}
})
div {
margin: 1em;
}
div.test:hover {
background-color: var(--bg-hover-color);
font-size: var(--hover-font-size);
}
div.test:hover::after {
margin-left: 1em;
content: var(--hover-content);
}
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app" :style="cssProps">
<div>Hover text: <input type="text" v-model="hoverContent"></div>
<div>Hover color: <input type="color" v-model="bgHoverColor"></div>
<div class="test">Hover over me</div>
</div>
Or have a look here: https://codepen.io/richardtallent/pen/yvpERW/
And here: https://github.com/vuejs/vue/issues/7346
You don't. You use a computed property and there you use the prop to return the style of the div, like this:
<template>
<div id="a" :style="style" #mouseover="mouseOver()">
</div>
</template>
<script>
export default {
name: 'SquareButton',
props: ['color'],
computed: {
style () {
return 'background-color: ' + this.hovering ? this.color: 'red';
}
},
data () {
return {
hovering: false
}
},
methods: {
mouseOver () {
this.hovering = !this.hovering
}
}
}
</script>
<style scoped>
<style>
As we are in 2020 now, I suggest using this trick with a css function called var
<template>
<div id="a" :style="cssVars"></div>
</template>
<script>
export default {
props: ['color'],
computed: {
cssVars () {
return{
/* variables you want to pass to css */
'--color': this.color,
}
}
}
<script>
<style scoped>
#a{
background-color: var(--color);
}
</style>
This method is very useful because it allows you to update the passed values through css later on (for example when you apply hover event).
credit
I know we're talking vue 2 here, but in case anyone from vue 3 lands in this question (like I did), vue 3 introduced a much cleaner way to do this:
<template>
<div id="a">
</div>
</template>
<script>
export default {
name: 'SquareButton',
props: ['color']
}
</script>
<style scoped>
#a {
background-color: v-bind(color);
}
<style>
What Vue actually does behind the scenes is the same "introducing css variables through component's style process", but it sure looks much better on the eyes now.
Documentation source: https://v3.vuejs.org/api/sfc-style.html#state-driven-dynamic-css
Why not just use :style prop in this way:
<template>
<div :style="{ backgroundColor: color }">
</template>
<script>
export default {
props: {
color: {
type: String,
default: ''
}
}
}
</script>
Make sure you define css properties in camelCase style.
If you need css that can't be applied by a style attribute like pseudo classes or media queries, what I do is the following:
Create a globally available style component when initializing Vue (you need it as otherwise you run into linting issues). It creates a style tag that simply renders the content in the slot:
I would only use this if you really need both dynamic values in your css and css features that can't be applied to a style attribute.
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
Vue.component('v-style', {
render: function(createElement) {
return createElement('style', this.$slots.default)
}
})
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
Then use it at the top of your template like this and you get the full JavaScript scope of your component and the full css syntax combined:
<template>
<v-style>
#media screen and (max-width: 820px) {
.gwi-text-media-{{ this.id }} {
background-image: url({{ mobileThumb }});
}
}
</v-style>
</template>
It seems a bit hacky to me, but it does it's job and I would rather go like this in some cases than having to add additional JS for mouse-over or resize events that have a big potential to slow down your application performance.
Vue 3 added new way of binding styles, so now you can easily bind your props to css properties.
Read source:
https://learnvue.co/2021/05/how-to-use-vue-css-variables-reactive-styles-rfc/
<template>
<div>
<div class="text">hello</div>
</div>
</template>
<script>
export default {
data() {
return {
color: 'red',
}
}
}
</script>
<style>
.text {
color: v-bind(color);
}
</style>
You could utilise the CSS var(--foo-bar) function. It is also useful if you are trying to pass an asset that has its own dynamic path, like Shopify does.
This method also works for styling the :before and :after elements as they refer back to the style applied on the owner element.
Using the original post example for passing a colour:
<template>
<div
id="a"
:style="{ '--colour': color }">
</div>
</template>
<script>
export default {
name: 'SquareButton',
props: ['color']
}
</script>
<style scoped>
#a {
background-color: var(--colour);
}
</style>
Using the original post example for passing an URL:
<template>
<div
id="a"
:style="{ '--image-url': 'url(' + image + ')' }">
</div>
</template>
<script>
export default {
name: 'SquareButton',
props: ['image']
}
</script>
<style scoped>
#a {
background-url: var(--image-url);
}
</style>
Source

Resources