i got a question about php and ajax with the slim Framework
I created some routes that routes me to a controller now i want to submit a simple form with Ajax. This is working fine, but the problem is if i will submit the form without Ajax i send a post request the server this will call the createAction instead of the form renderAction method in my controller (see code).
But i need to call formRender because when the form not is valid i have to show the form with the values to the user again.
note: I'am not implemented any validation code yet.
Here my JS Code to submit the Form:
$('#reservation').on('submit', function (ev) {
ev.preventDefault();
var data = $(this).serialize();
var keyVal = data.split("&");
var values = [];
keyVal.forEach(function (element) {
values[element.split("=")[0]] = element.split("=")[1];
});
$.post("/admin/reservation/create", data).done(function (data) {
console.log(data);
}).error(function (err) {
});
});
and here the code of my controllers:
public function formRender(Request $request, Response $response)
{
$formData = $request->getParams();
return $this->view->render($response, '/reservations/form.twig', [
'formData' => $formData]);
}
public function createAction(Request $request, Response $response)
{
$formData = $request->getParams();
$response = $response->withJson($formData);
return $response;
}
here my routes:
$app->get('/reservation/create', 'ReservationController:formRender');
$app->post('/reservation/create', 'ReservationController:createAction');
here the view code (using twig):
<form class="col s6" id="reservation" method="post">
<div class="row">
<div class="input-field col s6">
<input placeholder="Titel" id="title" name="title" type="text" class="validate"
value="{{ formData.title }}">
<label for="title">Titel</label>
</div>
<div class="input-field col s12 m6">
<select class="icons" multiple>
<option value="" disabled selected>Choose Rooms</option>
<option value="" data-icon="images/sample-1.jpg" class="circle">example 1</option>
<option value="" data-icon="images/office.jpg" class="circle">example 2</option>
<option value="" data-icon="images/yuna.jpg" class="circle">example 1</option>
</select>
<label>Rooms</label>
</div>
</div>
<div class="row">
<div class="input-field col s6">
<input value="{{ formData.startDate }}" id="startDate" name="startDate" type="date" class="validate">
</div>
<div class="input-field col s6">
<input value="{{ formData.endDate }}" id="endDate" name="endDate" type="date" class="validate">
</div>
</div>
<button type="submit" class="waves-effect waves-light btn">button</button>
</form>
how should i solve this ... so i want to be able to send data per ajax, and i want to be able to submit my form without js. I'am looking for a clean solution .. not a quick and dirty fix with a hidden field or something...
whats best practice for such cases?
I suggest you solve it naming your routes:
$app->get('/reservation/create', 'ReservationController:formRender')->setName('reservationFormRenderer');
$app->post('/reservation/create', 'ReservationController:createAction')->setName('reservationFormAjaxProcessor');
Since you are using Twig as templating engine, use path_for method to inject the rotes to the form:
<form class="col s6" id="reservation" method="post" action="{{ path_for('reservationFormRenderer') }}" data-ajax-processor="{{ path_for('reservationFormAjaxProcessor') }}">
All that is left to do is to pick the dynamic route in your JS code:
$('#reservation').on('submit', function (ev) {
ev.preventDefault();
var data = $(this).serialize();
var keyVal = data.split("&");
var values = [];
keyVal.forEach(function (element) {
values[element.split("=")[0]] = element.split("=")[1];
});
// here we pass the value of data-ajax-processor attribute of the form
$.post(($this).data('ajax-processor'), data).done(function (data) {
console.log(data);
}).error(function (err) {
});
});
Now if the form is not submitted dynamically (i.e. AJAX-way), the URL of the processor will be in form's action attribute.
You could actually do this without naming your routes, but this manner will keep maintainability of your code, since you'll only have to change actual URLs in one place - that is in routes declarations.
Related
In my ClientController#index, I have a form with a select input to list every client in the database.
After submitting the form to list detailed client information, the URL is like /clients?client_id=id.
The routes are the defult with route::resource().
<form name="show_client" id="show_client">
<div class="form-group">
<label for="branch"><b>Selectione o Cliente</b></label>
<select class="form-control select2" name="client_id" id="client_id" required>
<option value="">Selecione o Cliente</option>
#foreach ($list as $client)
<option value="{{ $client->client_id }}">{{ $client->name }} </option>
#endforeach
</select>
</div>
<hr />
<div class="form-group">
<button type="submit" class="btn btn-primary btn-rounded">Listar Cliente</button>
</div>
</form>
<script>
$(function() {
$('#show_client').submit(function(){
var client_id = $('#client_id').val();
$(this).attr('action', "/clients/" + client_id);
});
});
</script>
Is there any way to work the url to be /clients/id?
I accomplish that by using an js function but it's clearly not the solution.
You should listen to the change event on the select list:
<script>
$(function() {
$('#client_id').change(function(){
var client_id = $(this).val();
$('#show_client').attr('action', "/clients/" + client_id);
});
});
</script>
You do know you can make the parameter in the route optional. That way, it can accept the route without a parameter. You then append the parameter on submit of the form
I have patients information in database, now I want to access one's information in another form. When I will input patient's ID the patient name field need to be filled/loaded automatically. I have my Patient model also.
This is the from...
<form method="post" class="" action="" >
#csrf
<div class="input-field col s3">
<input name="patient_id" id="id" type="text" class="validate">
<label class="active" for="id">Patient ID</label>
</div>
<div class="input-field col s9">
<input name="patient_name" id="name" type="text" class="validate">
<label class="active" for="name">Patient Name</label>
</div>
<div class="input-field col s12">
<select name="room">
<option value="" disabled selected>Select Room</option>
<option value="2001">ROOM 2001 - Non AC - 500</option>
<option value="4001">ROOM 4001 - AC -800</option>
<option value="301">CABIN 301 - AC - 1700</option>
</select>
</div>
<div class="input-field col s12 text-center">
<button class="btn waves-effect waves-light" type="submit" name="action">Assign Room</button>
</div>
</form>
You can
create the json object in the blade template, which may be a little messy if special characters are present. Also, i don't see this as a good solution if you have tons of records.
I would use a library, like https://select2.org/, what you'll be looking for is here https://select2.org/data-sources/ajax ... i personally use this one https://semantic-ui.com/modules/search.html#/examples... but i think select2 is more straight.
At the bottom of https://select2.org/data-sources/ajax you can see how an object with the full data can be passed while querying the server.
Since the name is just for searching the id ( I Assume)
You could also adjust your controller so it looks in CONCAT(id,name) so the user can type the id or name and find the patient.
Pass the patient details to the view through the compact and use the values of the patient collection accordingly in the input fields.
controller
public function edit($id){
$patient = Patient::find($id);
return view('patients.edit, compact('patient'))
}
In the view
<input value="{{ old('name') ? old('name') : $patient->name }}" name="name" type="text" class="form-control" required>
<input name="patient_id" onkeydown="getInfo(this)" id="id" type="text" class="validate">
<script type="text/javascript">
function getInfo(input){
var xhr = new XMLHttpRequest();
xhr.open("GET", 'your/url/to/get/info/from/db/'+input.value, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send();
xhr.onload = function() {
var data = JSON.parse(this.responseText);
document.getElementById('name').value = data.name;
document.getElementById('room').innerHTML= '<option value="'+
data.room +'">'+data.room +'</option>';
data.name
}}
you can try this.
Execute a JavaScript when a you Enter patient id in input field:
here is the example -> https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_ev_oninput
HTML
<input name="patient_id" id="id" type="text" class="validate" oninput="myFunction()">
Javascript
function myFunction() {
var p_id = document.getElementById("id").value;
$.ajax({
url: '{{URL::to('get_patient_name')}}'+ '/'+p_id,
type: "get",
success: function (data) {
}
});
}
Now make one route:
Route::get('get_patient_name/{p_id}', 'PatientController#getPatientName'});
In controller get the name of the patient
public function getPatientName($id)
{
return ModelName::where('patient_id',$id)->value('patient_name');
}
and finally, print patient name in the name input field.
in the javascript success function
success: function (data) {
$('#name').val(data);
}
If you want to do it without using jquery, here is vanilla js
dont forget to change request url!
document.querySelector("#id").addEventListener("change", function () {
let xml = new XMLHttpRequest(),
token = document.querySelector("input[name=_token]").value,
id = document.querySelector("#id").value,
name = document.querySelector("#name");
xml.open("get", "get/" + id); // change url
xml.setRequestHeader("X-CSRF-TOKEN", token);
xml.onreadystatechange = function () {
if (xml.readyState === 4) {
var response = JSON.parse(xml.responseText);
if (xml.status === 200 ) {
name.value = response
} else {
console.log('something bad happened');
}
}
};
xml.send()
})
Then in your controller find patient and send back
public function getPatient($id){
$patient = Patient::find($id);
return response()->json($patient->name);
}
This is my first api project. Can you help me with my code please?
I can't see the problem.
Here is my controller.
public function store(Request $request)
{
//
$valid=Validator::make($request->all(),[
'text'=>'required',
'body'=>'required'
]);
if($valid->fails()){
return response()->json(['message'=>$valid->messages()]);
}else{
$item= Item::create([
'text'=>$request->input('text'),
'body'=>$request->input('body')
]);
return response()->json($item);
}
}
and here is my form.Is there anything wrong in the form?
<form id="form">
<div class="form-group">
<label>Text :</label>
<input type="text" id="text" class="form-control col-sm-4">
</div>
<div class="form-group">
<label>Body :</label>
<textarea id="body" class="form-control col-sm-4"></textarea>
</div>
<div class="form-action">
<input type="submit" class="btn btn-primary" value="submit">
</div>
</form>
and the ajax code between the show function is working but I don't know where the problem is ?.
$('#form').on('submit', function (e) {
e.preventDefault();//prevent the form to submit to file
let text = $('#text').val();
let body = $('#body').val();
addItems(text, body);
});
function addItems(text, body) {
var item = {
text: text,
body: body
};
$.ajax({
method: 'POST',
url: 'http://localhost:8000/api/items',
data: item,
success: function (item) {
alert('done the item number' + item.id + ' has been added!!');
location.reload();
},
error: function () {
alert('error')
}
})
}
Thanks for helping!
if your front-end source separated from back-end source, then add cross-Origin Resource Sharing
package to your laravel project.
if its on your laravel view then add csrf token to meta tag -
<meta name="csrf-token" content="{{ csrf_token() }}">
and send it with your ajax request { _token : document.querySelector('meta[name="csrf-token"]').content}
The problem is that you're sending the form without sending the cross site request forgery token.
Add the directive #csrf to your view
Then send it has Hasan wrote ;)
I use ajax to submit a form without having to reload the page after, but I really don't know how to get the forms errors, especially for the required fields.
Here is my form, it's a simple form with two datepicker:
<form>
<div class="form-group row">
<label for="date_debut" class="col-md-4 col-form-label text-md-right">Date de début</label>
<div class="col-md-6">
<input type="text" id="date_debut" name="date_debut" class="datepicker-here form-control" data-timepicker="true" data-language='fr' placeholder="Choisir une date" />
</div>
</div>
<div class="form-group row">
<label for="date_fin" class="col-md-4 col-form-label text-md-right">Date de fin</label>
<div class="col-md-6">
<input type="text" id="date_fin" name="date_fin" class="datepicker-here form-control" data-timepicker="true" data-language='fr' placeholder="Choisir une date" />
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<button id="ajoutDispoButton" onclick="myfunction()" type="button" class="btn btn-primary">
Ajouter
</button>
</div>
</div>
<input type="hidden" id="user_id" name="user_id" class="form-control" value="{{$user->id}}" required>
</form>
And here is my Ajax call :
function myfunction(param){
var date_debut = $('#date_debut').val();
console.log(date_debut);
var date_fin = $('#date_fin').val();
var user_id = $('#user_id').val();
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
url: '{{ route('createDispo') }}',
type: 'POST',
dataType: "json",
data: {
user_id: user_id,
date_debut: date_debut,
date_fin: date_fin,
},
success: function (data) {
$("#centralModalSuccess").modal();
$("#date_fin").val("");
$("#date_debut").val("");
},
error: function (data) {
var errors = data.responseJSON;
console.log(errors);
}
});
}
And here my controller :
public function createDispo(Request $request){
$user = User::find($request->user_id);
$disponibilite = new Disponibilite();
$disponibilite->date_debut = Carbon::createFromFormat('d/m/Y H:i',$request->date_debut);
$disponibilite->date_fin = Carbon::createFromFormat('d/m/Y H:i',$request->date_fin);
$user->disponibilites()->save($disponibilite);
return response()->json(['ok' => 'ok']); // Return OK to user's browser
}
I think this is not the right way to proceed, but this work. The problem is that I want to handle the validations errors, my fields are required but I can send the ajax call even if they are empty.
Anyone know how to do that?
you can make form validation with jquery instead of laravel validation
Look at this question : A simple jQuery form validation script
Add validation in controller function
public function createDispo(Request $request){
$request->validate([
'date_debut' => 'required',
'date_fin' => 'required',
]);
// your code
}
and display the errors in html.
I need to send a Form with just the values append to the URL, like this:
http://thisistheurl.com/serv#search/VALUE1/VALUE2/VALUE3/VALUE4
I could send like this:
http://thisistheurl.com/serv?variable1=value&variable2=value&variable3=value&variable4=value#search/
The form is very simple.
<form id="consultatickets" name="consultatickets" role="form" method="get" class="tickets-form" action="http://thisistheurl.com/serv#search/" target="_blank">
<div class="row">
<div class="form-group col-md-12 col-sm-12">
<label for="ciudadorigen" class="tickets-imputs">Ciudad de Origen</label>
<select name="ciudadorigen" class="form-control ciudadorigen tickets-imputs" for="ciudadorigen">
<option selected disabled>1</option>
<option value="562">2</option>
<option value="582">3</option>
</select>
</div>
</div>
<!-- Here goes the rest of the form -->
<a type="submit" class="btn btn-warning waves-effect btn-block" href="javascript:{}" onclick="document.getElementById('consultatickets').submit();">Buscar <i class="fa fa-search" aria-hidden="true"></i></a>
</div>
I don't know how to extract the just the values from the variables and append to the URL.
If the order doesn't matter, you can achieve this by serializing the values of the form and appending it to the action attribute of the form to build the final url.
<form id="consultatickets" name="consultatickets" role="form" method="get" class="tickets-form" action="http://thisistheurl.com/serv#search" target="_blank">
<div class="row">
<div class="form-group col-md-12 col-sm-12">
<label for="ciudadorigen" class="tickets-imputs">Ciudad de Origen</label>
<select name="ciudadorigen" class="form-control ciudadorigen tickets-imputs" for="ciudadorigen">
<option selected disabled>1</option>
<option value="562">2</option>
<option value="582">3</option>
</select>
<label for="campo_adicional">Campo adicional</label>
<input id="campo_adicional" type="text" name="campo_adicional" />
</div>
</div>
<input type="submit" value="search"/>
</form>
$("#consultatickets").on('submit',
function(e) {
e.preventDefault();
var values = $(this).serializeArray();
var baseUrl = $(this).prop("action");
$.each(values, function(i, v) {
baseUrl += "/" + encodeURIComponent(v.value);
});
alert(baseUrl);
}
);
https://jsfiddle.net/kb3rvLjs/
Untested and I'm not sure if I got your question correctly but it seems you look for something like this:
// your form submit event handler
function formSubmit() {
var form = $('#consultatickets');
// build your url
var url = 'http://thisistheurl.com/serv#search/' +
getValues(form).join('/');
// redirect to your new location
location.href = url;
};
// function to get the values from the form elements
function getValues(form) {
// get all form fields in the form
var fields = $( "input, select", form);
var values = [];
// loop over the fields, add them to array
jQuery.each( fields, function( field ) {
values.push(encodeURI(field.val()));
});
return values;
}
In case you want to trigger the form submit with the a tag, simply change your onclick attribute to: onclick ="formSubmit();".