I am using Laravel 5.3.18 to build a form that allows the user to enter one or more dates. I am also using the HTML/Form library from the Laravel Collective along with a FormRequest object to validate the fields. My problem is when the user dynamically adds in more date inputs (via JavaScript) and submits the form, if it doesn't pass validation, the "dynamically" added data (and inputs) are not redisplayed on the form.
My question is: Does Laravel handle this use case? And if so, how can I make this work (or what am I doing wrong)? Your insights and help are much appreciated!
Here is the actual snippet of code that initially generates the date inputs:
#foreach ($eventDates as $index=>$eventDate)
<div class="form-group{{ $errors->has('eventDates.'.$index.'.start_datetime') ? ' has-error' : '' }}" id="{{ 'event_date_group_'.$index }}">
{!! Form::label('eventDates['.$index.'][start_datetime]', 'Event Dates (Day '.($index + 1).')', ['class' => 'col-md-4 control-label']) !!}
<div class="col-md-3">
{!! Form::text('eventDates['.$index.'][start_datetime]', $eventDate['start_datetime'], ['id' => 'start_datetime_'.$index, 'class' => 'datetimepicker form-control']) !!}
#if ($errors->has('eventDates.'.$index.'.start_datetime'))
<span class="help-block"><strong>{{ $errors->first('eventDates.'.$index.'.start_datetime') }}</strong></span>
#endif
</div>
</div>
#endforeach
which generates this:
<div class="form-group" id="event_date_group_0">
<label for="eventDates[0][start_datetime]" class="col-md-4 control-label">Event Dates (Day 1)</label>
<div class="col-md-3">
<input id="start_datetime_0" class="datetimepicker form-control" name="eventDates[0][start_datetime]" type="text">
</div>
</div>
So, if the user dynamically creates another date input, it will look as follows:
<div class="form-group" id="event_date_group_0">
<label for="eventDates[0][start_datetime]" class="col-md-4 control-label">Event Dates (Day 1)</label>
<div class="col-md-3">
<input id="start_datetime_0" class="datetimepicker form-control" name="eventDates[0][start_datetime]" type="text">
</div>
</div>
<div class="form-group" id="event_date_group_1">
<label for="eventDates[1][start_datetime]" class="col-md-4 control-label">Event Dates (Day 2)</label>
<div class="col-md-3">
<input id="start_datetime_1" class="datetimepicker form-control" name="eventDates[1][start_datetime]" type="text">
</div>
</div>
And here is part of my FormRequest object:
public function rules() {
return [
'name' => 'required|max:100',
'eventDates.*.start_datetime' => 'required',
'eventDates.*.end_datetime' => 'required',
...
];
}
public function messages() {
return [
'eventDates.*.start_datetime.required' => 'Start date/time is required.',
'eventDates.*.end_datetime.required' => 'End time is required.',
...
];
}
Lastly, the validation works. The error messages show up for the dates input. In fact, if I dynamically create the extra date inputs. Fill everything out but leave just the dynamic date inputs blank, the validation will fail and the form will redisplay but the dynamic inputs and data don't show up. I also put in the following debug statement in the template to see how many elements come back in the array and it always show just 1.
<p>Number of Dates: {{ count($eventDates) }}</p>
Related
EDIT:
Your solutions are working for text inputs and textareas, but checkboxes are not working correctly for me.
This was my original checkbox:
{{ Form::checkbox('active', true, (isset($user->active)) ? old($user->active) : true, ['class' => 'custom-control-input', 'id' => 'active']) }}
I've tried a lot of possible solutions like adding old('active', isset($user) ? $user->active: true) instead, but when an error occurs I lose the values from this input. On the controller I was checking this, but if I change the input to the 'new solution' active is always false on my db:
if(!array_key_exists('active', $validated)){
$validated = array_add($validated, 'active', '0');
}
ORIGINAL QUESTION (PARTIALLY RESOLVED):
I have one blade view call edit with two forms, but each one is calling his own method/route. One form is for edit/store the user and the other is a form in a modal to change the user password. When I change the password and no validation error happens, the other form still has all of his values that is getting from old() or $user variable via index method. But if for example the passwords do not match, a validation error occurs, and the values from the edit/store user form disappear.
Forms are pretty simple (remember, they are on the same view, and the one that is giving me problems is the edit/create one), and each one call a different method from UserController
Form 1 for edit users (simplified)
#if($user->exists)
{{ Form::model($user, ['route' => ['users.update', $user], 'class' => 'needs-validation', 'novalidate'=>'']) }}
#method('PATCH')
#else
{{ Form::model($user, ['route' => ['users.store'], 'class' => 'needs-validation', 'novalidate'=>'']) }}
#method('POST')
#endif
#csrf
<div class="form-group">
<div class="row">
<div class="col-sm-4">
{{ Form::label('cif', __('users.cif'), ['class' => 'form-label']) }}
{{ Form::text('cif', (isset($user->cif)) ? old($user->cif) : '', ['class' => 'form-control', 'required','maxlength'=>'12', 'minlength'=>'9']) }}
{{ Form::hidden('validate','', ['class' => 'form-control', 'required', 'id'=>'validate']) }}
</div>
<div class="col-sm-6">
{{ Form::label('name', __('users.name'), ['class' => 'form-label']) }}
{{ Form::text('name', (isset($user->name)) ? old($user->name) : '', ['class' => 'form-control','required','maxlength'=>'255']) }}
</div>
<div class="col-sm-2">
{{ Form::label('initials', __('users.initials'), ['class' => 'form-label']) }}
{{ Form::text('initials', (isset($user->initials)) ? old($user->initials) : '', ['class' => 'form-control', 'required','maxlength'=>'5']) }}
</div>
</div>
<div class="col-sm-6">
{{ Form::label('province', __('users.province'), ['class' => 'form-label']) }}
{{ Form::text('province', (isset($user->city)) ? $user->city->province->name : '', ['class' => 'form-control', 'disabled'=>'']) }}
</div>
{!! Form::close() !!}
Form 2: Update password
<form id="change-password" action="{{route('users.change.password', $user)}}" method="POST">
#csrf
<div class="modal-body">
<div class="card-body">
<div class="panel-tag">
<p>Las contraseñas debe de coincidir y tener más de 8 carácteres</p>
</div>
<div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">Contraseña</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control #error('password') is-invalid #enderror" name="password" required autocomplete="new-password" minlength="8">
#error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div>
<div class="form-group row">
<label for="password-confirmation" class="col-md-4 col-form-label text-md-right">Confirmar contraseña</label>
<div class="col-md-6">
<input id="password-confirmation" type="password" class="form-control #error('password') is-invalid #enderror" name="password_confirmation" required autocomplete="new-password" minlength="8">
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button id="change" type="submit" form="change-password" class="btn btn-primary">Confirmar</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Cancelar</button>
</div>
</form>
UserController I'm going to paste two methods, one for store/user, the other for change the password. Update method is very similar.
public function store(StoreUserRequest $request)
{
if( $request['validate'] == 1 ){
$validated = $request->validated();
$validated['password'] = Hash::make($validated['password']);
$id = DB::table('users')->insertGetId($validated);
return redirect()->route('users.edit',['user'=>$id])->with('status', 'created');
} else {
return redirect()->back()->withInput()->with('status', 'error_dni');
}
}
public function changePassword(PasswordUserRequest $request, User $user)
{ // HERE IS WHERE I THINK IS THE PROBLEM, IF VALIDATION FAILS (FOR EXAMPLE PASSWORD CONFIRM) VALUES FROM THE OTHER FORM DISAPPEAR AND IT DOESNT GET INTO THIS METHOD
$pass = Hash::make($request->password);
$user->password = $pass;
$action = $user->save();
if ($action) {
return redirect()->back()->with('status', 'change_password_ok');
}
return redirect()->back()->with('status', 'error_change_password');
}
PasswordUserRequest This is the request to validate the password form
public function rules()
{
return [
'password' => 'required|string|confirmed';
];
}
The route would be something like:
users/{user}/edit
I've spent all day trying to fix this and still didn't found a solution. My english is not very good so please tell me if I'm not explaining something correctly and I will edit the question.
Thanks and hope that I can find a solution.
old values are from input name
<input type="text" name="input" value="{{old('input')}}"
example
<div class="col-sm-4">
{{ Form::label('cif', __('users.cif'), ['class' => 'form-label']) }}
{{ Form::text('cif', old('cif', $user->cif ?? ''), ['class' => 'form-control', 'required','maxlength'=>'12', 'minlength'=>'9']) }}
{{ Form::hidden('validate','', ['class' => 'form-control', 'required', 'id'=>'validate']) }}
</div>
//$user->cif ?? '' <- left or right hand-side operand, return right-hand if left is null or undefined
//old('input', $user->cif ?? '') <- if old input available, use old input, if not, $user will be displayed
form::checkbox:
First argument : name
Second argument : value
Third argument : checked or not checked (true or false)
Fourth argument : additional attributes
note that value is attribute(value) and checked is attribute(checked)
then
{{ Form::checkbox('active', true, (isset($user->active)) ? $user->active : true, ['class' => 'custom-control-input', 'id' => 'active']) }}
//2nd parameter (true) will always set checkbox value to 1(true)
//(isset($user->active)) ? $user->active : true <- will set default to true (checked) if $user is null or undefined
//maybe try
{{ Form::checkbox('active', $user->active ?? false, $user->active ?? false) }}
//if $user != null, put $user->active else put false
//if $user != null, set checked value based on $user->active else put false
in html looks like this
<input type="checkbox" value="1" checked="checked">
then you need to add inline event onchange="$(this).is(':checked') ? $(this).val(1) : $(this).val(0);" in the 4th parameter of form::checkbox to change the default on runtime
If I understood all correctly, you should do this way:
old('name', isset($user) ? $user->name : ''),
Here you trying to get old name input, and if it doesn't exist, in second parameter od old function you are getting default value, which is user's name in case of user exists
There is documentation, which can help you to understand much more.
I'm building a Job Search type of application. There are two types of users, job seekers and employers where each has their own Role. When an Employer is logged in he can browse through the profiles of candidates and request an interview. He can choose 2 options for time and date and click send. When that specific User signs in, at the top of the page I want to display the notifications with a bell icon and the notification should say "You've been sent an Interview request!". Then when they click it or go to the Notification section on the admin panel, it will display the Employers information "Hi username, Company ABC is interested in your profile and would like to schedule you for an interview." with the 2 date and time options. The Job Seeker selects date and time option 1, clicks send and then the employer receives the notification from the job seeker. They will communicate this way until they both agree on a date and time to setup an interview. So I would like 2 notifications for this. 1 when the interview request is sent to a candidate and a second for when a candidate select a date and time that is good for him and sends the request back to the employer. I understand how to send a notification when a User is logged in, but I'm missing something for how to send a notification to a user that is not logged. Both of these types of users are stored in my Users Table, just with different roles.
job_seeker_profile.blade.php file:
{!! Form::open(['method'=>'POST', 'action'=>'AdminEmployerInterviewRequestsController#store', 'files'=>true, 'style'=>'width: 100%;']) !!}
<div class="form-group">
<div class="input-group date" id="datetimepicker1" data-target-input="nearest">
{!! Form::text('date_time1', null, ['class'=> $errors->first('date_time1') ? 'border-danger form-control datetimepicker-input' : 'form-control datetimepicker-input', 'data-target'=>'#datetimepicker1']) !!}
<div class="input-group-append" data-target="#datetimepicker1" data-toggle="datetimepicker">
<div class="input-group-text"><i class="fa fa-calendar"></i></div>
</div><br>
</div>
<small class="text-danger">{{ $errors->first('date_time1') }}</small>
</div>
<div class="col">
</div>
<div class="form-group">
<div class="input-group date" id="datetimepicker2" data-target-input="nearest">
{!! Form::text('date_time2', null, ['class'=> $errors->first('date_time2') ? 'border-danger form-control datetimepicker-input' : 'form-control datetimepicker-input', 'data-target'=>'#datetimepicker2']) !!}
<div class="input-group-append" data-target="#datetimepicker2" data-toggle="datetimepicker">
<div class="input-group-text"><i class="fa fa-calendar"></i></div>
</div><br>
</div>
<small class="text-danger">{{ $errors->first('date_time2') }}</small>
</div>
<div class="form-group">
{!! Form::hidden('user_id', Auth::user()->id, ['class'=>'form-control']) !!}
</div>
<div class="form-group">
{!! Form::hidden('job_seeker_profile_user_id', $jobSeekerProfile->id, ['class'=>'form-control']) !!}
</div>
<div class="form-group">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
{!! Form::submit('Send Interview Request', ['class'=>'btn btn-primary float-right']) !!}
</div>
<br><br><br><br>
{!! Form::close() !!}
AdminEmployerInterviewRequestsController.php file:
public function store(EmployerInterviewCreateRequest $request)
{
$input = $request->all();
$user = Auth::user();
$JobSeekerProfile = JobSeekerProfile::all();
$user->interviewRequestsSent()->create($input);
$user->interviewRequestsReceived()->create($input);
$user->notify(new InterviewRequestSent());
$JobSeekerProfile->notify(new InterviewRequestReceived());
return redirect('/admin/employer/interviews');
}
but when I called the
$JobSeekerProfile->notify(new InterviewRequestReceived());
It gave me this error:
Method Illuminate\Database\Eloquent\Collection::notify does not exist.
Is it possible to send another user a notification after an action is taken?
Your error is because you're pulling every single JobSeekerProfile into a collection and then trying to call notify() on the collection. Since you're submitting the ID, just use that to build an instance and notify it.
public function store(EmployerInterviewCreateRequest $request)
{
$input = $request->all();
$user = Auth::user();
$JobSeekerProfile = JobSeekerProfile::find($request->job_seeker_profile_user_id);
$user->interviewRequestsSent()->create($input);
$user->interviewRequestsReceived()->create($input);
$user->notify(new InterviewRequestSent());
$JobSeekerProfile->notify(new InterviewRequestReceived());
return redirect('/admin/employer/interviews');
}
It's not possible right now. Only users who are logged in can receive a notification. I've sent several tickets regarding this
Here is my routes
Route::get('add-members/{id}','MemberController#create');
Route::post('save-member/{id}','MemberController#store');
This is my code to show the create form
public function create($id)
{
$team=Team::find($id);
$users = User::doesntHave('teams')->whereHas('roles', function($role) {
$role->where('name', 'member');
})->get();
return view('members.create',compact('users','team'));
}
An this is my code to store it
public function store(Request $request,$id)
{
$team=Team::find($id);
dd($request->id);
$team->users()->attach($request->id);
return redirect('home');
}
and this is my blade file
#extends('layouts.app')
#section('content')
<form action="{{url('save-member',$team->id)}}" method="post" accept-charset="utf-8">
#csrf
<div class="form-group row">
<label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Select Member/s') }}</label>
<div class="col-md-6">
#foreach($users as $key => $user)
<input type="checkbox" name="id[]" value="{{$user->id}}">{{$user->email}}<br>
#endforeach
#error('member_id')
<span class="invalid-feedback" role="alert"><strong><font
color="red">{{ $message }}</font></strong></span>
#enderror
</div>
</div>
<button type="submit" class="btn btn-primary">Save</button>
</form>
#endsection
Now when i select none of the user and just click save button it will save the the user id as 1. After i am doing dd($request->id) it will show me the output 1. But in my form there is no users left or my form is empty.So where from 1 is coming. you can see this picture for clearify.
Please help me to solve this problems
You should be more specific with what data you are requesting from the Request:
$request->id; // could be an input named 'id' or a route parameter named 'id'
$request->input('id'); // is an input
$request->route('id'); // is a route parameter
You are running into a situation where you have a route parameter named id and potentially an input named id. Using the dynamic property of the Request, $request->id, will return the input id if it is there, if not it falls back to returning a route parameter named id.
Here is an article from the past that shows the issue with not being specific about what you are trying to get from the Request object:
asklagbox - blog - watch out for request
I am working on a ticket log where tickets get edited multiple times before they are 'done'.
I have an overview where you see all the tickets, on top of the page are 6 buttons. All buttons open a popup with a form. The first button is a create function which makes the ticket and fills in the first information. All other fields are now NULL. The second buttons is the first edit button.
Upon opening it opens an form where the user scans a barcode to fill in the first field; Ticket Number. this ticket number is unique for every Ticket. Next thing to fill in is your credentials, which come from a dropdown.
Due to the fact that all the edit forms work by Ticket_number (which is scanned from a QR code) I made it so all forms are on the same page. Therefor I am not able to do something like : action="{{ route('countries.update',$country->id) }} as I don't know the ID at this moment.
Here is the code behind everything(and you can see what I tried there too):
web.php:
// TICKET LOG ROUTES
Route::post('ticket/start-picking', 'TicketController#startpicking')->name('tickets.startpicking');
Route::resource('tickets', 'TicketController');
form for edit:
<div id="modal-start-picking" class="modal">
<form method="POST" id="modal-start-picking-form" action="{{ route('tickets.startpicking') }}">
#csrf
<input type="text" value="modal-start-picking" name="type" hidden>
<div class="modal-content">
<h4>Start Picking</h4>
<p>Scan Ticket Number here</p>
<div class="input-field">
<label for="start">Ticket Number</label>
<input type="text" name="ticket_number" id="start" autofocus>
</div>
<div class="input-field">
<select id="picker" name="picker">
<option value="" disabled selected>Choose a Picker</option>
#foreach($employees as $employee)
<option {{(old('picker') == $employee->initials ) ? 'selected' : ''}} value="{{ $employee->initials }}">{{ $employee->initials }}</option>
#endforeach
</select>
</div>
</div>
<div class="modal-footer">
<input class="btn-flat" type="submit" value="Start Picking">
</div>
</form>
</div>
Function in TicketController:
public function startpicking(Request $request, Ticket $ticket)
{
$request->validate([
'picker' => 'required',
]);
$ticket->update(array_merge($request->all(), ['picker_start_time' => Carbon::now()]));
return redirect()->route('tickets.index')->with('toast', 'Ticket updated successfully');
}
If any more info is required I Will gladly update my post.
I found out how it's done.
$request->validate([
'picker' => 'required',
]);
Ticket::where('ticket_number', $posted_ticket_number)->update([
'picker' => $request->picker,
'picker_start_time' => Carbon::now(),
]);
You just have to use ::where('column', 'variable').
The variable was pulled from my form (The Ticket number in my case. As this was an unique identifier.) and the column is self explanatory.
So I'm pretty new to laravel in general, and what I have is a search form that pulls information from the database and then calls it back on the same page, currently it's working like a redirect but I would like to know how to do this without having to refresh the page
This is the blade:
<form class="form-horizontal" role="form" id="policy-documents-search-form" action="/search" method="POST">
{{ csrf_field() }}
<fieldset>
<div class="form-group">
<label for="username" class="col-sm-6 control-label">Enter your policy number</label>
<div class="col-sm-8">
<input type="text" name="ordernumber" id="ordernumber" class="form-control"/>
<span class="text-danger">{{ $errors->first('ordernumber') }}</span>
</div>
</div>
#if (session('error'))
<div class="alert alert-danger">{{ session('error') }}</div>
#endif
<div class="form-group">
<div class="col-sm-offset-4 col-sm-8">
<button type="submit" class="btn btn-primary" id="search-button">Search</button>
</div>
</div>
<div class="form-group">
<div class="container">
#if(isset($order))
<h2>Your Policy Details</h2>
<table>
<thead>
<tr>
<th>Name</th>
<th>Claims Telephone</th>
<th>Policy Wording</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ #$order->scheme->Description }}</td>
<td>{{ #$order->scheme->ClaimsTelephone1 }}</td>
<td>Policy Wording </td>
</tr>
</tbody>
</table>
#endif
</div>
</div>
</div>
</fieldset>
</form>
This is the Controller function:
public function search(Request $request) {
if ($this->validate($request, [
'ordernumber' => 'string|min:8|max:16',
], [
'ordernumber.string' => ' Please enter a full order number. This will either be 8, 12 or 16 characters long and include a 2 letter prefix.',
'ordernumber.min' => ' Please enter a full order number. This will either be 8, 12 or 16 characters long and include a 2 letter prefix.',
'ordernumber.max' => ' Please enter a full order number. This will either be 8, 12 or 16 characters long and include a 2 letter prefix.',
]));
try {
$order = Order::findOrFail(decodeFullOrderNumber($request->ordernumber));
} catch (ModelNotFoundException $exception) {
return back()->withError('We could not find this policy number in our system, please try again')->withInput();
}
return view('policy_wording', compact('order'), [
'title' => "Policy Wording Results",
]);
}
And this is the route:
Route::get('/policy-wording',
'PolicyWordingController#policyWordingPage');
Route::any('/search', 'PolicyWordingController#search');
First of all i suggest to use Vuejs for that purposes so u can not think about how to rebuild your table, etc.
On the serverside all you need to do is return search result if was ajax
if ($request->isXmlHttpRequest())
return $order->toArray();
before return view()
To do it with AJAX, you need a front end solution, like Axios or jQuery, in order to make the AJAX requests.
Once the request is sent, you can handle it like a regular POST request and then return a JSON or a html.
For JSON, it's pretty simple, every array or model you return will be converted to JSON by default.
To return a view however, you need to use the render method. This method will "render" the view and return you the corresponding HTML.
So, instead of :
return view('policy_wording', compact('order'), [
'title' => "Policy Wording Results",
]);
you should have something like :
return view('policy_wording', compact('order'), [
'title' => "Policy Wording Results",
])->render(); //notice the render method here
Then all you need to do is to handle the response in your front-end.
Edit about validation
If your validation fails, it'll return a 422 error (Unprocessable Entity), so you can handle it like any other ajax error.