Catch only one specific error in Laravel 7 - php

I have a registration form, which contains the email and password fields. Currently, it returns the following errors in case the user does something wrong:
The email has already been taken.
The password must be at least 8 characters.
The password confirmation does not match.
However, I want that, when the user errs in the registry, only the error he made appears. I don't know if it is necessary to show the form, since there are only two input fields and a button. But, here is the code I made to return the errors:
#if(Session::has('errors') || count($errors) > 0)
#foreach($errors->all() as $error)
<div>
<h3>{{ $error }}</h3>
</div>
#endforeach
#endif

If you have an input like:
<input type="text" name="username" />
You can get the specific error, in the same view, like this:
#error('username')
<span>{{ $message }}</span>
#enderror

Related

Laravel Validate numeric multidimensional array

I want to give an error message if a string is entered in a integer inputfield with an multidimensional array.
View:
<div class="col-md-8">
<input name="answer[sleep][score]" type="text" class="form-control #error('answer[sleep][score]') #enderror" placeholder="Score" value="{{ #$answer_array['sleep']['score'] }}">
#error('answer[sleep][score]')
<span class="invalid-feedback" role="alert">
<strong>Geen letters alsjeblieft.😉</strong>
</span>
#enderror
</div>
Controller:
$request->validate([
'answer.sleep.score' => 'nullable|numeric',
]);
when i click save it just refreshes the page and does nothing. Can anybody please help me, how do i show the error on a multidimensional array.
Thanks!
#error is a blade directive used to display error messages in your template. The right way to use it is:
#error('answer.sleep.score')
<div>{{ $message }}</div>
#enderror
Notice that in order to detect whether the error message exists, I'm using the same format as you did in the validation i.e. answer.sleep.score and NOT answer[sleep][score].
If you want to add a class to your input element when an error is detected you can do this:
<input name="answer[sleep][score]" type="text" class="form-control {{ $errors->has('answer.sleep.score') ? 'error-class' : '' }}" placeholder="Score" value="{{ old('answer.sleep.score') }}">
By using old, you can pre-fill input field with the posted value.
You can use regular expression for the validation will be much better then this:
$request->validate([
'answer.sleep.score' => 'nullable|regex:/^[0-9]*$/',
]);
This allow you to enter only numbers in the field.

Using #error directive to target the previous input field from multiple input fields after submit in Laravel 5.8

The new #error directive was introduced in Laravel 5.8.13. So, instead of doing this:
// old
#if ($errors->has('email'))
<span>{{ $errors->first('email') }}</span>
#endif
You can now do this
// new
#error('email')
<span>{{ $message }}</span>
#enderror
However, I'm having issues trying to target only the input fields where the error was made among several similar input fields. These fields are similar because they have the same name. But they are also in seperate forms and have different submit buttons.
My html blade file is setup with multiple inputs generated from a #forelse statement. I've created a simple error check to check if a negative number is entered and to redirect back to the same page with an error message. The #error directive is also used to insert a custom class to target input field for styling.
#forelse($accounts as $account)
<form method="POST" action="{{ route('account.update', $account->id) }}">
#csrf
<div>
<input type="number" name="credit" class="#error('credit') is-invalid #enderror" required>
<input type="submit" class="btn" value="ok">
#error('credit')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</form>
#empty
#endforelse
The form submits to the update() method in AccountController.php
public function update(Request $request, Account $account)
{
if($request->input('credit') < 0)
{
return back()->withErrors(['credit'=>'enter a positive amount']);
}
// ... other logic
}
The problem is that when a negative number is entered in one input field, the error message shows up for every input with the same name, even when they are not in the same form.
I think making the input names unique will solve this, but this will make my backend logic more complex than is required.
Is there anyway of making the error message show for just the target input after the redirect, without having to use unique names for each input field?
Interestingly, the #error directive is not programmatically tied to any input field by an input name. It is only spatially related to an input field by proximity and can be placed any where on the page.
Also, you can conveniently use any string within the #error directive as long as same is passed to the withErrors() call in the controller.
So, solving the problem of targeting the appropriate input among multiple ones becomes as simple as using any unique string (not necessarily the target input name) as key in the withErrors() method call and retrieving the error message by passing the same string to the #error directive. In my case, I chose to use the account id as the unique string.
In AccountController.php:
public function update(Request $request, Account $account)
{
if($request->input('credit') < 0)
{
return back()->withErrors([$account->id=>'enter a positive amount']);
}
// ... other logic
}
And in the html blade template:
#forelse($accounts as $account)
<form method="POST" action="{{ route('account.update', $account->id) }}">
#csrf
<div>
<input type="number" name="credit" class="#error($account->id) is-invalid #enderror" required>
<input type="submit" class="btn" value="ok">
#error($account->id)
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</form>
#empty
#endforelse
NOTE: Using a non existent key in any #error directive breaks the code for other #error directives and will cause no error messages to be displayed.
A solution would be doing the following:
store the value / posted form in a variable using the value of the submit button
ditch the error directive and use the old version
combine the old version with the variable to check wether you have the correct form or not
You'll get something like this:
#if ($errors->has('email') && $submitted_form_identifier === $form_identifier)
<span>{{ $errors->first('email') }}</span>
#endif

Laravel: Show or hide content depending on a Session variable

I'm doing a view that has a password protection. Basically when you access that resource, you have a view that indicates that you need to put a password.
The correct behavior of this should be
You access the View
The user enters the password and sends the POST form
If the method redirects back with certain value, you must see the real content of the page.
So my blade code is the following:
#if ($passedPassword = Session::get('passedPassword'))
...here goes the real/true view content
#else
<section class="questionnaire-questions">
<div>
<form
action="{{ route('questionnaire.password', ['questionnaire' => $questionnaire->id]) }}"
method="POST">
{{ csrf_field() }}
<h3 class="text-center">#lang('questionnaire.password.advice')<h3>
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<div class="goal-input-group numeric">
<label>PASSWORD</label>
<input
style='visibility: visible;'
name="password"
type="password"
>
</div>
</div>
</div>
<div class="text-center">
<button type="submit" class="goal-btn goal-btn-lg goal-btn-artic-blue">#lang('questionnaire.password')</button>
</div>
</form>
</div>
</section>
#endif
That view is rendered with the following method:
public function show(Questionnaire $questionnaire) {
$data = [];
$data['questionnaire'] = $questionnaire;
\Session::flash('passedPassword', false);
return view('questionnaires.show', array('data' => $data));
}
In the previous method I'm passing the passedPassword, but I can't find a way to pass it as a flash variable. If there is a way to add data like
return back()->with(array(
'passedPassword' => false
));
But using the view method I'll really appreciate to know how.
Then, when the user clics the button I call the next function:
public function password(Request $request, Questionnaire $questionnaire) {
if (strcmp($questionnaire->password, $request->input('password')) == 0) {
return back()->with(array(
'passedPassword' => false
));
}
}
But even when the password is correct, I got the password view, the flash/session variable never arrived to the view.
Is there something I'm missing or doing wrong?
Thanks in advance.
As Dan told me in the comments, I was setting to false the value of the session variable.
So first I remove the \Session::flash('passedPassword', false); during the show method.
Then I modify my blade logic. In my case sometimes the password is needed and sometimes not.
#if (($passwordLength === 0) || ($passwordLength !== 0 && Session::has('passedPassword')))
With that, If the resource has no password we let the user pass. Or in the case it has a password and also we have the passedPassword variable, we also let the user see the content.

Laravel4+Bootstrap: How to make fields red on validation error

Inside a Laravel4 + Bootstrap 2.3.1 I have a form properly working with validation.
There are three fields obligatory: Name - Email - Phone.
When nothing is inserted, or the email is not in a proper format, the error messages are displayed.
But besides this, I would like to make the fields red, to show better where the error is.
How can I do this in Laravel + Bootstrap?
This is the form with the three fields obligatory:
<form name="room" method="post" class="narrow_width">
<label><span><i class="icon-user"></i></span> Name <span class="color-red">*</span></label>
{{ Form::text('name',Input::old('name'), array('class' => 'span7 border-radius-none')) }}
<label><span><i class="icon-envelope-alt"></i></span> Email <span class="color-red">*</span></label>
{{ Form::text('email',Input::old('email'), array('class' => 'span7 border-radius-none')) }}
<label><span><i class="icon-phone"></i></span> Phone number <span class="color-red">*</span></label>
{{ Form::text('phone',Input::old('phone'), array('class' => 'span7 border-radius-none')) }}
<p><button type="submit" name="submit" class="btn-u">Send Message</button></p>
</form>
Thank you very much!
I don't think there's an easy way to do this with the laravel Form class. I personally use my own package https://github.com/AndreasHeiberg/theme for this. You can use it if you wan't but it's subject to change.
Anyway raw code to do this is the following:
<div class="control-group {{ $errors->has($id) ? 'error' : false }}">
<label for="{{ $id }}" class="control-label">{{ $text }} {{ $required ? '<span class="required-red">*</span>' : ''}}</label>
<div class="controls">
<input type="{{ $type }}" id="{{ $id }}" name="{{ $id }}" value="{{ $value }}">
#if ($helpText)
<span class='help-inline'>{{ $helpText }}</span>
#endif
#foreach($errors->get($id) as $message)
<span class='help-inline'>{{ $message }}</span>
#endforeach
</div>
</div>
This being the important part
<div class="control-group {{ $errors->has($id) ? 'error' : false }}">
You can wrap this up in a form macro http://laravel.com/docs/html#custom-macros use a helper function or my package to do this.
With my package you would just use:
+#formText('name')
You can easily use Form macros, there is a bunch available here for Bootstrap 3:
http://forums.laravel.io/viewtopic.php?id=11960
Hope this helps...
Thanks for your efforts, especially #AndHeiberg.
For reason of simplicity, i decide to renounce to Laravel-Bootstrap validation and use instead a jquery plugin: https://github.com/jzaefferer/jquery-validation
The main reason is that is extremely easy to use.
It's enough to call the plugin and insert 'required' into the tag.
And the plugin will do all the rest, highlighting the field in red and displaying an error message for that field.
If your intention is to make the error more obvious to where it is, you can wrap the message text that is returned from Laravel validation errors in a span and give styling to that.
{{ $errors->first('email', "<span class='error'>:message</span>")}}
where :message is a "placeholder" for your error message. And then you can give any styling to .error spans as you wish. Check this Laracast lesson for more details (after 3:10).
In bootstrap, you can create errorfield with the id "inputError":
<input type="text" class="form-control" id="inputError">

Unable to access validation errors in view

I have set up a controller with some validation.
public function attemptLogin()
{
$rules = array(
'email'=>'required|email',
'password'=>'required'
);
$validator = Validator::make(Input::all() , $rules);
if($validator->fails()){
return Redirect::to('login')->withErrors($validator);
};
}
If I output the messages directly in the controller
$messages = $validator->messages();
print_R($messages->all());
I get the validation errors - however if I redirect:
return Redirect::to('login')->withErrors($validator);
The $errors array available in the view is always coming up empty.
From laravel four documentation
Note that when validation fails, we pass the Validator instance to the
Redirect using the withErrors method. This method will flash the error
messages to the session so that they are available on the next
request.
Variable $errors it's not an array.
The $errors variable will be an instance of
MessageBag.
For some reason I don't really like #seamlss idea.
You can use this instead.
#if(Session::has('errors'))
<? $errors = Session::get('errors'); ?>
<div class="alert alert-error">
<button type="button" class="close" data-dismiss="alert">×</button>
<ul>
<li id="form-errors" >
<h3> {{ $errors->first('email') }}</h3>
</li>
</ul>
</div>
#endif
I've used some bootstrap components, don't get confused, the only thing you need is the lines with the curly braces and the magical # sign.
From laravel docs error-messages-and-views
So, it is important to note that an $errors variable will always be
available in all of your views, on every request, allowing you to
conveniently assume the $errors variable is always defined and can be
safely used.
You can also check this
#if( $errors->has('email') )
<div class="control-group error">
<label class="control-label" for="email">Email</label>
<div class="controls">
<input type="text" id="email" placeholder="Email" name="email">
<span class="help-inline">{{ $errors->first('email') }}</span>
</div>
</div>
#endif
I've had success redirecting using ->withErrors($validation)
And then in the view checking the condition #if( $errors->count() > 0 )...
#if( $errors->count() > 0 )
<p>The following errors have occurred:</p>
<ul id="form-errors">
{{ $errors->first('username', '<li>:message</li>') }}
{{ $errors->first('password', '<li>:message</li>') }}
{{ $errors->first('password_confirmation', '<li>:message</li>') }}
</ul>
#endif
Have you tried:
return Redirect::to('login')->withErrors($validator);
or
return Redirect::to('login')->withErrors($validator->messages());
Here is another possibility when you have difficulty showing errors, and when they are passed correctly via ->withErrors(). If you redirect to a controller action that has to perform any sort of its own state checking and itself calls ->withErrors(), it will shadow the $errors first injected.
Try the following
return Redirect::to('login')->with('errors',$validator->errors->all());
then from your view loop through this errors
foreach($errors as $error) {
print $error;
}

Categories