XF 2.2 dynamic table column headers

briansol

Well-known member
Is something like this possible in the template itself, or do i need to pre-generate the list of field names in the viewparams?

idea is that the entity would drive the template. If i add a new field, the table i use to show it will grow/shrink based on the query/columns returned itself.

Code:
               <tr>
                    <xf:foreach loop="$mydata" key="$key" value="$value">
                        <th>{$mydata[0].colname}</th>                        
                    </xf:foreach>
                             
                </tr>
 
I Really want to do this as it will save me from having a ton of nearly identical templates.

Code:
            $headers = ['fields', 'I', 'want', 'including', 'RELATIONS.fieldname', 'not', just', 'RELATIONID'];

            $data = $this->getMyEntireData();
            
            $viewParams = [
                'data'            => $data,
                'headers'        => $headers              
            ];

            return $this->view('My\Mod:User\View', 'my_mod_genericlistview',$viewParams);


Code:
<table>
                <tr>
                    <xf:foreach loop="$headers" value="$h">
                        <th>{$h}</th>
                    </xf:foreach>
                </tr>            
                <xf:foreach loop="$data" value="$d">
                    <tr>
                        <xf:foreach loop="$headers" value="$h">
                            <td>{$d.$h}/td>
                        </xf:foreach>
                    </tr>
                </xf:foreach>                
            </table>

obviously, the $d.$h doesn't work.

It seems to make more sense to clean it on the backend before sending it to the template, but i can't get relations fields to come through. I get undefined array key RELATION.fieldname when i try to bring the relation value in from the id of the main table.
 
Yes, it does, for items that are in the main table.

For joined values (eg, RELATION.name where RELATIONID is stored in the main table), it throws a getter error.


Template errors​

  • Template public:my_mod_genericlistview: [E_USER_WARNING] Accessed unknown getter 'RELATION.name' on My\Mod:MyEntity[1] (src\XF\Mvc\Entity\Entity.php:199)
 
How is the relation defined, and how are you accessing it, exactly?

Code:
$structure->relations = [
    'User' => [
        'entity' => 'XF:User',
        'type' => self::TO_ONE,
        'conditions' => 'user_id',
        'primary' => true,
    ],
];

HTML:
$entity.User.username
 
For joined values (eg, RELATION.name where RELATIONID is stored in the main table), it throws a getter error.
Because you need manually resolve value.
Generating HTML code based on header titles and required column from entities - great idea, but slow and requiring a lot of code in places.
The right decision would be generating a template instead writing a template where you generate this "hard" HTML.
 
How is the relation defined, and how are you accessing it, exactly?
Oh, I see now. The . (period) in a template is the equivalent of accessing an element in an array (or the object operator when calling a method, but that's not relevant here). For example, $entity.Relation.column is compiled down to $entity['Relation']['column']. However, in your array the period is merely part of a string at runtime, so your usage becomes equivalent to $entity['Relation.column'].

You would probably have to do something like:
PHP:
$displayColumns = [
    'column1',
    'column2',
    'Relation' => [
        'column1',
        'column2',
    ],
    // ...
];

...but you'd need to adapt your template to loop over any sub-arrays, and come up with a scheme to serialize the sub-arrays into headings so it's still a bit of an awkward approach.
 
so using that approach, gives me

Template Compilation Error​

public:my_mod_genericlistview - substr(): Argument #1 ($string) must be of type string, array given in C:\xampp\htdocs\xf\src\XF\Mvc\Entity\Entity.php:123

I assume this is what you expected to see when templating the new sub-arry.

So, i altered my template to try to look for that and came up with:

Code:
<tbody>
                        <xf:foreach loop="$data" value="$d">
                            <tr>
                                <xf:foreach loop="$fields" key="$k" value="$f">
                                    <td>
                                        <xf:if is="$k==0">
                                            <a href="{{ link('base/'.{$type}, {$d}) }}">{$d.{$f}}</a>
                                        <xf:else />
                                            <xf:if is="$d.f is not empty">
                                                <xf:foreach loop="$d.f" value="$i">
                                                    {$i.{$d.{$f}}}
                                                </xf:foreach>
                                            <xf: else />
                                                {$d.{$f}}
                                            </xf:if>
                                        </xf:if>
                                    </td>
                                </xf:foreach>
                            </tr>
                        </xf:foreach>                        
                    </tbody>

this line (and similiar syntax in non template braces
Code:
<xf:if is="$d.f is not empty">
do not seem to work. I tried it a few different ways

With this, i also get a php error,
Code:
Fatal error: Illegal offset type
which points to my new subarray line in $fields

Code:
$fields = ['name', 'TYPES' => ['typename']];
$headers = ['Name', 'Type'];


            $viewParams = [
                'title'            => $title,
                'headers'        => $headers,
                'fields'        => $fields,
                'data'            => $data,
            ];

I know this seems convoluted but in doing this loop, I eliminate upwards of 50 templates effectively doing the exact same thing but with hard-coded headers in exchange for 2 lines of code in the controller ($headers and $fields as view params).


If you were building a Zoo database,
would you have a template for lion, one for puma, one for tiger, etc? or would you have a 'cats' template that took data?
The data might be different across the animals. Perhaps tigers use a 'pattern' header for their fur where as puma and lion use a 'color' header.
 
Back
Top Bottom