Vue - Setting the width of a component dynamically - javascript

I can't figure out how to dynamically set the width of a component.
I am using the component 'vue-burger-menu' -> https://github.com/mbj36/vue-burger-menu.
To set the width one needs to set the prop width to a number. As per the example below:
<Slide
ref="slideToggle"
disable-esc
class="slideToggle"
width="470"
right
:burger-icon="false"
:cross-icon="false"
disable-outside-click
>
It then sets a helper class - bm-menu width to the width. I have spent quite a while trying to figure out how to either set the prop's attribute dynamically or dynamically update the style.
For example I tried setting: this.$refs.slideToggle.$attrs.width = 1000 to no avail.
I can't bind a style to the bm-menu class as it's not visible.
How do I set the width so on the click of a button it changes (as per the button example below)?
Thanks for your help!
setDrawWidth() {
this.lineDrawWidth = "200px";
}

You just need binding which uses : before props:
<Slide
ref="slideToggle"
disable-esc
class="slideToggle"
:width="width"
right
:burger-icon="false"
:cross-icon="false"
disable-outside-click
>
And then in your data in js part:
export default {
data:() => ({ width: '470' }),
}
Now you just need to change width variable. For example:
export default {
data:() => ({ width: '470' }),
methods:{
changeWidth(){
this.width = '1000';
}
}
}
You can read more about binding variables from the doc: Vue Props

Listen on window width event:
data: () => ({
width: 470
})
created() {
window.addEventListener("resize", this.changeWidth);
},
destroyed() {
window.removeEventListener("resize", this.changeWidth);
},
methods: {
changeWidth(e) {
const screenWidth = window.innerWidth;
this.width = screenWidth
}
}
and set width in Slide component:
<Slide
ref="slideToggle"
disable-esc
class="slideToggle"
:width="width"
right
:burger-icon="false"
:cross-icon="false"
disable-outside-click
>

Related

Responsive canvas vuejs

I'm trying to make my canvas fit its container, in a vue component.
I fire resizeCanvas() in mounted, but the container height and width are 0.
How can I have a canvas that fits its container, so that I can change the container size using css and it will update the canvas ?
(Sorry for my english, i'm not fluent)
<template lang="html">
<div class="container" ref="container">
<canvas ref="canvas" :width="width" :height="height"></canvas>
</div>
</template>
<script>
export default {
name: "monster",
data ()
{
return {
width: 512,
height: 512
}
}
methods: {
resizeCanvas(){
console.log(this.$refs.container.offsetWidth); // logs 0
this.width = this.$refs.container.offsetWidth
this.height = this.$refs.container.offsetWidth
}
},
mounted ()
{
console.log(this.$refs.container.offsetWidth) // logs 0
window.addEventListener("resize", this.resizeCanvas);
this.resizeCanvas()
},
unmounted() {
window.removeEventListener("resize", this.resizeCanvas);
},
}
</script>
<style lang="css" scoped>
.container {
width: 100%; height: 100%
}
</style>
The mounted lifecycle hook in VueJS does not guarantee that the DOM is ready: you will need to wait for this.$nextTick() and then check the dimensions of your container element.
You can do it by moving the logic into the callback of nextTick, i.e.:
mounted () {
this.$nextTick(() => {
console.log(this.$refs.container.offsetWidth);
window.addEventListener("resize", this.resizeCanvas);
this.resizeCanvas();
});
},
If you're familiar with the async/await way of doing things, then you can also do this:
async mounted () {
await this.$nextTick();
console.log(this.$refs.container.offsetWidth);
window.addEventListener("resize", this.resizeCanvas);
this.resizeCanvas();
},
Another possibility is to delegate this "wait for DOM to be ready" responsibility to the resizeCanvas function, so you have full abstraction and separation of concerns:
methods: {
async resizeCanvas(){
await this.$nextTick();
this.width = this.$refs.container.offsetWidth
this.height = this.$refs.container.offsetWidth
}
},
mounted () {
window.addEventListener("resize", this.resizeCanvas);
this.resizeCanvas();
},

How to change context in Ag Grid React

I'm trying to use the documentation for adding context to my React Ag Grid app. My issue is that their code example doesn't use the way that I create the grid. This is how they add the context
var gridOptions = {
columnDefs: columnDefs,
defaultColDef: {
flex: 1,
resizable: true
},
rowData: rowData,
context: {
reportingCurrency: 'EUR'
},
};
// setup the grid after the page has finished loading
document.addEventListener('DOMContentLoaded', function() {
var gridDiv = document.querySelector('#myGrid');
new agGrid.Grid(gridDiv, gridOptions);
});
And they change the context value like this
function currencyChanged() {
var value = document.getElementById('currency').value;
gridOptions.context = {reportingCurrency: value};
gridOptions.api.refreshCells();
gridOptions.api.refreshHeader();
}
I'm using React though, so I'm creating my component like this
const [gridParams, setGridParams] = useState(null);
const onFirstDataRendered = (params) => {
setGridParams(params)
}
<AgGridReact
columnDefs={columnDefs}
defaultColDef={{
flex: 1,
resizable: true
}}
rowData={rowData}
context={{ reportingCurrency: 'EUR' }}
onFirstDataRendered={onFirstDataRendered}
>
This is how I'm changing context in my file
const currencyChange = (value) => {
gridParams.context = { reportingCurrency: value };
gridParams.api.refreshCells();
};
When I update the context like this, my cells don't see that the context has changed for them. Since the documentation doesn't show how to implement this for React, I figured I'm just missing something. Does anyone have any idea what that could be?
It looks like the way to change the context is actually different. After poking around, it looks like it needs to be changed like this
const currencyChange = (value) => {
gridParams.api.gridOptionsWrapper.gridOptions.context = { reportingCurrency: value };
gridParams.api.refreshCells();
};

Set the dynamic height and width to Konva Stage in Vue.js

I want to set the height and width of the Konva based on the width of its parent container. As I was using static value for the stage which is
stageConfiguration:{ height: innerWidth * .5, width:innerWidth * 0.5}
And have to refresh every time I resize the screen. Is there a way to set the dynamic height and width to stageConfiguration. Current I am stuck on this and looking for a way to set dynamic height and width.
<template>
<div class="konvaContainer">
<v-stage :config="stageConfiguration" >
<v-layer>
</v-layer>
</v-stage>
</div>
</template>
<script>
export default {
components: {
Loading
},
data: () => ({
stageConfiguration: {}
)},
methods:
{
responsiveStage : function() {
var container = document.querySelector('.konvaContainer');
var width = container.clientWidth;
const stageWidth= width*.5;
const stageHeight= width *.5;
this.stageConfiguration ={
width:stageWidth,
height:stageHeight
}
}}
}
</script>
You can use ResizeObserver or resize event from the window to detect size changes.
Here is a solution with ResizeObserver:
<template>
<div class="container">
<v-stage ref="stage" :config="stageSize">
<v-layer>
<v-circle
:config="{
x: stageSize.width / 2,
y: stageSize.height / 2,
radius: stageSize.width / 2,
fill: 'green',
}"
/>
</v-layer>
</v-stage>
</div>
</template>
<style>
.container {
width: 100vw;
height: 100vh;
}
</style>
<script>
export default {
data() {
return {
stageSize: {
width: 10,
height: 10,
},
};
},
mounted() {
const container = document.querySelector(".container");
const observer = new ResizeObserver(() => {
this.stageSize.width = container.offsetWidth;
this.stageSize.height = container.offsetHeight;
});
observer.observe(container);
},
};
</script>
Demo: https://codesandbox.io/s/vue-konva-change-stage-size-or-resize-tbwec?file=/src/App.vue

React: changing state onMouseOver

I'm trying to change a background image state when hovering an element (icon) but I'm always getting the error "TypeError: Cannot read property "icon" of undefined", which is strange, since the icon is working fine until I hover it.
Glad if anyone could help.
States:
this.state = {
images: {
header: "path to img",
icon: "path to icon"
}
}
The method:
handleMouseOver = () => {
this.setState({
images: {
header: "new img"
}
});
};
Header component receiving the image:
<Header bgImg={this.state.images.header} />
Hovered element:
<div>
<img onMouseOver={this.handleMouseOver} src={this.state.images.icon} />
</div>
This issue come from your onMouseOver function, which set a new value for state but remove icon from the images object. You need to run the following:
handleMouseOver = () => {
this.setState((state, props) => {
return {
images: {
header: "new img",
icon: state.images.icon
}
};
});
};
This is because when you are setting your images you are losing icon state. Try like this:
handleMouseOver = () => {
this.setState(prevState => ({
images: {
...prevState.images,
header: "new img"
}
}));
};
You are using the old images by spreading it and then update the necessary property. Why we use setState callback and prevState? Because when we are setting our new state we are depending on our old state.

Vue - change input width according to content

So I can do this (Pug & CoffeeScript):
input(placeholder="0", v-model.number="order[index]" v-on:change="adjustInput")
...
adjustInput: ->
event.target.style.width = event.target.value.length + 'ch'
... but it only works if I change the input in the browser, by hand. The input does not change its width if the v-model changes.
How can I make it so that the input width changes even if the change is due to Vue reactivity?
Check this one, but you must check the font-size on input and on fake_div
var app = new Vue({
el: '#app',
data() {
return {
order: 1, // your value
fakeDivWidth: 10, // width from start, so input width = 10px
};
},
watch: {
order: { // if value from input changing
handler(val) {
this.inputResize();
},
},
},
methods: {
inputResize() {
setTimeout(() => {
this.fakeDivWidth = this.$el.querySelector('.fake_div').clientWidth;
}, 0);
},
},
})
.fake_div {
position: absolute;
left: -100500vw;
top: -100500vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input placeholder="0" v-model.number="order" v-bind:style="{width: fakeDivWidth + 'px'}" >
<div class="fake_div">{{ order }}</div> // fake_div needed to see this div width
// этот блок фейковый и нужен только для того, что бы наш input становился такого же размера как этот div
</div>
Try this
input(placeholder="0", v-model.number="order[index]" v-on:change="adjustInput" :style="{width: reactiveWidth}")
// Your secret Vue code
data() {
return function() {
reactiveWidth: 100px; // (some default value)
}
},
methods: {
adjustInput() {
this.reactiveWidth = event.target.value.length + 'ch'
}
},
computed: {
reactiveWidth() {
return this.number + 'ch';
}
}
Since I don't know all parts of the code, you might need to tweak this a bit. With just binding this.number to a order[index] you are not affecting the width of the input in any way. The computed property listens to changes in number
The easiest workaround to me is to replace the input field with a contenteditable span which will wrap around the text:
<script setup>
import {reactive} from 'vue'
const state = reactive({
input: 'My width will adapt to the text'
})
</script>
<template>
<span class="input" #input="e => state.input = e.target.innerText" contenteditable>{{state.input}}</span>
</template>
This works like v-model=state.input

Categories