Why does binding class == "false" not working? - vuejs2

i wanted display the button. but if i did onMobileIcon true or false it given me the some resalte
<v-btn
:class="{compact:compact, onMobilIcon: false}"
>
#media(max-width: 800px){
.onMobilIcon{
display: none;
}
}

Related

Detect radio input getting unchecked (by clicking another radio input) in Vue

I want to give my label a border when the radio input is selected but I can only detect when the radio input is being activated. I know it's possible to do this in CSS with some tricks but I want to do it through Javascript.
<fieldset>
<label>
<input type="radio" name="test" #change="someMethod">
test
</label>
<label>
<input type="radio" name="test" #change="someMethod">
test
</label>
</fieldset>
methods: {
someMethod () {
console.log('something')
}
}
I was hoping to call the someMethod method when the input state would change between checked and unchcked, but this change is only called when the input is clicked (checked).
https://jsfiddle.net/alucardu/qhbpg2yj/1/
Use $refs to check all the radio inputs and use an array to store the previous state, then we can manage to do it:
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
previous_refs:[],
},
methods:{
someMethod(){
for(const key in this.$refs){
if(this.previous_refs[key]!==undefined &&
this.previous_refs[key].checked===true &&
this.$refs[key].checked===false){
console.log(this.$refs[key].id+' un-checked, do something');
}
if(this.$refs[key].checked===true){
console.log(this.$refs[key].id+' checked, do something');
}
if(this.previous_refs[key]===undefined){
this.previous_refs[key]={checked:this.$refs[key].checked};
}
else{
this.previous_refs[key].checked=this.$refs[key].checked;
}
}
},
}
})
Please check https://jsfiddle.net/sLw4e0p8/92/ to see details.
Managed to do it through CSS: https://jsfiddle.net/alucardu/qhbpg2yj/7/
Trick was adding a before to the checked input:
label {
display: flex;
position: relative;
input:checked {
&::before {
content: '';
position: absolute;
width: 100%;
height: 100%;
border: 1px solid blue;
}
}
}

How to pass function to html

I'm new to vue js, so I have simple function to hide the progress bar created in methods, but doesn't seem to work, I'm wondering if I need to add event or bind it, I think it's something simple, but I can't figure it out.
methods: {
hideProgressBar: function() {
const hideProgress = document.querySelector(".progress-bar");
if (hideProgress) {
hideProgress.classList.add(hide);
} else {
hideProgress.classList.remove(hide);
}
}
}
.progress-bar {
height: 1rem;
color: #fff;
background-color: #f5a623;
margin-top: 5px;
}
.hide.progress-bar {
display: none;
}
<div class="progress-bar" role="progressbar"></div>
If you want to invoke the method when the page is loaded, add the following created option after your methods option
created: function(){
this.hideProgressBar()
}
otherwise if you want to invoke the method based on an event then you would need to add your event.
If you're using vue.js you'd want to use the inbuilt directives as much as you can.
This means you can avoid the whole hideProgressBar method.
<button #click="hideProgressBar = !hideProgressBar">Try it</button>
<div class="progress-bar" v-if="!hideProgressBar">
Progress bar div
</div>
And you script would have a data prop that would help you toggle the hide/show of the progress bar
data () {
return {
hideProgressBar: false
}
}
just try like this:
methods: {
hideProgressBar: function() {
var element = document.getElementsByClassName("progress-bar")[0];
if (element.classList.contains('hide')) {
element.classList.remove('hide');
} else {
element.classList.add('hide');
}
}
}
<div class="progress-bar">
Progress bar 1 div
</div>
<div class="progress-bar hide">
Progress bar 2 div
</div>
I have used two progress bar for demonstration. Initially,
The first progress bar doesn't contain the hide class so hide class will be added.
Then the second progress already has hide class so it will be removed
DEMO:
//hides first progress bar by adding hide class.
var element = document.getElementsByClassName("progress-bar")[0];
if (element.classList.contains('hide')) {
element.classList.remove('hide');
} else {
element.classList.add('hide');
}
//display second progress bar by remove hide class
var element = document.getElementsByClassName("progress-bar")[1];
if (element.classList.contains('hide')) {
element.classList.remove('hide');
} else {
element.classList.add('hide');
}
.progress-bar {
height: 1rem;
color: #fff;
background-color: #f5a623;
margin-top: 5px;
}
.hide.progress-bar {
display: none;
}
<div class="progress-bar">
Progress bar 1 div
</div>
<div class="progress-bar hide">
Progress bar 2 div
</div>

#click on parent div not firing when pressing child button

I have made a custom number input box component and want it to activate on click. The component consists of 3 elements, two buttons (for decreasing and increasing the number value), and an input, where the number is displayed and can manually be changed. The problem is that the #click of the parent div (.numberField) only fires when clicking the input box, not when the buttons are clicked.
Because the input box seemed to be working I have tried changing the button elements to input[type=button] elements, but that failed.
I have checked when #click of the child elements (the two buttons and the input) fire, and confirmed that all of them behave in the same way (they don't fire on the initial click that sets :disabled="false" on each of them)
My Vue version is 3.7.0 if that matters
<template>
<div class="numberField" #click="fieldClicked">
<button #click="stepDown()" :disabled="disabled" class="left">
−
</button>
<input
v-model="value"
type="number"
:max="max"
:min="min"
:step="step"
:disabled="disabled">
<button #click="stepUp()" :disabled="disabled" class="right">
&plus;
</button>
</div>
</template>
<script>
export default {
name: 'NumberField',
props: {
defaultValue: Number,
max: Number,
min: Number,
step: Number,
disabled: Boolean,
},
data() {
return {
value: this.defaultValue,
};
},
watch: {
value() {
this.value = Math.min(this.max, Math.max(this.min, this.value));
},
},
methods: {
stepDown() {
this.value -= this.step;
},
stepUp() {
this.value += this.step;
},
fieldClicked(event) {
// #click.stop will stop all clicks from propagating; we will only stop clicks when the field is active
if (!this.disabled) event.stopPropagation()
},
},
};
</script>
<style scoped>
.numberField {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
height: 3em;
width: 8em;
}
.left {
border-top-left-radius: 0.2em;
border-bottom-left-radius: 0.2em;
}
.right {
border-top-right-radius: 0.2em;
border-bottom-right-radius: 0.2em;
}
input, button {
padding: 0;
border-radius: 0;
min-width: 0;
height: 100%;
width: 33%;
min-height: 0;
font-size: 1rem;
text-align: center;
}
</style>
This is a summary of how I'm using this component:
<div class="item" v-for="item in items" :key="item.id" #click="toggleItem(item.id)" :class="{ active: activeItems[item.id] }">
<h1>{{ item.name }}, some other elements irrelevant are here too</h1>
<NumberField
:defaultValue="item.amount"
:max="item.amount"
:min="1"
:step="1"
:disabled="!activeItems[item.id]"></NumberField>
</div>
toggleItem(id) toggles the boolean value of activeItems[item.id]. The NumberField is disabled when the item is inactive.
My expectation would be that clicking on any of the child elements of .numberField would fire the #click of .numberField, which (only if the item is inactive) then gets propagated to the #click of .item, but this only seems to be the case when clicking the input[type=number].
I would appreciate any help, I'm absolutely lost!
A <button> with a disabled attribute set will not fire click events. If the event doesn't fire on the <button> then it won't propagate to the <div> either.
In your case a simple workaround would be to put pointer-events: none on your buttons so that the button is skipped altogether. The <div> will just receive the click directly, as though the button wasn't even there.
const NumberField = {
name: 'NumberField',
template: `
<div class="numberField" #click="fieldClicked">
<button #click="stepDown()" :disabled="disabled" class="left">
−
</button>
<input
v-model="value"
type="number"
:max="max"
:min="min"
:step="step"
:disabled="disabled">
<button #click="stepUp()" :disabled="disabled" class="right">
&plus;
</button>
</div>
`,
props: {
defaultValue: Number,
max: Number,
min: Number,
step: Number,
disabled: Boolean,
},
data() {
return {
value: this.defaultValue,
};
},
watch: {
value() {
this.value = Math.min(this.max, Math.max(this.min, this.value));
},
},
methods: {
stepDown() {
this.value -= this.step;
},
stepUp() {
this.value += this.step;
},
fieldClicked(event) {
console.log('here')
// #click.stop will stop all clicks from propagating; we will only stop clicks when the field is active
if (!this.disabled) event.stopPropagation()
},
},
};
new Vue({
el: '#app',
components: {
NumberField
}
})
.numberField {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
height: 3em;
width: 8em;
}
.left {
border-top-left-radius: 0.2em;
border-bottom-left-radius: 0.2em;
}
.right {
border-top-right-radius: 0.2em;
border-bottom-right-radius: 0.2em;
}
input, button {
padding: 0;
border-radius: 0;
min-width: 0;
height: 100%;
width: 33%;
min-height: 0;
font-size: 1rem;
text-align: center;
}
button[disabled] {
pointer-events: none;
}
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<div id="app">
<number-field :defaultValue="7" :step="1" :min="0" :max="10" disabled></number-field>
</div>

Div (contains list of items) not close when clicked outside

Please open https://jsfiddle.net/gfmyt9u8/31/
When user clicks outside <section> tag area, then the opened div overlay panel should be closed.
Steps to produce scenario :
Click "Please Select Options"
Now, click first item from opened overlay panel (by doing this, the panel got closed automatically)
Next, Click inside the blue color border div (This shows "Please Select Options" as label) again
Now, try to click outside the "blue color border div" and "opened div overlay panel beneath" both
overlay panel will not close
Actual Result : overlay panel is not closing
Expected Result : overlay panel should close when clicked outside the "blue color border div" and "open overlay panel
beneath"
Use the mounted lifecycle hook to add a click event listener to check if the click event is outside the element or not, and based on that hide the element.
A working example:
new Vue({
el: '#app',
data: {
displayList: false,
cat: ['A', 'B']
},
methods: {
itemSelect(o) {
this.displayList = false;
}
},
mounted: function () {
// Listen to all clicks on the document
document.addEventListener("click", function(event) {
// If the click inside the element, do nothing
if (event.target.closest(".section-main")) return;
// If the clicks outside the element, hide it!
this.displayList = false;
}.bind(this));
}
});
.display-no-selected {
cursor: text;
width: 300px;
height: 25px;
border: solid 2px blue;
}
.display-list {
border: solid 1px wheat;
width: 300px;
max-height: 150px;
overflow-y: auto;
}
.toggle-list {
display: none;
}
ul, .selected-ul {
list-style-type: none;
margin: 0;
padding: 0;
}
ul.inner-ul li {
cursor: pointer;
font-weight: normal;
}
ul.inner-ul li:hover {
background-color: wheat;
}
.default-highlight {
background-color: wheat;
}
ul.inner-ul li span {
margin-left: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<section class="section-main">
<div class="display-no-selected" #click="displayList=true"> Please Select Options
</div>
<div class="display-list"
v-bind:class="{'toggle-list': !displayList}">
<ul class="inner-first-ul inner-ul">
<li v-for="o in cat" #click="itemSelect(o)">
<span>{{o}}</span>
</li>
</ul>
</div>
</section>
</div>

How to create the perfect autosize textarea?

I do auto expanding textarea.
The principle is this: I create a hidden div in which I place the input text, then in the updated () method I define the height of the div and apply the value to the textarea.
But there is one problem - there is text twitching, because First, the text crawls up, and then when the field is expanded, it returns to its place. As if the updated () method works late. By the same principle, I made a text field in the ReactJS there was no such effect.
What can do with it?
How it works: https://jsbin.com/zakavehewa/1/edit?html,css,js,console,output
<template>
<div class="textarea_wrap">
<textarea class="text_input textarea" v-model="value" ref="textarea"></textarea>
<div v-if="autoRow" class="text_input textarea shadow" ref="shadow">{{ value }}!</div>
</div>
</template>
<script>
export default {
props: {
autoRow: {
type: Boolean,
default: false
},
default: String
},
data () {
return {
value: this.default,
}
},
mounted() {
this.updateHeight()
},
updated() {
this.updateHeight()
},
methods: {
updateHeight() {
if (this.autoRow && this.$refs.shadow) {
this.$refs.textarea.style.height = this.$refs.shadow.clientHeight + 5 + 'px'
}
}
}
}
</script>
<style lang="scss" scoped>
.textarea_wrap {
position: relative;
}
.textarea {
line-height: 1.5;
min-height: 31px;
width: 100%;
font-family: inherit;
}
.shadow {
position: absolute;
left: -9999px;
pointer-events: none;
white-space: pre-wrap;
word-wrap: break-word;
resize: none;
}
</style>
Checkout https://github.com/wrabit/vue-textarea-autogrow-directive, it caters for rendering in hidden divs plus copying and pasting text.