2

I'm trying to create a layout with elements (input fields in this case), where the user can add as many of them as they want, and also remove them. The elements go into columns and each column can have a maximum of 4 elements. Here's a simple version, without the column functionality https://jsfiddle.net/khfpp2vL/2/

If there's 4 elements, it should look like this:

[1]
[2]
[3]
[4]

If a fifth element is added, it should be in its own column:

[1][5]
[2]
[3]
[4]

And with more elements:

[1][5][9]
[2][6][10]
[3][7]
[4][8]

And so on.

I can't create wrappers and have four elements each, because if elements are removed from the middle, the ones that are left must be able to switch to another column. For example if I remove 3 and 6 from the previous example, it would change to

[1][7]
[2][8]
[4][9]
[5][10] 

I've tried css columns, something like this http://jsfiddle.net/NJ4Hw/ (not created by me). But the problem is that I can't control the amount of elements in each column. I can change the column count with javascript when the amount of elements is divisible by 4, so I'll have the right amount of columns, but I you for example remove everything but 9 elements in the fiddle and change the column count to three, it will divide them equally like this:

[1][4][7]
[2][5][8]
[3][6][9]

And I need it to still have 4 elements in the first columns:

[1][5][9]
[2][6]
[3][7]
[4][8]

I also thought of a solution where the parent has a max-height, and only four elements would fit in it vertically, but I couldn't figure out how to arrange them like that. For example if I use floats, it will float 1 and 2 next each other when the space runs out.

So I'm not sure what to try next. Flexbox? Some kind of Javascript solution? Or is there some super simple solution that I haven't thought of?

YellowPlanet
  • 55
  • 1
  • 4

3 Answers3

2

I've tried css columns, something like this http://jsfiddle.net/NJ4Hw/ (not created by me). But the problem is that I can't control the amount of elements in each column.

You can, by controlling the height of the elements and the height of the columns in your container:

.container {
  -moz-column-count: 4;
  -moz-column-gap: 20px;
  -webkit-column-count: 4;
  -webkit-column-gap: 20px;
  column-count: 4;
  column-gap: 20px;
  height: 5em;
}
.container > input {
  height: 1em;
  margin: 0;
}
<!--[if lt IE 10]>
<style>
/* This is copied from the Fiddle you referenced, I presume it's a
   fallback for IE9 and earlier not supporting columns or some such
*/
.container > input {
    width: 25%;
    float: left
}
</style>
<![endif]-->
<div class="container">
  <input type="text" value="Item 1">
  <input type="text" value="Item 2">
  <input type="text" value="Item 3">
  <input type="text" value="Item 4">
  <input type="text" value="Item 5">
  <input type="text" value="Item 6">
  <input type="text" value="Item 7">
  <input type="text" value="Item 8">
  <input type="text" value="Item 9">
  <input type="text" value="Item 10">
  <input type="text" value="Item 11">
  <input type="text" value="Item 12">
  <input type="text" value="Item 13">
  <input type="text" value="Item 14">
  <input type="text" value="Item 15">
  <input type="text" value="Item 16">
  <input type="text" value="Item 17">
  <input type="text" value="Item 18">
  <input type="text" value="Item 19">
  <input type="text" value="Item 20">
  <input type="text" value="Item 21">
  <input type="text" value="Item 22">
  <input type="text" value="Item 23">
</div>

Obviously, you'll want to tweak to make it look good. :-)

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thanks! This seemed to work well, but then I tried it with smaller column count and less elements [https://jsfiddle.net/khfpp2vL/5/](https://jsfiddle.net/khfpp2vL/5/) And it doesn't have four in each column anymore. Am I missing something? I also need to have it working when there's only a few elements. – YellowPlanet Jun 20 '16 at 16:49
  • @YellowPlanet: Ugh, you're right, the browser tries to balance the columns. [This question](http://stackoverflow.com/questions/18061860/how-to-prevent-starting-a-new-css-column-until-necessary) covers that and has a couple of answers, but I don't have time now to try them out. :-| – T.J. Crowder Jun 20 '16 at 17:11
  • Okay thanks, I'll look into that if the other solutions won't work! – YellowPlanet Jun 21 '16 at 07:25
2

This can be done with CSS flex box. I put together a quick version. You can learn tweak it to get it the way you want.

http://codepen.io/aaronbalthaser/pen/vKXVvm

I added the following CSS to your code:

.inputs {
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
  -webkit-flex-direction: column;
      -ms-flex-direction: column;
          flex-direction: column;
  -webkit-flex-wrap: wrap;
      -ms-flex-wrap: wrap;
          flex-wrap: wrap;
  height: 120px;
  width: 100%; 
}

.container {
  -webkit-align-self: flex-start;
      -ms-flex-item-align: start;
          align-self: flex-start; 
}
Aaron
  • 2,364
  • 2
  • 31
  • 56
  • Thank you! This was working perfectly, until I tried with IE... [https://jsfiddle.net/khfpp2vL/7/](https://jsfiddle.net/khfpp2vL/7/) I have to support IE11 in compatibility view, I guess I should have mentioned that in the beginning. I added some prefixes, but do I need some more? Or will it ever work in IE? – YellowPlanet Jun 20 '16 at 16:56
  • I added the required prefixes. Also changed the height from max to explicit. Here is a link the can i use: http://caniuse.com/#feat=flexbox If you select known issues you can try to track diagnose them from the list. I am sorry I cannot spend too much time making this bullet proof. I also am unaware of specification Im sure. – Aaron Jun 20 '16 at 20:25
0

You can edit the JS in your first jsfiddle to the following:

$('.add').on('click', function() {
  if($('.inputs:last .container').length > 3){
    $('.inputs:last').last().after('<div class="inputs"></div>');
  };
  $('.inputs:last').append(' \
    <div class="container"> \
        <input type="text" class="input"> \
      <button class="remove">Remove</button> \
     </div>'
   );
});

And add this to your stylesheet:

.inputs { float: left; }
Ninowis
  • 379
  • 1
  • 8
  • This one is adding wrapper divs? I said in my post: "I can't create wrappers and have four elements each, because if elements are removed from the middle, the ones that are left must be able to switch to another column." And it doesn't work like that with your code. If you add elements and then remove some of them, you'll see what I mean [https://jsfiddle.net/khfpp2vL/8/](https://jsfiddle.net/khfpp2vL/8/) – YellowPlanet Jun 20 '16 at 17:06