2

I want to append .item from .left to .right on page load and resize when $(window).width() < 479. The problem is that with multiple instances, the resize function re-iterates to append .item several times.

How do I change the code so that it only executes once per .item?

codepen.io/moofawsaw/pen/PoNVejV

function moveDiv() {
  if ($(window).width() < 479) {
    $('.item').appendTo('.right');
  } else {
    $('.item').appendTo('.left');
  }
}
moveDiv();
$(window).resize(moveDiv);
body {
  display: flex;
}

.post {
  display: flex
}

.item {
  height: 100px;
  width: 100px;
  border: 2px solid;
}

.right,
.left {
  min-width: 100px;
  height: 200px;
}

.right {
  background: silver;
}

.left {
  background: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="post">
  <div class="right">
    <div class="item"></div>
  </div>
  <div class="left"></div>
</div>
<div class="post">
  <div class="right">
    <div class="item"></div>
  </div>
  <div class="left"></div>
</div>
Kyle Underhill
  • 89
  • 15
  • 43
  • You need to debounce. That's probably [covered well already](https://stackoverflow.com/questions/45905160/javascript-on-window-resize-end). – isherwood Sep 24 '20 at 16:47
  • Perhaps I am not using the debounce correctly: https://codepen.io/moofawsaw/pen/PoNVejV – Kyle Underhill Sep 24 '20 at 17:21
  • @KyleUnderhill There is probably a much cleaner way of achieving something you are trying to do. Can you please provide more details on what is expected behaviour? Do you want the same item bounce between two containers on different screen sizes? – Vasiliy Artamonov Oct 02 '20 at 13:31

1 Answers1

1

If I would answer the given question, here it is.

The main problem in the given code was that $('.item') selects all existing .items and clones them as much as there are .right or .left items on the page. It would work perfectly if you had only one of those .right or .left containers.

So to solve this one we won't select all .items at once and instead we would process each .item separately using convenient jQuery function .each()

function moveDiv() {
  if ($(window).width() < 479) {
    moveItemInPostTo('.right');
  } else {
    moveItemInPostTo('.left');
  }
}

function moveItemInPostTo(selector) {
  // Instead of working with all .item elements at once,
  // iterate over each one separately
  $('.item').each(function(i, el) {
    // Get parent container, in which we can find
    // both .left and .right elements
    var $post = $(el.closest('.post'));
    // Move the .item to one of them
    $(el).appendTo($post.find(selector));
  })
}

moveDiv();
$(window).resize(moveDiv);
body {
  display: flex;
}

.post {
  display: flex
}

.item {
  height: 100px;
  width: 100px;
  border: 2px solid;
}

.right,
.left {
  min-width: 100px;
  height: 200px;
}

.right {
  background: silver;
}

.left {
  background: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="post">
  <div class="right">
    <div class="item"></div>
  </div>
  <div class="left"></div>
</div>
<div class="post">
  <div class="right">
    <div class="item"></div>
  </div>
  <div class="left"></div>
</div>

Though this code works well, I would really recommend you solve this one in a non-javascript way (probably, just CSS). And if it still should be done using javascript - at least don't use jQuery. It is not really optimized in terms of how much it is pressuring the internet traffic (almost 90KB), and every thing you do with jQuery you can achieve using plain Javascript. Although, gotta admit, it's good for starters.

I answered your question, but if you would provide more details on what are your trying to achieve, I probably could give you another good answer.

Vasiliy Artamonov
  • 939
  • 2
  • 8
  • 24
  • Thanks for the answer. I have a list of items each having a button nested within. When in mobile view, I want to move this button to a placement inside the item that cant be achieved using CSS because it needs to be moved to an unrelated div inside of the item – Kyle Underhill Oct 02 '20 at 14:21
  • @KyleUnderhill Could it be done without using nested containers? I mean, you can use a very powerful tool called CSS Grid, it is very flexible in terms of layout on different screen sizes – Vasiliy Artamonov Oct 02 '20 at 14:35
  • @KyleUnderhill Also it is very expensive operation to move an item in DOM on every `$(window).resize()` trigger – Vasiliy Artamonov Oct 02 '20 at 14:40
  • I only need it moved if the window is ever < 479 so if there is a better way to trigger this if the user resizes the window to this width please let me know. – Kyle Underhill Oct 02 '20 at 14:45
  • @KyleUnderhill Okay maybe that's the information for another big topic, but if you are interested you can check these articles: https://medium.com/@patrickbrosset/css-grid-layout-6c9cba6e8a5a and https://css-tricks.com/snippets/css/complete-guide-grid/. It has a good browser support nowadays: https://caniuse.com/css-grid. For supporting old Microsoft browsers you can use CSS post-processors like PostCSS autoprefixer with some task-runner like Webpack, Gulp or Grunt: https://github.com/postcss/autoprefixer That's a lot of reading I would say – Vasiliy Artamonov Oct 02 '20 at 15:23