wyc
wyc

Reputation: 55273

Why is the following assignment removing the "width and height" properties?

I have an array of objects:

elements: [
    {
      id: '1',
      dataX: 0,
      dataY: 0
    },
    {
      id: '2',
      dataX: 189,
      dataY: 189
    }
  ]

They are used in the template like this:

// This is inside a repeat loop:
<a class="btn"
  id="{{ id }}"
  data-x="{{ dataX }}"
  data-y="{{ dataY }}"
  style="transform: translate({{ dataX }}px, {{ dataY}}px);">
</a>

Final output:

<a class="btn" id="2" data-x="189" data-y="189" style="transform: translate(189px, 189px); width: 144px; height: 36px;"></a>

I have code that changes the value of data-x and data-y and the transform property, so the anchor tags can be dragged.

At the end of that function I have a few lines that change the array elements itself:

const target = event.target
const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx
const y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy

// the code that makes the anchor tags move

// the code that modifies the array itself
 this.elements.map(item => {
   if (item.id === target.id) {
      item.dataX = x
      item.dataY = y
    }
 })

It works. However, the width and height properties are wiped out:

<a class="btn" id="2" data-x="189" data-y="189" style="transform: translate(189px, 189px);"></a>

Why is this and how to prevent it?

NOTE: this.elements is a reactive element. Meaning that if it data changes the element is re-rendered in the template.

EDIT (full JavaScript code. I'm using Interact.js):

 ready () {
    interact('#plane > *')
      .draggable({
        snap: {
          targets: [
            interact.createSnapGrid({ x: this.baseUnit, y: this.baseUnit })
          ],
          range: Infinity,
          relativePoints: [ { x: 0, y: 0 } ]
        },
        restrict: {
          restriction: 'parent',
          elementRect: { top: 0, left: 0, bottom: 1, right: 1 }
        },
        onmove: (event) => {
          const target = event.target
          const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx
          const y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy

          // translate the element
          target.style.webkitTransform =
          target.style.transform =
            'translate(' + x + 'px, ' + y + 'px)'

          // update the positon attributes
          target.setAttribute('data-x', x)
          target.setAttribute('data-y', y)

          this.elements.map(item => {
            if (item.id === target.id) {
              console.log(item)
              item.dataX = x
              item.dataY = y
            }
          })
        }
      })
      .resizable({
        snap: {
          targets: [
            interact.createSnapGrid({ x: this.baseUnit, y: this.baseUnit })
          ],
          range: Infinity,
          relativePoints: [ { x: 0, y: 0 } ]
        },
        edges: { left: true, right: true, bottom: true, top: true },
        onmove: (event) => {
          const target = event.target
          let x = (parseFloat(target.getAttribute('data-x')) || 0)
          let y = (parseFloat(target.getAttribute('data-y')) || 0)

          // update the element's style
          target.style.width = event.rect.width + 'px'
          target.style.height = event.rect.height + 'px'

          // translate when resizing from top or left edges
          x += event.deltaRect.left
          y += event.deltaRect.top

          target.setAttribute('data-width', event.rect.width)
          target.setAttribute('data-height', event.rect.height)

          target.textContent = Math.round(event.rect.width) + '×' + Math.round(event.rect.height)
        }
      })
  },

Upvotes: 3

Views: 234

Answers (1)

Peter M. Elias
Peter M. Elias

Reputation: 1194

Here is my wild guess at what is happening in the face of some missing pieces...

You probably have some kind of binding setup so that when the array changes (as mutated by the map call) it re-renders the template; I'm assuming that.

The original template (pre map call) contains width and height values in the style attribute but is not clear where these come from. What is clear is that they are not included in your re-computation.

Therefore, my guess is they are being overridden by the map call because it re-writes the entire style attribute with ONLY the transform.

Add the width and height values back onto the dynamically rendered value for the style attribute and you'll be okay.

EDIT: With the full code posted basically everything I said is true except with the added flavor of competing onmove events. (I believe)

What I think is happening is your first onmove event is firing and setting the width and height and then the second one fires and overwrites the style with transform. Fixing this is a matter of changing up the logic a bit so your event handlers are not fighting each other.

Upvotes: 2

Related Questions