How to set form data for a Joomla subform?

1.9k views Asked by At

I'm trying to create a Joomla (3.x) component and struggling with using subforms. There doesn't seem to be much documentation for using subforms besides e.g. https://docs.joomla.org/Subform_form_field_type

For my component I have one parent table and some associated database rows from a child table.

The idea is to display an edit form for that parent table using Joomla's XML syntax for forms and in that edit form also display a subform with multiple items (the associated rows from the child table).

I would like to be able to modify the parent table fields but also in one go the associated child table rows (of course one could just edit each row associated to the parent table individually but I'm guessing that would be a terrible user experience). Or am I approaching this thing the wrong way?

Now, I know how to implement/show a subform and also know how to show the parent table fields and populate those fields with the right data. But how do I populate or refer to the subform using the parent form?

I have this function inside my component model (which inherits from JModelAdmin).

protected function loadFormData()
{
  $data = JFactory::getApplication()->getUserState('com_mycomp.edit.parent.data', array());

  if (empty($data))
  {
    $data = $this->getItem();
    // how to refer to subform fields inside $data?
  }

  return $data;
}

I know if a field is called name or title I can just change the $data object after $this->getItem(), e.g. $this->set('name', 'John Doe').

Let's say the field of type subform has a name attribute of books and I wanted to insert one or more rows, how would I refer to it? I've tried dot syntax in various forms, e.g.: $data->set('books.1.childfield') or $data->set('books.pages1.childfield'). But it doesn't seem to refer to the right form.

There is of course getForm function in the same model file, however I do not think a subform should be loaded independently of the containing parent form?

public function getForm($data = array(), $loadData = true)
{
  $app = JFactory::getApplication();

  $form = $this->loadForm('com_mycomp.parent', 'parent', array('control' => 'jform', 'load_data' => $loadData));
  if (empty($form))
  {
    return false;
  }

  return $form;
}

EDIT: Already answered my own question.

1

There are 1 answers

0
Wieger On BEST ANSWER

Never mind. I figured it out after taking a break for some time and trying again (inspecting the form inputs again and taking a deep breath).

This is the format used:

$data->set('nameofsubformfield',
[
  'nameofsubformfield0' => [
    'fieldwithinsubform' => 'value-of-field-within-subform'
  ]
]);

This seems to work! I'm using this within getItem function now. Just have to loop and put loop counter in place of the zero after nameofsubformfield. See code below for some context (function resides in parent model).

public function getItem($pk = null)
  {
    $data = parent::getItem((int)$pk);
    if (empty($data))
    {
       return false;
    }
    $childModel = JModelLegacy::getInstance('child', 'MycompModel');
    $rowChildren = $childModel->getChildrenByParentID((int)$data->get('id'));
    $childArray = [];
    for ($i = 0; $i < count($rowChildren); $i++)
    {
        $childArray['children'. $i] = [
            'name' => $rowChildren[$i]['name']
        ];
    }
    $data->set('children', $childArray);
    return $data;
}