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

Access models within fields function in Nova Actions #1029

Closed
ack202 opened this issue Nov 26, 2018 · 23 comments
Closed

Access models within fields function in Nova Actions #1029

ack202 opened this issue Nov 26, 2018 · 23 comments

Comments

@ack202
Copy link

ack202 commented Nov 26, 2018

Hey guys,

I am sending the models within an action to some webservice. The results should be displayed in a select field where the user can choose a suitable option for him.
Is there a way to access the models within the fields function?

Thanks

@davidhemphill
Copy link
Contributor

This is out of the scope for actions, but you could probably accomplish by redirecting from the action to your own tool which would do the ajax call and let you finish out the action.

@thiskbj
Copy link

thiskbj commented Jul 8, 2019

+1, I'd like this ability as well.

@henryavila
Copy link

henryavila commented Jul 26, 2019

@davidhemphill, access the model from fields methods is not out of scope. In some situations, it's very importante. See this example (my case)

  • I have Company and Sector (sector belongs to Company).
  • I wanna to import employess from xls file.
  • To the user don't have to define the the sector id in xls file, I will import employees per company and sector.
  • The action run in company Detail
  • For a best user experience, the user should:
  • Click action
  • Choose one sector
  • Choose file
  • Click upload.

But to choose one sector (that belongs to company) I must pass some data to Fields function (company or sectors).

I know I can attach this action in sector, but after each import, the user will have to back to company page, scroll down to sector, open a new sector detail page and click in action again.

If I could get the Company model from fields method in action, I could show a select with just the sector of the company, and this will be a better experience to the user (click action, choose sector, choose file, click upload. To import new users, justs: click action, chooose new sector, choose file, upload).

I know I can build a ResourceTool for this, but this shold be covered by action, because that's the reason actions exists.

Please, allow access the model (id or object) from fields method.

@m-lotze
Copy link

m-lotze commented Aug 2, 2019

I would also like to see this. One approach might be to allow the fields() method to return a callback, which receives the collection of models as an argument and returns an array of fields. If a callback is returned from fields(), Nova makes an ajax request with the selected models and executes the callback before rendering the fields.

@Dontorpedo
Copy link

while i am sending mails from a action, i am not able to prefill the receiver of the mail with model data..

accessing models in action fields would be super

@BrunoRB
Copy link

BrunoRB commented Oct 22, 2019

For single model actions (onlyOnDetail()) this can be accomplished accessing request()->resourceId. Ex:

    public function fields()
    {
        // assuming your action is only used for one entity of a specific type
        $modelObj = MyModel::find(request()->resourceId);
        ...

@henryavila
Copy link

henryavila commented Oct 24, 2019

@BrunoRB, I tryed request()->resourceId and it works fine when displaying the Action. But when I run the action (will run the validation), the code request()->resourceId found nothing and break the code.

My workarround is:

public function fields() {

       if (empty(request()->resourceId)) {
            $options = [];
        } else {
            $company = Company::findOrFail(request()->resourceId);
            $options = $company->sectors->pluck('name', 'id');
        }

      ...

    return [
        Select::make('Sector')
                ->options($options)
                ->rules('required'),

         ...
    ];

}

This way, when I run the action, i don't care about the optionValues.
It works, but there must be a better way to do this.

@vincenzoraco
Copy link

I believe resourceId has been replaced by viaResourceId as it is not available on the request()

@lifeblood
Copy link

Same here, Otherwise, the action is tasteless

@tititorn
Copy link

It would be good that we can pass model to fields in Nova Action

@tititorn
Copy link

I believe resourceId has been replaced by viaResourceId as it is not available on the request()

Both request()->resourceId and request()->viaResourceId return null

any suggestion?

@tanaticreative
Copy link

tanaticreative commented May 6, 2020

@tititorn You can use
$resourceId = $request->resources ? $request->resources : $request->resourceId;.
Once again, I am convinced of the poor usability of Nova. Basic things are not implemented. And you have to dig into the Nova code to add normal functionality

@ClaraLeigh
Copy link

I needed something similar, not quite the same, for changing the currency and locale of a field based on the store information.

this was what I did.
Created: App\Nova\Resource\DisplayCallbackTrait.php

<?php
namespace App\Nova\Resource;

trait DisplayCallbackTrait
{
    public function resolveForDisplay($resource, $attribute = null)
    {
        if (!empty($this->beforeDisplayCallback)) {
            call_user_func($this->beforeDisplayCallback, $this, $resource);
        }

        parent::resolveForDisplay($resource, $attribute);

        return $this->value = e($this->value);
    }

    protected $beforeDisplayCallback = null;
    public function beforeDisplayCallback(callable $function)
    {
        $this->beforeDisplayCallback = $function;

        return $this;
    }
}

Then I used an extended currency field: App\Nova\Resource\Currency.php

<?php
namespace App\Nova\Resource;

class Currency extends \Laravel\Nova\Fields\Currency
{
    use DisplayCallbackTrait;
}

Then I can do this:

Currency::make(__('Payment Amount'), 'total')
                ->beforeDisplayCallback(function ($field, $model) {
                    $field
                        ->currency($model->store->currency)
                        ->locale($model->store->locale);
                })

You could adapt this for other methods too, just have a read through the code to find where you need to insert it in.

Tbh, I think the best way to resolve this on nova's end is to add a bunch more callbacks to allow for this sort of use case as I see it being fairly frequently used; at least for me.

@ljmoleiro
Copy link

For me works like this

https://stackoverflow.com/questions/56535376/run-where-get-on-nova-action-fields/63913601#63913601

@f-liva
Copy link

f-liva commented Oct 9, 2020

Why is this issue closed when there are many people who need it?

@coclav
Copy link

coclav commented Oct 15, 2020

Made it work inspired by the stack overflow link above (thanks @ljmoleiro )

// Resource

public function actions(Request $request)
    {
        return [
            (new ManageFields($request->resourceId))->onlyOnDetail()
        ];
    }

// Action ManageFields

protected $model;

    public function __construct($model = null)
    {
        $this->model = $model;
    }

public function fields() {
        if ( $this->model) {

            $user = User::find($this->model);
            if ( $user) {

                return [
                    Text::make("User Name" 'name')->default(  $user->name),
                ]
            }
      }
     return [];
}

@f-liva
Copy link

f-liva commented Oct 15, 2020

Yes it's a great solution, thanks!

@bastinald
Copy link

Made it work inspired by the stack overflow link above (thanks @ljmoleiro )

// Resource

public function actions(Request $request)
    {
        return [
            (new ManageFields($request->resourceId))->onlyOnDetail()
        ];
    }

// Action ManageFields

protected $model;

    public function __construct($model = null)
    {
        $this->model = $model;
    }

public function fields() {
        if ( $this->model) {

            $user = User::find($this->model);
            if ( $user) {

                return [
                    Text::make("User Name" 'name')->default(  $user->name),
                ]
            }
      }
     return [];
}

this solution does not work for bulk acitons, where we could use whereIn etc. in a Select fields options, for example.

@blackfyre
Copy link

This issue definitely should be re-opened.
As Nova applications get more complex, the requirements against it will as well.

@gemanzo
Copy link

gemanzo commented Jun 14, 2023

Hello all, during this time has anyone maybe found a solution to this?

@ghost
Copy link

ghost commented Jun 14, 2023

Hello all, during this time has anyone maybe found a solution to this?

This might come handy... https://github.com/tunezilla/nova-dynamic-action-fields

@chimit
Copy link

chimit commented Jun 20, 2023

@davidhemphill @crynobone this needs to be reopened.

@laravel laravel locked and limited conversation to collaborators Jun 20, 2023
@crynobone
Copy link
Member

We never open old issues, more so if the issue is related to a version no longer supported by Nova. You can start new discussion or question

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests