I am submitting an array of inputs to my controller like so:
<input id="box-1-nickname" name="box-nickname[]" class="form-control" type="text" placeholder="Required">
<input id="box-2-nickname" name="box-nickname[]" class="form-control" type="text" placeholder="Required">
I am doing some validation like this:
$validator = Validator::make(Input::all(), array(
'supplies-count' => 'required|in:0,1,2,3,4',
));
$arrayValidator = Validator::make(Input::all(), []);
$arrayValidator->each('box-nickname', ['required|min:1|max:60']);
if( $validator->fails() || $arrayValidator->fails() ) {
return Redirect::route('route-2')
->withErrors($arrayValidator)
->withInput();
}
The problem is when I try to check the errors like this it doesn't work:
if( $errors->has('box-1-nickname') ) { echo ' has-error'; }
Displaying input array errors in the view (L5.8 onwards)
To get the first validation error for an input array:
{{ $errors->first('input_array.*') }}
To check if there is an error within an input array:
#if($errors->has('input_array.*'))
<h1>There is an error in your input array</h1>
<ul>
#foreach($errors->get('input_array.*') as $errors)
#foreach($errors as $error)
<li>{{ $error }}</li>
#endforeach
#endforeach
</ul>
#endif
Other examples:
#error('input_array.*')
<div class="alert alert-danger">{{ $message }}</div>
#enderror
From 5.8^ documentation
Working with error messages
If you are validating an array form field, you may retrieve all of the messages for each of the array elements using the * character:
foreach ($errors->get('attachments.*') as $message) {
//
}
Hope it helps!
You've probably long found a solution, but for anyone else who stumbles across this:
The validator uses array dot notation of the field array keys. For example box-nickname[0] becomes box-nickname.0
Therefore if( $messages->has('box-nickname.0') ) { echo ' has-error'; } should give you your desired result. However, you will need to dynamically generate the array key since as you've said, you won't know how many box-nicknames are being applied. I use this in my form view:
#if(!is_null(Input::old('box-nickname')))
#foreach(Input::old('box-nickname') as $n => $box-nickname)
#include('box-nickname-create-form-partial')
#endforeach
#endif
Then create a partial view called "box-nickname-create-form-partial.blade.php" or whatever you want to call it with the form field, which might look something like this:
<div class="form-group {!! $errors->has('box-nickname.'.$n) ? ' has-error' : '' !!}">
<input name="box-nickname[{{$n}}]" class="form-control" type="text" placeholder="Required">
</div>
I hope that's helpful.
The errors are collected by name property, not id, and Laravel's default MessageBag variable is $messages, not $errors:
if( $messages->has('box-nickname') ) { echo ' has-error'; }
http://laravel.com/docs/4.2/validation#working-with-error-messages
$errors is correct, but you should be checking for box-nickname. As you can see you will run into the issue of not being able to identify what box is what because of the generic name. I think the easiest way to to give each input a unique name (eg. box-1, box-2)and do a for loop on the server side to retrieve inputs that start with box-.
Related
Firstly I can say that after search I dont find any solution about this. I do validation array like this post: laravel validation array
I need validate each size array position. I write this validation code:
// Fields validation
$request->validate([
'name' => 'required|max:150',
'theySay' => 'nullable|array',
'theySay.*' => 'string|max:1000',
'theyDontSay' => 'nullable|array',
'theyDontSay.*' => 'string|max:1000',
]
Where theySay and theyDontSay are both array of strings. In migration I have both fields (text) like strings of 1000 characters.
$table->string('text', 1000);
And validation works correctly. I mean, if put a text greater than 1000 chars I cannot save but..dont show any error message.
I want the error message to be shown in the input just like the rest of the fields.
What am I doing wrong?
Best regards
'YOUR_FIELD' => '...|...|max:1000| ...'
Look at the Laravel validation docs for more information
Please put below code in your blade file for show any error message.
#if ($errors->any())
<div class="alert alert-danger">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
Quoting laravel documentation:
Likewise, you may use the * character when specifying your validation messages in your language files, making it a breeze to use a single validation message for array based fields:
'custom' => ['person.*.email' => ['unique' => 'Each person must have a unique e-mail address']]
It seems it does not work. I have a validation message:
'infos.*.*.*' => ['required' => 'My text']
Then I have some inputs in my view:
<input type="text" name="infos[1234][0][name]">
<input type="text" name="infos[1234][1][name]">
<input type="text" name="infos[5678][0][name]">
And in my controller I validate the input:
$this->validate($request, [
'infos.*.*.*' => 'required'
]);
And in view I have a error displayer:
#if (count($errors) > 0)
<strong>Oops. Errors:</strong>
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
#endif
And if I leave all input empty I got:
My text
My text
My text
My text
My text
etc.
What's wrong with my code? Reading Laravel documentation I though it should have worked (I mean: it should have been displayed only once). Did I misunderstood something?
This is working as intended. Since you're passing multiple inputs in an array, the validation throws an error for each item. Therefore 3 inputs with 2 causing errors and 1 passing would obviously pass error for 2 inputs. So in your case the multiple errors are due to multiple inputs failing validation.
I want to use form model binding in Laravel. The following (simplified) example works fine:
{{ Form::model($user, array('class'=>'form-horizontal')) }}
{{ Form::token() }}
{{ Form::label('email', 'Email Address') }}
{{ Form::text('email') }}
{{ Form::close() }}
However, I want to use arrays in the name attributes, as is pretty standard nowadays. In other words, have user[email] as the field name, so that I get all the form elements in one array in the backend.
Is this possible with model binding? When I use {{ Form::text('user[email]') }} the email does not get filled in. I tried adding array('user'=>$user) in the Form::model function in case it needed a nested value, but no luck.
Form::model(array('user' => $user)) is the correct solution, BUT unfortunately the implementation of form model binding is pretty bad as it does not easily work on a nested, mixed set of arrays and objects. See https://github.com/laravel/framework/pull/5074
You could try Form::model(array('user' => $user->toArray())) or Form::model((object) array('user' => $user)).
You could do something like this assuming that you would have a single $user and multiple $types
Form::macro('userTypes', function($user,$types)
{
foreach ($types as $type) {
$concat = $user . "_" . $type;
return '<input type="{$type}" name="{$concat}">';
}
});
And customize the output with your form style, even adding more complexity to the function might be required.
And then simply calling it for example
$user = "johndoe";
$types = array("email","text");
Form::userTypes($user,$types);
That would result in
<input type="email" name="johndoe_email">
<input type="text" name="johndoe_phone">
If you want to do it in a single line and assuming that you would have a single $user and a single$type you could do something like
Form::macro('userType', function($user,$type)
{
return '<input type="{$type}" name="{$user[$type]}">';
});
And with the call
$user = [ "mail" => "some_mail_value" ];
Form::userType($user,"mail");
Would result in
<input type="mail" name="some_mail_value">
Or perhaps you'd like something that would work with a single $user key-value array as :
Form::macro('userType', function($user)
{
$keys = array_keys($user);
foreach ($keys as $key => $value) {
return '<input type="{$key}" name="{$value}">';
}
});
And with the call
$user = ["mail" => "mail_value" , "text" => "text_value"];
Form::userType($user);
That would result in
<input type="mail" name="mail_value">
<input type="text" name="text_value">
And finally I didn't find a direct way to do it with default form model binding, as It requires the field name to be the same as the model attribute, but you could do a workaround as
Form::macro('customBind', function($user_model,$type)
{
return '<input type={$type} name="user[{$type}]" value="{$user_model->$type}">';
});
And then
$user = new User();
$user->email = "johndoe#gmail.com";
Form::customBind($user,"email");
Which would produce something like
<input type="email" name="user[email]" value="johndoe#gmail.com">
The takeaway point is that basically the solution to your problem is creating a Macro, I have provided some workarounds on this but you will need to refine this to your specific needs.
Is there any utility function in Laravel that allows you to give an alternative value for a specific input field if the old value is empty? Currently I have the following code:
<input type="text" class="form-control" id="title" name="title" value="{{ (!empty(Input::old('title'))) ? Input::old('title') : 'hey' }}">
But its not really that pretty. Any ideas?
use
Input::old('title', 'fallback value')
Yes! Don't use the input tag :)
If you use {{ Form you will get this, and much, much more!
{{ Form::text('email', null, array('class'=>'form-control', 'placeholder'=>'Email Address')) }}
Check out the docs here (http://laravel.com/docs/html & http://laravel.com/docs/requests) and you will notice that when the input is flashed to the session, this input box rendered by blade will automatically replace that "null" (the second parameter) with the flashed value from the session.
This removes the need to check for the old input or have any nasty if/else checks inside your template. Also, you no longer need to worry about any HTML code injections or XSS happening, because Form::text will ensure that the text is correctly converted to their HTML entities.
Where you are checking for errors, you should use a Laravel validator. Something similar to this:
protected function createUser(){
$rules = array(
'email'=>'required|email',
'password'=>'required|min:6|confirmed',
'password_confirmation'=>'required'
);
$validator = Validator::make(Input::all(), $rules);
if (! $validator->passes()) {
Input::flashExcept('password', 'password_confirmation');
return Redirect::to('my_form');
} else {
// do stuff with the form, it's all good
}
return Redirect::intended('/complete');
}
Additionally, in your template, you can show all of the errors from the form:
<ul>
#foreach($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
Or just select the first error and show it under the {{ Form::text
#if ($errors->has('first_name'))
<span class="error">{{$errors->first('first_name')}}</span>
#endif
Laravel has all of this built in, and you get it for free! Using Requests, Validators, Blade/HTML
I'm having a hard time figuring out how to repopulate a form for edit that has check boxes in it. I think the most confusing part is because they are coming from a pivot table.
I have users, permissions, and users_permissions tables.
For a quick demonstration of what the tables look like, I ran this query and included a screen clip of the results.
return $userPermissions = User::with('permissions')->find($id);
In my form I just have two permissions check boxes for now until I get the concept working, then I will add a foreach loop and grab them all from the database, but now I have the following:
<div class="form-group">
<label>
{{ Form::hidden('permissions[4]', '0', ['class' => 'checkbox-inline']) }}
{{ Form::checkbox('permissions[4]', '1', ['class' => 'checkbox-inline']) }}
Manage Content
</label>
</div>
<div class="form-group">
<label>
{{ Form::hidden('permissions[3]', '0', ['class' => 'checkbox-inline']) }}
{{ Form::checkbox('permissions[3]', '1', ['class' => 'checkbox-inline']) }}
Manage Users
</label>
</div>
I'm not sure if this is useful information, but when I first create the user, I create a permissions array to attach to the new user. Here is the code for that,
public function createUserPermissionsArray($input)
{
$permissionsArray = [];
$permissions = $input['permissions'];
foreach ($permissions as $id => $value)
{
if ($value == 1)
{
array_push($permissionsArray, $id);
}
}
$this->saveNewUserToDatabase($input, $permissionsArray);
}
I really need some direction here about how to solve this problem. Thanks
I recently worked on something similar, except I had groups with permissions assigned to them, which users were then assigned to. For example, for GroupController::edit() I had this code:
public function edit($id)
{
if(!permitted('group.edit')) {
return Redirect::route('user.dashboard');
}
$group = Group::find($id);
$permissions = Permission::all();
return View::make('admin.group.edit', [
'group' => $group,
'permissions' => $permissions,
'assigned' => $group->permissions->lists('id')
]);
}
Then within the form partial for the view (admin.group.partials.form), I had the following code to handle permissions:
#foreach($permissions as $permission)
<div class="row">
#if(isset($assigned))
{{ Form::checkbox(
'permissions[' . $permission->ident .']',
$permission->id,
in_array($permission->id, $assigned))
}}<label for="permissions">{{ $permission->ident }} - {{ $permission->description }}</label>
#else
{{ Form::checkbox(
'permissions[' . $permission->ident .']',
$permission->id)
}}<label for="group">{{ $permission->ident }} - {{ $permission->description }}</label>
#endif
</div>
#endforeach
I've formatted it the best I can, so that it's easy to read. Basically I had a create.blade.php and edit.blade.php which both include the form partial, but each file handles the opening and closing of the form (model binding for edit, normal open for create), hence the if statement.
Unfortunately I couldn't find a better method to achieve this. I hope this helps you.
P.S: As a side note, I've actually written a tutorial about creating a robust and simple ACL with Laravel, I can link if you'd like.