akeeba / fof

Rapid Application Development framework for Joomla!™ 3 and 4
0 stars 0 forks source link

Easy way to render btn-group-yesno #698

Closed compojoom closed 3 years ago

compojoom commented 3 years ago

I'm rewriting the view of an extension I wrote around 2015 which used the F0F XML forms. I'm writing a blade template and I'm wondering if there is an easy way/helper to render a yes/no radio buttons with bootstrap styling:

image

With the forms I was using BooleanToggle:

        <field
            name="is_double"
            type="BooleanToggle"
            label="COM_CAPARTMENTS_APARTMENT_FIELD_IS_DOUBLE"
            required="true"
            />

I tried to use @jhtml('select.booleanlist', 'enabled', array(), $item->enabled) but this one doesn't render the fieldset necessary for the btn-group. I also searched in ars for something similar, but there I see you only render genericList.

compojoom commented 3 years ago

And I'm wondering. So the F0F XML forms are gone, but can we easily use the joomla forms in the templates?

I used to have such a view:

image

Which was pretty easy to generate: form.default.xml

<?xml version="1.0" encoding="utf-8"?>
<form
    type="browse"
    show_header="1"
    show_filters="1"
    show_pagination="1"
    norows_placeholder="COM_CAPARTMENTS_COMMON_NORECORDS"
    relation_depth="2"
    >

    <field name="capartments_unit_id" type="Model"
           sortable="true" apply_access="false"
           label="COM_CAPARTMENTS_TITLE_APARTMENTS"
           key_field="capartments_unit_id" value_field="[ITEM:TITLE] [ITEM:FLOOR].[ITEM:NUMBER]"
           parse_value="true"
           model="Apartments"
           required="true"
           none="None"
        />

    <field name="parking_id" type="Model"
           sortable="true" apply_access="false"
           key_field="capartments_unit_id" value_field="[ITEM:TITLE] [ITEM:FLOOR].[ITEM:NUMBER]"
           parse_value="true"
           model="Parkings"
           label="COM_CAPARTMENTS_PARKINGBOOKINGS_PARKING_LABEL"
           required="true"
           none="None"
        />

    <field name="capartments_bookingperiod_id" type="Model"
           sortable="true" apply_access="false"
           label="COM_CAPARTMENTS_BOOKINGS_CAPARTMENTS_BOOKINGPERIOD_ID_LABEL"
           key_field="capartments_bookingperiod_id" value_field="title"
           model="Bookingperiods"
           none="None"
           required="true"
        />

    <field name="user" type="User" label="COM_CAPARTMENTS_BOOKINGS_USER_LABEL"/>
    <field name="parking_user" type="User" label="COM_CAPARTMENTS_BOOKINGS_USER_LABEL"/>
</form>

and then I was rendering the form with:

<?php
defined('_JEXEC') or die('Restricted access');

$form = $this->container->factory->form('contracts', 'form.default', 'Contracts');

?>

<div class="box-info">
    <h2>Vertrag generieren</h2>
    <div class="col-md-3">
        <form action="index.php" method="post" class="form">
            <div class="form-group">
                <?php echo $form->renderField('capartments_unit_id'); ?>
            </div>

            <div class="form-group">
                <?php echo $form->renderField('capartments_bookingperiod_id'); ?>
            </div>

            <div class="form-group">
                <?php echo $form->renderField('user'); ?>
            </div>

            <button class="btn-primary btn">
                Apartment Mietvertrag generieren
            </button>

            <input type="hidden" name="contract_type" value="apartments" />
            <input type="hidden" name="task" value="generate" />
            <input type="hidden" name="option" value="com_capartments" />
            <input type="hidden" name="view" value="Contracts" />
        </form>
    </div>
</div>

putting the complicated fields:

    <field name="parking_id" type="Model"
           sortable="true" apply_access="false"
           key_field="capartments_unit_id" value_field="[ITEM:TITLE] [ITEM:FLOOR].[ITEM:NUMBER]"
           parse_value="true"
           model="Parkings"
           label="COM_CAPARTMENTS_PARKINGBOOKINGS_PARKING_LABEL"
           required="true"
           none="None"
        />

aside - I'm currently wondering how to render a user select field?

what html am I supposed to write for this? Or are we still able to define joomlaforms and render them instead?

nikosdion commented 3 years ago

You can see how I have solved these problems for FEF in https://github.com/akeeba/fof/tree/development/fof/Utils/FEFHelper and https://github.com/akeeba/fof/tree/development/fof/ViewTemplates/Common I wrote my own HTMLHelper helpers which duplicate Joomla's but use markup specific for my CSS framework. You could create your own helpers which create BS2 or BS5 markup depending on the Joomla version.

For fields which are implemented as Layouts in Joomla we just use FOF30\Layout\LayoutFile to load and render them. This allows per-component template overrides of these fields if needed. That's the only difference to Joomla's LayoutFile class.

You can create your own renderer and Blade compiler extension to reduce the repeated code in your component. See the FEF renderer to see how I am handling wrapping my output with special classes and the ATS' custom Blade compiler extension (also applicable in Akeeba Ticket System Core) for how to register a custom extension to the Blade compiler extension.

For commonly used fields I created Blade view templates which abstract this for me. Since ViewTemplateFinder allows per Joomla-version and per-renderer suffixes (see the comments in FOF30\View\ViewTemplateFinder::resolveUriToPath()). For example, you could have yes_no.j3.blade.php and yes_no.j4.blade.php files to render the fancy yes/no radios in Joomla 3 and 4 respectively. In the former case it'd just call the core select HTMLHelper to render a radio list with a special class. In the latter case it's a layout file.

Yes, it's a lot of hard work. In the past I had to do this and I had to keep it updated for each and every new Joomla version. It was no longer a tenable approach which is why I removed the XML forms. I don't have the time to deal with Joomla changing its internals every minor version and making massive b/c changes between Joomla 4 beta 6 and 7. In the end of the day it was cheaper commissioning my own CSS framework and writing my own JS framework than relying on the whims of an unreliable partner. It is what it is...

compojoom commented 3 years ago

Thanks Nick! I was afraid that you'll say this. That's a little sad and doesn't feel as "rapid" as it used to be, but that's life.

Using the Layoutfile feels a little cumbersome when one is used to just generate a xml form and do renderField on it :)

I'll have to write some code I guess :)

nikosdion commented 3 years ago

XML forms were very limiting and not RAD at all except for extremely simple use cases. Whenever you needed to do anything beyond simple text display and hardcoded drop-downs you needed to make custom fields which were cumbersome to say the least.

I am maintaining more than 20 extensions, a dozen of which are components. I had hit a wall with XML forms in 2016. That's why I implemented Blade templates in our software, seeing how much easier it was past the small initial time investment.

The new method has a bit of upfront time investment but the end result is much cleaner view files which support advanced features without having to write custom fields for each extension and view. If you take a look at ATS you'll see that we have FOF Blade extensions to query a Model and display a title field when our local model only stores an ID, for example. Search boxes, drop-down boxes etc are the same. All the boiler plate code for making browse and edit views is abstracted away and reusable in master Blade files.

You can use that code, part of FOF 3 and the upcoming version 4, convert them to use whichever version of Bootstrap you're targeting and turn them into a mini library for your extensions. From that point your extension development and maintenance is far easier than using XML forms.

Bonus points: if you decide to change the CSS framework you're using 80% of your work is addressing the common code and 20% is changing your views. Even better, your custom code can be wrapped in a renderer and your view template files can target it by means of their file extension. This means that you can detect, for example, the Joomla version in your Dispatcher or custom Container, assign the correct renderer and have an extension that runs on multiple Joomla versions without much fanfare. You couldn't really do that with XML forms. The core fields required me to spend 10x as much time to massage for a new Joomla version and they still wouldn't address custom fields, of which there were about a dozen in every non-trivial extension. There was no way to reliably make a core or custom field cross-framework without convoluted code that was hard to maintain at best. I told you, XML forms hit a wall circa 2016. They were a great idea in 2011 but definitely not anymore. The same problems exist with wherever Joomla is still using XML forms (extension options, extending category/article options etc) and they do drive me insane.