laravel / nova-issues

556 stars 34 forks source link

Access models within fields function in Nova Actions #1029

Closed ack202 closed 5 years ago

ack202 commented 5 years ago

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 commented 5 years ago

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 commented 5 years ago

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

henryavila commented 5 years ago

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

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 commented 5 years ago

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 commented 5 years ago

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 commented 5 years ago

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 commented 5 years ago

@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 commented 4 years ago

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

xerox-xeon commented 4 years ago

Same here, Otherwise, the action is tasteless

tititorn commented 4 years ago

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

tititorn commented 4 years ago

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 commented 4 years ago

@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 commented 4 years ago

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 commented 4 years ago

For me works like this

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

f-liva commented 4 years ago

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

coclav commented 4 years ago

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 commented 4 years ago

Yes it's a great solution, thanks!

bastinald commented 3 years ago

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 commented 3 years ago

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

gemanzo commented 1 year ago

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

ghost commented 1 year ago

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 commented 1 year ago

@davidhemphill @crynobone this needs to be reopened.

crynobone commented 1 year ago

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