mauricius / vue-draggable-resizable

Vue3 Component for draggable and resizable elements.
https://mauricius.github.io/vue-draggable-resizable/
MIT License
3.33k stars 559 forks source link

Dynamically Adjust height to fit content. #277

Closed adamprocter closed 3 years ago

adamprocter commented 3 years ago

I would like to adjust the height of the draggable element as content expands dynamically in it. Setting css to min-height doesn’t help. I am assuming I need to update the height attribute with some JavaScript but wasn’t sure if this was already built in? Thanks

TitanFighter commented 3 years ago

Get height of content, then using h prop set height of draggable element.

Or like this: https://mauricius.github.io/vue-draggable-resizable/?path=/story/basic--basic-component-with-auto-size

adamprocter commented 3 years ago

Thanks , Yes I am now re-setting the height based on content and drag box size now as the auto thing doesnt stay in place once you start moving and resizing manually, where as checking I can resize on drop

adamprocter commented 3 years ago

I wonder if there maybe a way to do this with the objects so they always respect the content size https://dev.to/sammm/using-mutationobserver-and-resizeobserver-to-measure-a-changing-dom-element-in-vue-3jpd

TitanFighter commented 3 years ago

What objects do you mean?

adamprocter commented 3 years ago

I just mean the draggable objects

TitanFighter commented 3 years ago

Thanks , Yes I am now re-setting the height based on content and drag box size now as the auto thing doesnt stay in place once you start moving and resizing manually, where as checking I can resize on drop

This is a bit mixed, so probably this is the reason I do not understand something. Does it mean that you change height but then dragging or resizing an object resets the height?

adamprocter commented 3 years ago

Sorry Im probably not being clear and I have a workround but see this video - the content on auto can still fall out of the container once resized even with Auto on https://www.loom.com/share/1cf3e4e149534daabdcd3e4f5ab606c4

TitanFighter commented 3 years ago

@adamprocter

Here is the code you need:

const textHeight = document.getElementsByClassName('draggable resizable vdr')[0].getElementsByTagName('p')[0].offsetHeight

Code is written for this example: https://mauricius.github.io/vue-draggable-resizable/?path=/story/basic--basic-component-with-auto-size Change width of container few times and after each change run the above code in console and you will catch the idea.

Then write a code where min height of the container can not be less than textHeight, something like

if (containerHeight + 10px <= textHeight) {
  // block vertical resizing
}
Adhders commented 3 years ago

I wonder if there maybe a way to do this with the objects so they always respect the content size https://dev.to/sammm/using-mutationobserver-and-resizeobserver-to-measure-a-changing-dom-element-in-vue-3jpd

you can try this way , changing the content size through the item during dragging @resizing="((x, y, width, height)=>{onResize(x, y, width, height,item)})"

selfagency commented 3 years ago

I'm doing more or less what @TitanFighter suggests but in a Vue way...

<template>
  <draggable
    :id="id"
    class="window"
    h="auto"
    :min-height="minHeight"
    :min-width="minWidth"
  >
    <title-bar ref="titleBar" :title="title"></title-bar>
    <div ref="windowBody" class="window-body">
      <slot></slot>
    </div>
  </draggable>
</template>

<script>
export default {
  props: {
    id: {
      type: String,
      default: '',
    },
    title: {
      type: String,
      default: '',
    },
    minWidth: {
      type: Number,
      default: 0,
    },
  },
  data() {
    return {
      minHeight: 0,
    }
  },
  mounted() {
    this.$nextTick(() => {
      setTimeout(() => {
        this.minHeight = this.getHeight()
      }, 1000)
    })
  },
  methods: {
    getHeight() {
      const titleBar = this.$refs.titleBar?.$el
      const windowBody = this.$refs.windowBody

      return titleBar && windowBody
        ? titleBar.offsetHeight + windowBody.offsetHeight + 30
        : 0
    },
  },
}
</script>

...and it appears that the properties aren't being updated reactively. As you can see here, the prop for 'min-height' isn't changing the data of 'minH' in the component.

CleanShot 2021-07-24 at 15 19 57

And indeed, upon examining the code, that is the problem. If you assign a prop to the data object, it will only copy its initial value, it will not update reactively. Those props should either be passed directly to the component or returned as computed values from the computed property.

{
  data: function () {
    return {
      left: this.x,
      top: this.y,
      right: null,
      bottom: null,
      width: null,
      height: null,
      widthTouched: false,
      heightTouched: false,
      aspectFactor: null,
      parentWidth: null,
      parentHeight: null,
      minW: this.minWidth,
      minH: this.minHeight,
      maxW: this.maxWidth,
      maxH: this.maxHeight,
      handle: null,
      enabled: this.active,
      resizing: false,
      dragging: false,
      dragEnable: false,
      resizeEnable: false,
      zIndex: this.z
    }
  },
}

I have it working and passing all linting and tests in #310.