{"id":233,"date":"2014-09-22T17:42:52","date_gmt":"2014-09-22T17:42:52","guid":{"rendered":"https:\/\/www.lianeallen.com\/home\/?p=233"},"modified":"2014-09-23T04:12:33","modified_gmt":"2014-09-23T04:12:33","slug":"module-to-auto-generate-column-widths-in-a-grid-system","status":"publish","type":"post","link":"https:\/\/www.lianeallen.com\/home\/2014\/09\/module-to-auto-generate-column-widths-in-a-grid-system\/","title":{"rendered":"Module to Auto-generate Column Widths in a Grid System"},"content":{"rendered":"<p>Yesterday, I added the ability for admins to view, create, and edit categories. This meant I needed to display columns of categories, organized by category type (think of it as meta-categories) &#8211; just what I had done on the home page, but without the extra column to deal with. <\/p>\n<p>The code I&#8217;d written to generate the columns on the home page was seriously ugly, and there was no way I wanted to copy it into *another* controller. Nope. This was a time to stay <a href=\"http:\/\/en.wikipedia.org\/wiki\/Don't_repeat_yourself\">DRY<\/a>.<\/p>\n<p>So, I made a module, and refactored the heck out of the code &#8211; resulting in what you see above. Instead of more than 30 lines of <strong><em>eeeek!<\/em><\/strong>, it&#8217;s now 18 lines that you can actually read:<\/p>\n<p><a href=\"https:\/\/github.com\/liantics\/gph\/blob\/master\/lib\/generate_column_widths.rb\">https:\/\/github.com\/liantics\/gph\/blob\/master\/lib\/generate_column_widths.rb<\/a><\/p>\n<h3>Here&#8217;s How it Works:<\/h3>\n<p>In <a href=\"http:\/\/getbootstrap.com\/getting-started\/\">Bootstrap 3<\/a>, columns are arranged in rows. Each row has a certain maximum number of columns in it. The default is 12. <\/p>\n<p>The columns in a row can be divided into sections, using a &#8220;<strong>col-<\/strong>&#8221; css class that indicates how many of those 12 columns you want to use for each section of content within the row. <\/p>\n<p>The css class also indicates the smallest screen size on which to apply that class. Any device with a screen below that size will default to using all 12. Everything above that size will use the number you specify. (You can specify for multiple sizes, too, but I&#8217;ll leave that to the bootstrap docs).<\/p>\n<p>So, if you want your 12 columns divided evenly into 4 sections, you&#8217;d use a span of &#8220;3&#8221;: which means you want each section take up 3 of the 12 columns. Dividing the 12 columns by the span indicates how many sections you&#8217;ll end up with. In this case, 12 \/ 3 = 4, so the row will be divided into 4 sections.<\/p>\n<p>In your html, the css class to make 4 even columns for all screen sizes, from size small (tablet) on up, would look like this:<\/p>\n<blockquote><p><code>col-sm-3<\/code><\/p><\/blockquote>\n<p>&#8220;<strong>col<\/strong>&#8221; = define a column span<br \/>\n&#8220;<strong>sm<\/strong>&#8221; = define the screen size at which to start using this span<br \/>\n&#8220;<strong>3<\/strong>&#8221; = the number of columns to use for this section. <\/p>\n<p>In a div on your page, it would look like:<\/p>\n<blockquote><p><code>&lt;div class=\"col_sm_3\"><\/code><\/p><\/blockquote>\n<p>So far, so good!<\/p>\n<h3>What To Do About Empty Columns?<\/h3>\n<p>But what if you won&#8217;t know how many columns you&#8217;re going to need until you do some other calculation (like in my case, I have no idea if there will be any projects in a given meta-category), and you don&#8217;t want to display any empty columns?<\/p>\n<h3>The Default Solution is Ugly<\/h3>\n<p>The default solution is to pick the maximum number of columns, programmatically don&#8217;t show any columns that are empty, and do some css magic to align things. But I don&#8217;t like that, because you end up with clumps of unnecessary css alignment divs all over your code. I hate having to add a bunch of nested divs in order to make things align. <\/p>\n<h3>What If the Server Could Do It?<\/h3>\n<p>I thought what if, instead, the server could figure that stuff out all on its own, and automatically re-size columns based on what&#8217;s needed in a given spot at a given time. Even more important, on one page, I needed an extra column of data to co-exist alongside the meta-categories.<\/p>\n<p>So the problem is even bigger than not knowing how many columns I&#8217;m going to have, but not necessarily knowing how many I need them to fit alongside. In the case of the home page, from the user&#8217;s perspective, the extra column (&#8220;projects near the finish line&#8221;) is just another meta-category for projects, but from the system&#8217;s perspective, it&#8217;s something completely different, calculated separately based on the number of donations a project has received, and it needs to fit nicely with the auto-generated category columns.<\/p>\n<p>What I wanted to be able to do from the controller was generate the column span value, based on:<\/p>\n<blockquote>\n<ul>\n<li>The number of new columns I was adding to the view<\/li>\n<li>The number of columns that the new columns would have to share space with<\/li>\n<li>The minimum span size (the number to divide into the total number of columns)<\/li>\n<li>The maximum span size (essentially, this is what to do if there&#8217;s only one column)<\/li>\n<li>The total number of columns available &#8211; in case I decided to use a grid that wasn&#8217;t 12 columns wide in the future. I&#8217;ve used 9 in the past.<\/li>\n<\/ul>\n<\/blockquote>\n<p>From a code perspective, in the controller, this is roughly what I needed to be able to specify:<\/p>\n<blockquote><p><code> @column_span = generate_a_span(<br \/>\n      &nbsp;&nbsp;number_of_new_columns,<br \/>\n      &nbsp;&nbsp;total_columns_in_row,<br \/>\n      &nbsp;&nbsp;number_of_existing_columns_if_any,<br \/>\n      &nbsp;&nbsp;minimum_span_size,<br \/>\n      &nbsp;&nbsp;maximum_span_size<br \/>\n    )<\/code><\/p><\/blockquote>\n<p>And in the view, I&#8217;d use something like:<\/p>\n<blockquote><p><code>&lt;div class=\"col-sm-&lt;%= @column_span %>\"><\/code><\/p><\/blockquote>\n<p>But &#8230;<\/p>\n<h3>Specifying All Those Vars Every Time Would Be Annoying<\/h3>\n<p>I didn&#8217;t want to have to specify every single variable every time. Most of the time, everything but the number of new columns would be entirely optional, because I&#8217;d want 4 columns on most pages, and I&#8217;m not likely to change the grid size willy-nilly. This meant making all but one variable optional, and defining defaults for the rest. <\/p>\n<h3>The result: <\/h3>\n<blockquote><p><code>def generate_widths(new_columns,<br \/>\n                      &nbsp;&nbsp;total_grid_columns: 12,<br \/>\n                      &nbsp;&nbsp;existing_columns: 0,<br \/>\n                      &nbsp;&nbsp;min_column_span: 3,<br \/>\n                      &nbsp;&nbsp;max_column_span: 12<br \/>\n                  )<br \/>\n<\/code><\/p><\/blockquote>\n<p>In my controller for the home page, I have:<\/p>\n<blockquote><p><code>@column_width = Category.new.generate_widths(<br \/>\n      &nbsp;&nbsp;@category_types_count, existing_columns: 1<br \/>\n    )<\/code><\/p><\/blockquote>\n<p>This handles the new columns I&#8217;m creating based on the number of category types in use (<strong>@category_types_count<\/strong>) as well as the one existing column generated from another source (<strong>existing_columns: 1<\/strong>). <\/p>\n<p>Since I&#8217;m using the defaults for total grid columns, the minimum column span, and the maximum column span, I don&#8217;t have to specify those.<\/p>\n<p>In my controller for the categories display page for admins, I have: <\/p>\n<blockquote><p><code>@column_width = Category.new.generate_widths(@category_types.count)<\/code><\/p><\/blockquote>\n<p>Since I don&#8217;t have to accommodate columns generated by other sources, I need only specify the number of new columns I&#8217;m adding, thus I can skip the &#8220;existing_columns&#8221; specification. <\/p>\n<p>In both views, I have:<\/p>\n<blockquote><p><code>&lt;div class=\"col-sm-<%= @column_width %>\"><\/code><\/p><\/blockquote>\n<p>That&#8217;s it.<\/p>\n<p>All I had to do was include the module in my category model. <\/p>\n<h3>Extra Cool<\/h3>\n<p>The extra cool thing: this can be used for any grid system that uses a numeric value in the css class strings in the view. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Yesterday, I added the ability for admins to view, create, and edit categories. This meant I needed to display columns of categories, organized by category type (think of it as meta-categories) &#8211; just what I had done on the home page, but without the extra column to deal with. The code I&#8217;d written to generate &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.lianeallen.com\/home\/2014\/09\/module-to-auto-generate-column-widths-in-a-grid-system\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Module to Auto-generate Column Widths in a Grid System&#8221;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":234,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-233","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.lianeallen.com\/home\/wp-json\/wp\/v2\/posts\/233","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lianeallen.com\/home\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lianeallen.com\/home\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lianeallen.com\/home\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lianeallen.com\/home\/wp-json\/wp\/v2\/comments?post=233"}],"version-history":[{"count":11,"href":"https:\/\/www.lianeallen.com\/home\/wp-json\/wp\/v2\/posts\/233\/revisions"}],"predecessor-version":[{"id":257,"href":"https:\/\/www.lianeallen.com\/home\/wp-json\/wp\/v2\/posts\/233\/revisions\/257"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.lianeallen.com\/home\/wp-json\/wp\/v2\/media\/234"}],"wp:attachment":[{"href":"https:\/\/www.lianeallen.com\/home\/wp-json\/wp\/v2\/media?parent=233"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lianeallen.com\/home\/wp-json\/wp\/v2\/categories?post=233"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lianeallen.com\/home\/wp-json\/wp\/v2\/tags?post=233"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}