Crud: [4.1] Relationship field does not work inside repeatable

Created on 29 Apr 2020  路  17Comments  路  Source: Laravel-Backpack/CRUD

I've managed to get it to work in part using the Repeatable Relationship field.
With the following attribute:
'multiple' => false,
'data_source' => url($this->crud->route.'/fetch/person'),

I can add the data or register a new one in the table.

    //RELATIVE
         $this->crud->addField([
            'name'  => 'relation_relative',
            'label' => trans('contact.relative.data'),
            'type'  => 'repeatable',
            'tab'   => trans('contact.relative.tab'),
            'fields' => [
                [   'name' => 'id',
                    'type' => 'hidden',
                ],
                [   'name' => 'contact_id',
                    'type' => 'hidden',
                    'default'   =>  $this->crud->getCurrentEntryId(),
                ],        
           [
            'name'  => 'data1',
            'label' => trans('contact.relative.name'),
            'type'  => 'relationship',
            'wrapper'   => ['class' => 'form-group col-md-8'],           
            'entity'    => 'relatives.person',
            'data_source' => url($this->crud->route.'/fetch/person'),
            'attribute' => 'display_name',
            'model'     => 'App\Models\ContactPerson',
            'ajax' => false,
            'multiple' => false,
            'allows_null' => true,
            'inline_create' => ['entity' => 'contactperson'],             
            ],  
                [   'name'  => 'data2',
                    'label' => trans('contact.relative.type'),
                    'type'  => 'select_from_array',
                    'wrapper' => ['class' => 'form-group col-md-4'], 
                    'options' => ContentType::getTypeRelationRelatives(),
                ],
                [   'name'  => 'data3',
                    'label' => trans('contact.relative.label'),
                    'type'  => 'text',
                ],
            ],
        ]);
    public function fetchPerson()
    {        return $this->fetch('App\Models\ContactPerson');    }

image

The problem I have is that after saving and re-modifying, it doesn't associate the value in the Relationship field.

image

Well if you know how to solve that part then it would be repeatable.

I share the way I found to intercept in the model and save in the related table. And the way to read it and convert to json. This can be added to the documentation.

class ContactFamily extends Model
{ 
   protected $table = 'contacts';
    public $timestamps = true;
    protected $guarded = ['id'];
    protected $fillable = ['display_name', 'civil_status', 'status', 
        'relation_parent', 'relation_spouse', 'relation_children', 'relation_relative', 'relation_other'];

    public function relatives()
    {
        $keys = array_keys(ContentType::getTypeRelationRelatives());
        return $this->hasMany('App\Models\ContactRelation','contact_id', 'id')
                        ->whereIn('data2', $keys);
    }
    public function getRelationRelativeAttribute() {
        $data = self::relatives()->get();
        return $data->toJson();
    }    

    public function setRelationRelativeAttribute($value) {
        $data = (json_decode($value, true)); //converts json into array
        $keys = self::relatives()->get()->modelKeys();
        //Insertar o actualizar registros en parent
        if(is_array($data)) {
            foreach ($data as $entry) {
                if (!empty($entry['data1'])) {
                    $id = (int) $entry['id'];
                    unset($entry['id']);
                    if (($key = array_search($id, $keys)) !== false) 
                        unset($keys[$key]);  
                    self::relatives()->updateOrCreate(['id' => $id], $entry);
                }
            }
        }
        //Eliminar registros en parent
        if(!empty($keys)) {
            foreach ($keys as $id) 
                self::relatives()->find($id)->delete();
        }    
    }    

Bug

Most helpful comment

The problem with the Relationship field is resolved.
What I did was upgrade the chrome browser from version 79 to 80

If you can verify what I say, it is possible that the Relationship field is not compatible with the following versions:
chrome 79
firefox 66
internet explorer 11
Microsoft Edge 41 - EdgeHTML 16

All 17 comments

Hey @DanielKimmich

Thanks for bring this up.

I'v sent a PR #2728 to fix ajax selects, it will probably work the same way with relationships. I think we will not need all that code to make it work.

I think by tomorrow i will have a go on relationships and let you know my findings.

For now i will let this open.

@pxpm just merged your final fix for selects. Do you think you can put together a similar PR for relationship too?

On it :+1:

Hey @tabacitu i did some dig around,

Couldn't we make the function public instead of protected

https://github.com/Laravel-Backpack/CRUD/blob/400bb8827bb02fc8b6ad2d6502e3710afcb57936/src/app/Library/CrudPanel/Traits/FieldsProtectedMethods.php#L18

And add before the line:

https://github.com/Laravel-Backpack/CRUD/blob/400bb8827bb02fc8b6ad2d6502e3710afcb57936/src/resources/views/crud/fields/repeatable.blade.php#L30

$subfield = $crud->makeSureFieldHasNecessaryAttributes($subfield);

That way we could still write the fields exactly as in $crud->addField(), and expect the same guessing.

This would also work wonders for relationships, otherwise I think using relationships is a no go in repeatables, because some keys are needed beforehand like relation_type etc.

Do you see any inconvenience in this ?

Aftermath ..

You referenced that repeatable strips the name from fields so I really think that making relationships work here is also an impossiblemazing job, we parse names for html etc, and that only makes sense because we are creating the relations, need validation etc.

In this scenario everything is stored in json, or handled by developer after submission so I think making relationships work here does not make much sense at all. I remember in our conversation we talked about this, and looking at it from some perspective it clearly does not worth the effort.

I think we should focus in making only fetch_and_create work in here because of the InlineCreate feature, for other scenarios you have the select2, select2_multiple, select2_from_ajax, select2_from_ajax_multiple.

Let me know how you think we should tackle this one.

Hey @pxpm . The more I think about it, the more I realize we have no way around it. All standard fields need to work inside repeatable. Especially relationship.

What you said on the call was eye-opening. Yes, people WILL use this to bulk create other Models, even if this was not the intended purpose. Because... it鈥檚 a real need, and it will work. And since people WILL be using Relationship inside their CRUDs, we鈥檒l need to make them work inside repeatable too. Otherwise it will be frustrating for them...

Let me know what you find when trying to guess field attributes inside repeatable. Theoretically it should work perfectly (brilliant idea btw), but... you know... life is never as easy as it seems 馃槄 Totally agree that we can make that method public.

As the PR #2763 is open and I think very close to be merged, let's move any further conversation about this topic over there.

Thanks again @DanielKimmich , and sorry for making you go to the trouble of fixing this. I am very happy that you found a solution that works for you, but if the one we provided in the PR matches your expectations you could do a composer update as soon as the PR gets merged to have the latest code.

From my understanding, and what I told to @tabacitu is that relationship field in the context of a repeatable field, is only useful as a shortcut, a way to allow people write less code and have the fields displayed, because in reality we are not directly creating/editing any relation. That can be done after when you intercept the request, but does not matter if it's a select2_from_ajax or a relationship with ajax, in request you get the selected value.

Wish you the best.

Pedro

Merged! A composer update should do it for you @DanielKimmich !

After updating, the following not works.

        $this->crud->addField([    // Relationship
            'name'  => 'category_id',
            'label' => trans('blog.post.category'),
            'type'  => 'relationship',
            'tab'   => trans('blog.data'),
            'wrapper'   => ['class' => 'form-group col-md-6'],           
            'entity'    => 'category',
            'attribute' => 'name',
            'model'     => 'App\Models\BlogCategory',
            'ajax' => false,
            'inline_create' => ['entity' => 'blogcategory'],             
            ]);

The select is empty and the link new does not work.

image

see something I should change?

Hmm... I don't think you can do ajax false and InlineCreate true at the same time. Am I right @pxpm ?

Try disabling the InlineCreate - I bet the entries get populated then. If so, I recommend you

That should do it for you. Also a composer update bakpack/crud won't hurt - we're pushing bug fixes like crazy these days 馃槈

I have made the suggested changes and everything still doesn't work.
Besides, it doesn't work either.

        $this->crud->addField([
            'name'  => 'name_first',
            'label' => trans('contact.name.first'),
            'type'  => 'text',
            'tab'   => trans('contact.name.tab'),
            'attributes' => ['id' => 'name_first'],
            'wrapper'   => ['class' => 'form-group col-md-6'], //resizing
            'entity'    => 'names', 
            'auto_focus' => 'true',
            ]);

    public function names()
    {        return $this->hasOne('App\Models\ContactName','contact_id','id');    }

Apparently it is something related to the entity attribute.
Cheers,

That's odd @DanielKimmich . I've just triple-checked after merging https://github.com/Laravel-Backpack/CRUD/pull/2777 - relationship worked well inside repeatable for me, including the InlineCreate. It also works in the beta online demo.

So I don't know what the problem can be for you. Maybe after a composer update backpack/crud some of the fixes we've pushed will do it for you too? Any JS errors in the console? Is the request response fine? There's not a lot to go on to debug this.

In an hasOne relation you just need to use $this->crud->addField('relation.field_in_relation') it will create a text field, setup type if you need different one.

Also check in demo how we handle HasOne Relations.

https://github.com/Laravel-Backpack/demo/blob/9e697cd755e0b1d55f1c57637be80da38dc35f91/app/Http/Controllers/Admin/MonsterCrudController.php#L777

Thank you can solve the relationship HasOne Relations.

But I continue with the problem with the Relationship field
I have tried using the backpack demo and I have the same problem
image

Update the framawork from 6 to 7.
Replace the package.
php artisan vendor: publish --provider = "Backpack \ CRUD \ BackpackServiceProvider" --tag = public --force
Try multiple browsers.

I can't think what to do anymore. Do you have any more ideas?

PHP VERSION:

PHP 7.2.11 (cli) (built: Oct 10 2018 02:04:07) ( ZTS MSVC15 (Visual C++ 2017) x64 )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies

LARAVEL VERSION:

v7.10.3@6e927e78aafd578d59c99608e7f0e23a5f7bfc5a

BACKPACK VERSION:

4.1.2@7084182b38bff6b19624788ff143bb249ecdc758

Thank you can solve the relationship HasOne Relations.

But I continue with the problem with the Relationship field
I have tried using the backpack demo and I have the same problem
image

Update the framawork from 6 to 7.

Replace the package.
php artisan vendor: publish --provider = "Backpack \ CRUD \ BackpackServiceProvider" --tag = public --force

Clear cache
php artisan cache:clear
php artisan view:clear
php artisan route:clear
php artisan config:clear
php artisan clear-compiled

Try multiple browsers.

I can't think what to do anymore. Do you have any more ideas?

PHP VERSION:

PHP 7.2.11 (cli) (built: Oct 10 2018 02:04:07) ( ZTS MSVC15 (Visual C++ 2017) x64 )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies

LARAVEL VERSION:

v7.10.3@6e927e78aafd578d59c99608e7f0e23a5f7bfc5a

BACKPACK VERSION:

4.1.2@7084182b38bff6b19624788ff143bb249ecdc758

Hmm if you're talking about this:

        $this->crud->addField([    // Relationship
            'name'  => 'category_id',
            'label' => trans('blog.post.category'),
            'type'  => 'relationship',
            'tab'   => trans('blog.data'),
            'wrapper'   => ['class' => 'form-group col-md-6'],           
            'entity'    => 'category',
            'attribute' => 'name',
            'model'     => 'App\Models\BlogCategory',
            'ajax' => false,
            'inline_create' => ['entity' => 'blogcategory'],             
            ]);

Then I just noticed your name is not right. The name of the relationship field should be the name of the relationship method in the model. So in this case category, not category_id.

The problem with the Relationship field is resolved.
What I did was upgrade the chrome browser from version 79 to 80

If you can verify what I say, it is possible that the Relationship field is not compatible with the following versions:
chrome 79
firefox 66
internet explorer 11
Microsoft Edge 41 - EdgeHTML 16

Ugh that's nasty. Sorry you had to go through all this trouble @DanielKimmich !

Was this page helpful?
0 / 5 - 0 ratings