Closed Jam0r85 closed 5 years ago
You can do this by setting a default attribute to your model, but yeah I think there should be a way to pass a value to the fields.
This would be especially useful for the code field. Being able to provide placeholder JSON data into a field by default would allow for more context on how that field can be filled appropriately, rather than being constricted to having it filled with "null" as it currently does.
@mink Currently I hide my code field's when creating a record and use a model observer to input the default json values. Not the best solution but it does the job.
I've found that if you set the default attribute on a model (as @chinleung mentioned) as an array, it will fill a JSON code field on the new resource view. If you set the default value as a string, any code field that is not declared as JSON will be filled in with the specified value too.
Other fields that I've tested such as the Text field will accept various types as a default value to fill in the field.
This would be great to have in the documentation. It is personally enough of a solution for my usage, however, being able to set default values within the resource class would be useful as well.
Edit: If you override a model's constructor you can programmatically declare the default attribute values, which you could use to pull in config data for instance. If you require different default values for the model specifically in Nova you could assign the values this way as well.
Is there a way to do this for an action field? I have an action field asking me to input something, it would be great if it would fill a field for me with a default data.
Something like:
Text::make('Field')->defaultValue('a-value');
Would be great to be able to default let's say a BelongsTo::make('User')
with the currently authenticated user.
Something is known, how can I set a default value?
As per what @mink suggested, default values for json (code) fields can be achieved by setting the value to the attribute in the model's constructor
This works for me:
protected $casts = [
'fields' => 'array',
];
public function __construct(array $attributes = [])
{
$this->fields = config('app.default_fields');
parent::__construct($attributes);
}
I do however also have this field on a pivot... and haven't found a way to specify a default for that... the best way would probably indeed by a defaultValue
method on Nova fields. I am toying with pivot classes but as of yet have had no success, I've also tried using resolveUsing
but so far no luck
@MadMikeyB You can achieve set the authenticated user by default for the BelongsTo::make('User') field like this:
public function __construct(array $attributes = [])
{
if (! isset($attributes['user_id']) && auth()->check()) {
$attributes['user_id'] = auth()->user()->id;
}
parent::__construct($attributes);
}
Yeah but this seems like a hacky way to do it. Taylor explicitly said "Nova doesn't interact with your code, it doesn't even touch your code at all". I don't want to make adjustments to my code, especially overriding a constructor of a model, just so I can set default value in Nova. IMHO, this should be resolved, especially since this doesn't feel like a hard bug to fix, since there is a value
property on the Field (or Element, not sure) class.
Until then, I'm fine with overriding certain methods in Nova resources, or extending the base Resource class or something, but I'm not fine with modifying my models, especially setting default attributes with some hardcoded values.
Your point is valid, I was already setting this default in the creating block, for other code paths, it was just a case of making it happen earlier so it applies to an unsaved model e.g. the nova create forms — nova should have specific defaultValue handling also, so that changes aren’t necessary, and for when the defaults need to be different for the admin On Thu, 30 Aug 2018 at 15:08, Josip Crnković notifications@github.com wrote:
Yeah but this seems like a hacky way to do it. Taylor explicitly said "Nova doesn't interact with your code, it doesn't even touch your code at all". I don't want to make adjustments to my code, especially overriding a constructor of a model, just so I can set default value in Nova. IMHO, this should be resolved, especially since this doesn't feel like a hard bug to fix, since there is a value property on the Field (or Element, not sure) class.
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/laravel/nova-issues/issues/58#issuecomment-417313187, or mute the thread https://github.com/notifications/unsubscribe-auth/AARq-8eBkVN_UDfIbPkg18KuZbB1-8xnks5uV-PlgaJpZM4WJ-2I .
This repository is for tracking bugs. Feature requests may be emailed to Nova customer support.
Add the following to your resource file
/**
* Get a fresh instance of the model represented by the resource.
*
* @return mixed
*/
public static function newModel()
{
$model = static::$model;
$var = new $model;
$var->attributeForDefaultValue = defaultValue;
return $var;
}
This is how you set default values. Will work most of the times except when your field is a number and you want to set 0 as default then it wouldn't work.
Text::make("Your Field")
->withMeta(["value" => "Some Value"])
How to specify meta tag only while creating a new value and not for all. Right now it ignores its own values and displays this for all the records.
@sonalmahajan01 You can do this to have it only populate the default value if the item doesn't have a value for that field already:
Text::make("Name")->withMeta($this->name ? [] : ["value" => "John Smith"])
Because of new PHP syntax, it can be even easier.
Text::make("Name")->withMeta(['value' => $this->name ?? 'Default']);
Makes use of the Null Coalescing Operator.
@Jam0r85 I have managed to set a default value (current user's ID) on a BelongsTo field this way:
BelongsTo::make('User')
->withMeta([
'value' => $this->user_id ?? auth()->user()->id,
'belongsToId' => $this->user_id ?? auth()->user()->id
])
->rules('required'),
@peterhaluska small note on your solution. It works great for Create/Edit. However on Index/Details pages it causes the BelongTo value to be the ID instead.
I got around by adding two BelongsTo. The original BelongTo with ->hideWhenCreating()->hideWhenUpdating()
attached. And then adding ->hideFromIndex()->hideFromDetail()
to your BelongsTo with default value.
BelongsTo::make('Author', 'user', 'App\Nova\User')->withMeta([
'value' => $this->user_id ?? auth()->user()->id,
'belongsToId' => $this->user_id ?? auth()->user()->id
])->hideFromIndex()->hideFromDetail()
BelongsTo::make('Author', 'user', 'App\Nova\User')->hideWhenCreating()->hideWhenUpdating()
You should use this package: Nova Hidden Fields also you can set default value for your hidden fields such as current user_id and much more..
If you’re using the auth user for the id, don’t pass it via hidden fields. Use observers. Creating and updating events can access the auth user
@peterhaluska great solution, you saved me lots of time!!
@nickpoulos there is no need to make two BelongsTo. I am only using the 'belongsToId' and removed the 'value', it works great like that.
BelongsTo::make('User')
->withMeta([
'belongsToId' => $this->user_id ?? auth()->user()->id
]);
Unfortunately using the withMeta function doesn't appear to work in combination displayUsingLabels() when using a select field. Does anyone have a solution for this situation?
Select::make('Rate')
->options('work_rates' => [
'1' => 'Standard',
'2' => 'Priority',
])
->withMeta(['value' => '1'])
->displayUsingLabels()
@devonmather You are not passing the options correctly. It should be:
Select::make('Rate')
->options([
'1' => 'Standard',
'2' => 'Priority',
])
->withMeta(['value' => '1'])
->displayUsingLabels()
Then the value Standard is selected by default.
@chinleung Thanks for pointing out the syntax error I had in the arguments. However, that wasn't the issue. The issue is on the detail and index where the number '1' shows in place of the text 'Standard'.
Please see screenshots.
I have since solved the issue by using the model's attributes.
It seems the withMeta functionality for setting defaults could be flawed in that it will always set that value for any page, not just the create form. It also does not respect the displayUsingLabels() function.
you can use fillUsing
callback and in relation use filled
callback like this:
public function fields(Request $request)
{
return [
ID::make()->sortable(),
ColorField::make('hex')->sortable()->fillUsing(function(NovaRequest $request, $model) {
if(! isset($model->hex)){
$model->hex = '#000000';
}
}),
BelongsTo::make('user', 'owner')->nullable()->filled(
function(NovaRequest $request, $model) {
if(is_null($model->owner_id)) {
$model->owner_id = $request->user()->id;
}
}
),
];
}
+1
Hey, could anybody resolve the issue of @devonmather ? I got the same problem while using the withMeta function. The default value is set in detail view but also everywhere else in index view. So when a user changes the default value while creating a resource, the value is stored correctly in the database, but the default value is shown on index view of all created resources instead of the changed value which is stored in database.
I'm looking to solve for this issue too. However, I'm working with Actions, rather than Models. I'm wanting to create a checkbox that is checked by default.
I'm looking to solve for this issue too. However, I'm working with Actions, rather than Models. I'm wanting to create a checkbox that is checked by default.
->withMeta(['value' => true])
I've been running into so many issues like this with Nova. I love Nova because it helps us rapidly develop a standardized admin panels - but issues like this are such a show stopper and you have no idea when it will be fixed/added. I feel like I'm battling with Nova a lot of times.
I've just published a package which wraps this default behaviour in some convenience methods, including caching previous values. Hope this is useful! https://novapackages.com/packages/inspheric/nova-defaultable
@LukasRothZeitraum, @devonmather
I've come up with a solution that works for me, and it seems to solve this problem. It also accounts for the issue that @crnkovic pointed out, and thus my solution doesn't require changing anything outside of Nova.
The problem that you guys were seeing is that using the withMeta
approach replaces the value returned to the client, even if a value was already present (which is certainly the case for existing models).
Additionally, I'm dealing with a field that uses a resolve callback, which the value provided in withMeta
has already handled, so if you override that component, any effect that your callback would have isn't performed (in my case, I'm working with a "percent" field, which is a number field that shows "35" to represent "0.35" in the database. I'd have to use "100" for the withMeta
approach, instead of the desired value of "1").
The solution lies with provide default attributes to the model, but doing it within the Nova codebase. This is similar to solution @idragon81 posted, but more abstract.
In my base resource class, I've added the following methods:
/**
* Creates and returns a fresh instance of the model represented by the resource.
*
* @return mixed
*/
public static function newModel()
{
$model = static::$model;
$instance = new $model;
$instance->setRawAttributes(static::getDefaultAttributes());
return $instance;
}
/**
* Returns the default attributes for new model instances.
*
* @return array
*/
public static function getDefaultAttributes()
{
return static::$defaultAttributes ?? [];
}
This allows me to provide either a defaultAttributes
static attribute on the resource, or I can override the getDefaultAttributes
method on the implementing resource (which is useful if I needed to make function calls instead of providing constants).
Now in my specific resource, I've added the following attribute:
/**
* The default attributes for new model instances.
*
* @var array
*/
public static $defaultAttributes = [
'percent' => 1
];
Doing this will send my "1" through my resolve callback, and converting it to "100" (similar to how "0.35" would have been changed to "35", had "0.35" been the value stored in the database). If the model is instead retrieved from the database, then it will replace my default value (even if the stored value is null
, null
would be used for the "percent" attribute rather than "1").
Hopefully this helps.
I don't know if this is the Laravel way of doing things, but I just returned the default value within the resolve callback. However, I tried the same thing for relationships and it threw an error.
Boolean::make('My Boolean', 'working', function () {
return true;
})
Date::make('My Default Date', 'date', function () {
return now();
})
For anyone interested I made this macro which seems to do the trick:
In NovaServiceProvider:
public function boot()
{
Field::macro('default', function ($default) {
return $this->resolveUsing(function ($value) use ($default) {
return $value ?? $default;
});
});
parent::boot();
}
Use it like:
Text::make('Name')
->sortable()
->rules('required', 'max:255')
->default('John Doe'),
@rasmuscnielsen Excellent thanks a lot ! I've juste updated a bit your solution. In some cases, I needed a default value only when creating, but user can empty the field.
In NovaServiceProvider :
public function boot()
{
Field::macro('default', function ($default) {
return $this->resolveUsing(function ($value, $model) use ($default) {
return $model->getKey() === null ? $default : $value;
});
});
parent::boot();
}
And the usage stay the same when creating the field.
As i'm also using, NovaFlexibleContent
package, i've added :
public function getKey()
{
return $this->inUseKey();
}
In my layouts in order to have them working like expected.
@rasmuscnielsen and @intraordinaire when defining a macro like that I get
"Using $this when not in object context",…}
at $this->resolveUsing
Any ideas what I am missing?
@intraordinaire Excelent, but i dont understand where you put and how to use in contenflexible public function getKey() { return $this->inUseKey(); }
@mpoma i have a BaseLayout
class, all my flexibles extend this class.
Just an example, but you can put that on every class that extend the Layout
class from the FlexibleContent package, or implementing your own solution if necessary.
use Whitecube\NovaFlexibleContent\Layouts\Layout;
class BaseLayout extends Layout
{
/**
* Return the layout identifier
*
* @return null|string
*/
public function getKey()
{
return $this->inUseKey();
}
}
@ajthinking Not sure what can be the problem here. Are you well in the NovaServiceProvider
, is Field
the good Laravel Nova class (use Laravel\Nova\Fields\Field;
), can you dump $this
?
Just for completeness, setting the default value via the 'value' attribute and withMeta()
method not only override existing values (including in lists), but also prevent the value to be changed in the form, even if a different value was manually entered.
The correct answer is indeed from https://github.com/laravel/nova-issues/issues/58#issuecomment-419691484 (and https://github.com/laravel/nova-issues/issues/58#issuecomment-533821333) : set the default values directly on the model attributes.
I personally do it in the fields()
methods of the Nova resource, when the model exists
property is false
meaning that we are on the creation form.
As per what @mink suggested, default values for json (code) fields can be achieved by setting the value to the attribute in the model's constructor
- if you add the value in attributes static it'd have to be a json string given laravel/nova tries to json decode it because of the cast
- if you add it in creating, that's too late
This works for me:
protected $casts = [ 'fields' => 'array', ]; public function __construct(array $attributes = []) { $this->fields = config('app.default_fields'); parent::__construct($attributes); }
I do however also have this field on a pivot... and haven't found a way to specify a default for that... the best way would probably indeed by a
defaultValue
method on Nova fields. I am toying with pivot classes but as of yet have had no success, I've also tried usingresolveUsing
but so far no luck
did you ever figure out a way to set default values on pivot fields? i've looked up and down with no luck
How would default value be handled for hasMany?
For example on User Detail page, I click 'add book', but on the book creation form i want school_id of Book to be prefilled with that User's school_id
@ziming
How would default value be handled for hasMany?
For example on User Detail page, I click 'add book', but on the book creation form i want school_id of Book to be prefilled with that User's school_id
I have tried something similar to your situation, in the default callback function I want to use another relation of the current model to find the ID to use as default value, but seems not to work, the callback is not even called?
What I tried was something like this (in the Book fields):
BelongsTo::make('School')->default(function () {
return $this->user->school->id;
})
So that when I create a new book from the User page, where the user ID is already fixed, it should be able to also assign the default school ID.
But since it doesn't seem to work, what would be the correct way of using default to achieve this?
It seems like the callback is simply not executed for BelongsTo fields? This works:
BelongsTo::make('School')->default(1)
This works (like in the examples):
Text::make('School')->default(function () {
return 'Saturn';
}),
But then this does nothing:
BelongsTo::make('School')->default(function () {
return 1;
}),
Another problem seems to be that at the moment of assigning the default value, the user relation is not known yet (even though we create the Book from the User resource page, and the dropdown on the Book create page is greyed out with the correct value).
This means that when I try to do it like this:
BelongsTo::make('School')->default($this->user->school->id)
I get Trying to get property 'school' of non-object
So maybe using default for this is not even possible?
Unfortunately using the withMeta function doesn't appear to work in combination displayUsingLabels() when using a select field. Does anyone have a solution for this situation?
Select::make('Rate') ->options('work_rates' => [ '1' => 'Standard', '2' => 'Priority', ]) ->withMeta(['value' => '1']) ->displayUsingLabels()
Have you solved this problem? Right now, I also can't solve the problem of displaying labels when default values are set for a field
Select::make('Тип', 'type')
->options(\App\Cost::TYPE)
->sortable()
->withMeta([
'value' => $this->type ?? 'expense' // default value for the select
])
Easier, for the date field asked:
Date::make('Upload date', 'uploadDate', function ($value) {
if ($value){
return $value;
}else{
return now();
}
})
Wow this super cool soap opera is like the longest ever explanation of how to set defaults for Nova! For those still struggling with Select
and the initial default value and displayUsingLabels
because you're using ENUMs and you have nice friendly names for example Lead Statuses, that point to sensible lower case defaults in your database, e.g.:
'proposal_sent' => 'Proposal Sent'
The key is don't use withMeta
but rather resolveUsing
as in the example below:
Select::make('Status')->options(
Leads::ui_options()
)
->sortable()
->resolveUsing(function () {
return $this->status ?? 'new';
})
->displayUsingLabels(),
Compliments of this Stack post.
This is how to set a default value on create only for a DateTime field:
DateTime::make('When')
->withMeta(['value' => $this->when ?? Carbon::now()->toDateTimeString()])
->rules('required')
->hideFromIndex()
->hideFromDetail(),
DateTime::make('When')
->sortable()
->hideWhenCreating()
->hideWhenUpdating()
Inspired by https://vander.host/knowledgebase/software-development/how-to-set-the-default-date-using-laravel-nova/
I met this issue today, should use this instead of the default
or withMeta
, from: https://github.com/laravel/nova-issues/issues/493#issuecomment-419735037
use Illuminate\Database\Eloquent\Model;
class Booking extends Model
{
protected $attributes = [
'status' => 'pending',
'price' => 0,
'commission' => 0,
];
}
Wow this super cool soap opera is like the longest ever explanation of how to set defaults for Nova! For those still struggling with
Select
and the initial default value anddisplayUsingLabels
because you're using ENUMs and you have nice friendly names for example Lead Statuses, that point to sensible lower case defaults in your database, e.g.:
'proposal_sent' => 'Proposal Sent'
The key is don't use
withMeta
but ratherresolveUsing
as in the example below:Select::make('Status')->options( Leads::ui_options() ) ->sortable() ->resolveUsing(function () { return $this->status ?? 'new'; }) ->displayUsingLabels(),
Compliments of this Stack post.
it's work, tnx
Not sure if i've missed this from the docs but is there anyway to populate a field in a create form with a default value?
eg.
This would be helpful with relationship fields also, especially with BelongsTo (example of using Spark with it's current_team_id column in the users table.
Would help reduce bits and pieces being added to model observers checking for missing values and populating them etc