Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Form with related record editing #419

Closed
romaninsh opened this issue Mar 28, 2018 · 7 comments
Closed

Form with related record editing #419

romaninsh opened this issue Mar 28, 2018 · 7 comments
Assignees
Labels
enhancement 👍 hangout agenda 🔈 Will discuss on next hangout

Comments

@romaninsh
Copy link
Member

romaninsh commented Mar 28, 2018

Sometimes in the Form you want to also be able to edit related records.

Suppose you have "Inovice" model which "hasMany('Lines')". Each line contains "item_no", "item_name" as well as "price" and some other columns.

screen shot 2018-03-28 at 20 32 58

However, before you save the form, you cannot add items. This results in a difficult-to-implement UI.

My proposal is to implement this as extension to the form.

  1. Implement a MultiLineForm component, which looks like a regular form, but will duplicate itself to add more and more fields.
  2. Form will not submit, instead it will serialize it's fields (array of hashes)
  3. On initialization form can use same JSON to pre-fill the values.

So here is what can be done:

  1. Add a regular form for model for 'Invoice'
  2. Add a hidden field.
  3. Add MultiLineForm for $invoice->refModel('Lines');

This can be wrapped nicely into a Component that interract with form.

$form->add(['MultiLine', 'Lines']);

Additionally this can extend $form->save mechanics like this:

  1. first $form->model is saved.
  2. next $form->model->ref('Lines') is populated with supplied data.
  3. if already exists, lines will be removed/amended.

Alltogether this would be a powerful mechanism how to edit record along with it's related records. I think that multiple MultiLineForm components can be used to work on various related records.

This also makes possible to use many-to-many relations.

$form->setModel(['Invoice']);
$form->add(['MultiLine', 'PaymentAllocation', ['payment_id']);

See also: #351

@funyx
Copy link
Contributor

funyx commented Apr 24, 2019

I've spend some time working on scenario like this:

// test model a
$model_a = new \atk4\data\Model($app->db,[
    'table' => 'test_a'
]);
$model_a->addFields([
    ['name_a'],
    ['flag_a' => 'boolean']
]);
// test model b
$model_b = new \atk4\data\Model($app->db,[
    'table' => 'test_b'
]);
$model_b->addFields([
    ['name_b'],
    ['flag_b' => 'boolean']
]);
// test model c
$model_c = new \atk4\data\Model($app->db,[
    'table' => 'test_c'
]);
$model_c->addFields([
    ['name_c'],
    ['flag_c' => 'boolean']
]);

$model_c->hasOne('test_b_id',[$model_b]);
$model_b->hasOne('test_a_id',[$model_a]);
$model_a->hasOne('ModelB',[$model_b]);
$model_b->hasMany('ModelC',[$model_c]);


// include a, b, c in form fields for add/edit

$a = $app->add(['\ddfsbo\Form']);
$a->setModel($model_a,false);
$a->addField('name_a');

// use the sublayout directly
//$b = $a->addRef('ModelB');
//$b->addField('name_b')

// or use the form layout
$a->addField('ModelB.name_b');

// use the sub-sublayout directly
//$c = $b->addRef('ModelC');
//$c->addField('name_c')

// or use the form layout
$a->addField('ModelB.ModelC.name_c');

that involved adding functionality to store atk4\data\Model References and their section layout within the \atk4\ui\View and also creating two new instances to interpret them

  • \atk4\ui\FormLayout\Section\Reference_One
  • \atk4\ui\FormLayout\Section\Reference_Many

Goals:

  • they should be traversable using the Form::model as root
  • they should have ::model set with conditions (Form::model->ref($refLink))
  • they should use hoooks beforeSubmit and afterSave for propagating all the data in the reference Tree

What do you think of an implementation like this @romaninsh ?

  • Model::Reference->ui['form'] might hold specific seed (which extends ..\Section\Reference_**)
  • if we implement Section\Reference_** as interfaces the seeds might inherit already existing sections like Accordion and Tabs
  • functionality like this (managing view->refs) would allow us implementation for the functionality in most of the ui components..

@skondakov
Copy link
Contributor

@funyx As far as I understand @romaninsh has asked here what we need and proposes a solution to have 2 forms, but you propose to have 1 section of the standard form for fields and below another section for Reference fields.

I like @funyx idea here. I just think for something in between i.e. extending the Form class by providing this ref editing functionality that @funyx is talking about. Maybe naming the new form something like AdvancedForm or MultilineForm .

WDYT think guys?

@DarkSide666
Copy link
Member

Form can have multiple layout segments and if I am not mistaken then each segment can have separate model attached and all of them will be saved when form submits. Maybe that can help somehow here too?

@funyx
Copy link
Contributor

funyx commented Apr 25, 2019

yup, that's the idea..
atm the we have a layout which has a form instance within it, that form instance uses the layout's ability to addField..
the segments are attached to the form and can manipulate the model and the layout.. but thats it..
what i mean is that nowhere in the FormLayout i can find something with model relations (references)..
you are able to attach fields from different models via the FormFieldDecorator but the layout is trying to insert them in the layout::model, which shouldn't be the default behaviour of the component i think..
that's why my idea was to introduce atk4\data\reference to atk4\ui\view mirroring the atk4\data\model's functionality..

$form->addField('parent_name'); // result -> <input name="parent_name" />

// parent->hasOne('child')
$form->addField('child.child_name'); // result -> <input name="[child]child_name" />

// parent->hasMany('children')
$form->addField('children.child_name'); // result -> <input name="[children][0]child_name" />
$form->addField('children.child_name'); // result -> <input name="[children][1]child_name" />

on form submit

$parent_model_instance->import($submitted_data);

@romaninsh
Copy link
Member Author

Implemented by #700

@PhilippGrashoff
Copy link
Collaborator

I think this can be closed as the MultiLine FormField now exists.

@PhilippGrashoff PhilippGrashoff added the hangout agenda 🔈 Will discuss on next hangout label Aug 22, 2019
@abbadon1334
Copy link
Collaborator

referenced in #784

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement 👍 hangout agenda 🔈 Will discuss on next hangout
Development

No branches or pull requests

7 participants