<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Passing Curiosity: Posts tagged tables</title>
    <link href="https://passingcuriosity.com/tags/tables/tables.xml" rel="self" />
    <link href="https://passingcuriosity.com" />
    <id>https://passingcuriosity.com/tags/tables/tables.xml</id>
    <author>
        <name>Thomas Sutton</name>
        
        <email>me@thomas-sutton.id.au</email>
        
    </author>
    <updated>2011-07-11T00:00:00Z</updated>
    <entry>
    <title>Drupal 7: theming forms with tables</title>
    <link href="https://passingcuriosity.com/2011/drupal-7-forms-tables/" />
    <id>https://passingcuriosity.com/2011/drupal-7-forms-tables/</id>
    <published>2011-07-11T00:00:00Z</published>
    <updated>2011-07-11T00:00:00Z</updated>
    <summary type="html"><![CDATA[<p>There are a few different ways to use tables to layout Drupal 7
forms. The most commonly described method (indeed, it’s used in the
core [tableselect][1] form field type) is to create a custom form
field type that can process it’s children and render as a table. This
is pretty limiting (<code>tableselect</code>, for instance, is pretty much just a
select field).</p>
<p>Another approach is to use <code>#prefix</code> and <code>#suffix</code> to wrap each field
in the table with the appropriate HTML tags to build the table. This,
though, means that changing the weights of elements, adding and
removing elements, or making pretty much any change to the form might
result in invalid or completely broken markup.</p>
<p>The approach I think is best is to treat the table similarly to the
way the forms API handles fieldsets: as a container with multiple
fields within it. This can be a little tricky to get working, but
seems to do the trick for me. The approach works like this:</p>
<p>Create a new form element that will be the table:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode php"><code class="sourceCode php"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">&lt;?php</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="va">$form</span>[<span class="st">'people'</span>] <span class="op">=</span> <span class="dt">array</span>(</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  <span class="st">'#prefix'</span> =&gt; <span class="st">'&lt;div id=&quot;people&quot;&gt;'</span><span class="ot">,</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  <span class="st">'#suffix'</span> =&gt; <span class="st">'&lt;/div&gt;'</span><span class="ot">,</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>  <span class="st">'#tree'</span> =&gt; <span class="kw">TRUE</span><span class="ot">,</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>  <span class="st">'#theme'</span> =&gt; <span class="st">'table'</span><span class="ot">,</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>  <span class="st">'#header'</span> =&gt; <span class="dt">array</span>(t(<span class="st">'First name'</span>)<span class="ot">,</span> t(<span class="st">'Family name'</span>))<span class="ot">,</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>  <span class="st">'#rows'</span> =&gt; <span class="dt">array</span>()<span class="ot">,</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>)<span class="ot">;</span></span></code></pre></div>
<p>Then loop over your data to create the rows in the table. This is a
little tricky: if you just put your fields straight into
<code>$form['people']['#rows']</code> then FAPI won’t see them (remember that it
won’t traverse array components begining with a <code>#</code>) and so won’t
process them. On the other hand, you <em>could</em> name your array
<code>$form['people']['rows']</code> but then the FAPI will generate quite noisy
field names and add additional values which will confuse
<code>theme_table()</code> when it comes time to render the whole lot.</p>
<p>Instead, we’ll use references to build both include the fields in the
form (though in a way that they won’t be actually output) <em>and</em> put
them in <code>$form['people']['#rows']</code> so the table will be rendered
nicely. This is possible mainly through the use of references!</p>
<p>Assuming you’ve got an array <code>$people</code> containing your data you can
loop over them to add the rows to your table like so (and yes, I know
this could be structured better):</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode php"><code class="sourceCode php"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">&lt;?php</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> (<span class="va">$i</span> <span class="op">=</span> <span class="dv">0</span><span class="ot">;</span> <span class="va">$i</span> <span class="op">&lt;</span> <span class="fu">count</span>(<span class="va">$people</span>)<span class="ot">;</span> <span class="va">$i</span><span class="op">++</span>) {</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Build the fields for this row in the table. We'll be adding</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>  <span class="co">// these to the form several times, so it's easier if they are</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>  <span class="co">// individual variables rather than in an array.</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>  <span class="va">$fname</span> <span class="op">=</span> <span class="dt">array</span>(</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>    <span class="st">'#id'</span> =&gt; <span class="st">'people-'</span> <span class="op">.</span> <span class="va">$i</span> <span class="op">.</span> <span class="st">'-fname'</span><span class="ot">,</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>    <span class="st">'#type'</span> =&gt; <span class="st">'textfield'</span><span class="ot">,</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>    <span class="st">'#default_value'</span> =&gt; <span class="va">$people</span>[<span class="va">$i</span>][<span class="st">'fname'</span>]<span class="ot">,</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>  )<span class="ot">;</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>  <span class="va">$sname</span> <span class="op">=</span> <span class="dt">array</span>(</span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>    <span class="st">'#id'</span> =&gt; <span class="st">'people-'</span> <span class="op">.</span> <span class="va">$i</span> <span class="op">.</span> <span class="st">'-sname'</span><span class="ot">,</span></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a>    <span class="st">'#type'</span> =&gt; <span class="st">'textfield'</span><span class="ot">,</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a>    <span class="st">'#default_value'</span> =&gt; <span class="va">$people</span>[<span class="va">$i</span>][<span class="st">'sname'</span>]<span class="ot">,</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a>  )<span class="ot">;</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Include the fields so they'll be rendered and named</span></span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a>  <span class="co">// correctly, but they'll be ignored here when rendering as</span></span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a>  <span class="co">// we're using #theme =&gt; table.</span></span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a>  <span class="co">//</span></span>
<span id="cb2-23"><a href="#cb2-23" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Note that we're using references to the variables, not just</span></span>
<span id="cb2-24"><a href="#cb2-24" aria-hidden="true" tabindex="-1"></a>  <span class="co">// copying the values into the array.</span></span>
<span id="cb2-25"><a href="#cb2-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-26"><a href="#cb2-26" aria-hidden="true" tabindex="-1"></a>  <span class="va">$form</span>[<span class="st">'people'</span>][] <span class="op">=</span> <span class="dt">array</span>(</span>
<span id="cb2-27"><a href="#cb2-27" aria-hidden="true" tabindex="-1"></a>    <span class="st">'fname'</span> =&gt; <span class="op">&amp;</span><span class="va">$fname</span><span class="ot">,</span></span>
<span id="cb2-28"><a href="#cb2-28" aria-hidden="true" tabindex="-1"></a>    <span class="st">'sname'</span> =&gt; <span class="op">&amp;</span><span class="va">$sname</span><span class="ot">,</span></span>
<span id="cb2-29"><a href="#cb2-29" aria-hidden="true" tabindex="-1"></a>  )<span class="ot">;</span></span>
<span id="cb2-30"><a href="#cb2-30" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb2-31"><a href="#cb2-31" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Now add references to the fields to the rows that</span></span>
<span id="cb2-32"><a href="#cb2-32" aria-hidden="true" tabindex="-1"></a>  <span class="co">// `theme_table()` will use.</span></span>
<span id="cb2-33"><a href="#cb2-33" aria-hidden="true" tabindex="-1"></a>  <span class="co">//</span></span>
<span id="cb2-34"><a href="#cb2-34" aria-hidden="true" tabindex="-1"></a>  <span class="co">// As we've used references, the table will use the very same</span></span>
<span id="cb2-35"><a href="#cb2-35" aria-hidden="true" tabindex="-1"></a>  <span class="co">// field arrays as the FAPI used above.</span></span>
<span id="cb2-36"><a href="#cb2-36" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-37"><a href="#cb2-37" aria-hidden="true" tabindex="-1"></a>  <span class="va">$form</span>[<span class="st">'people'</span>][<span class="st">'#rows'</span>][] <span class="op">=</span> <span class="dt">array</span>(</span>
<span id="cb2-38"><a href="#cb2-38" aria-hidden="true" tabindex="-1"></a>    <span class="dt">array</span>(<span class="st">'data'</span> =&gt; <span class="op">&amp;</span><span class="va">$fname</span>)<span class="ot">,</span></span>
<span id="cb2-39"><a href="#cb2-39" aria-hidden="true" tabindex="-1"></a>    <span class="dt">array</span>(<span class="st">'data'</span> =&gt; <span class="op">&amp;</span><span class="va">$sname</span>)<span class="ot">,</span></span>
<span id="cb2-40"><a href="#cb2-40" aria-hidden="true" tabindex="-1"></a>  )<span class="ot">;</span></span>
<span id="cb2-41"><a href="#cb2-41" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-42"><a href="#cb2-42" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Because we've used references we need to `unset()` our</span></span>
<span id="cb2-43"><a href="#cb2-43" aria-hidden="true" tabindex="-1"></a>  <span class="co">// variables. If we don't then every iteration of the loop will</span></span>
<span id="cb2-44"><a href="#cb2-44" aria-hidden="true" tabindex="-1"></a>  <span class="co">// just overwrite the variables we created the first time</span></span>
<span id="cb2-45"><a href="#cb2-45" aria-hidden="true" tabindex="-1"></a>  <span class="co">// through leaving us with a form with 3 copies of the same fields.</span></span>
<span id="cb2-46"><a href="#cb2-46" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb2-47"><a href="#cb2-47" aria-hidden="true" tabindex="-1"></a>  <span class="kw">unset</span>(<span class="va">$fname</span>)<span class="ot">;</span></span>
<span id="cb2-48"><a href="#cb2-48" aria-hidden="true" tabindex="-1"></a>  <span class="kw">unset</span>(<span class="va">$sname</span>)<span class="ot">;</span></span>
<span id="cb2-49"><a href="#cb2-49" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>Now you should have a form full of fields all laid out nicely in a
table. Hoorah!</p>]]></summary>
</entry>

</feed>
