new FormData works on one site but not on other - yii2

In my previous project I have:
let send = (form) => {
form = $(form)
...........
$.ajax({
method: 'post',
url: form.attr('action'),
data: new FormData(form[0]),
contentType: false,
processData: false
})
..........
return false
}
And my form looks like:
<?php $form = \yii\widgets\ActiveForm::begin([
'id' => 'w0',
'action' => 'site/send-contact',
'fieldConfig' => [
'options' => [
'tags' => false
]
]
]) ?>
................ some fields ............
\yii\widgets\ActiveForm::end(); ?>
Here, using the new FormData(..) works totally fine. You can check it here in the console networks tab. I have added var_dump($_POST) in the action. Now on my new project, new FormData(..) doesn't work. Absolutely no idea why. The dumped array is empty.
$.ajax({
method: 'get',
url: 'site/index',
data: {
data: new FormData($("#w0")[0])
},
})
And the form:
$form = \yii\bootstrap\ActiveForm::begin();
........... some fields here ............
\yii\bootstrap\ActiveForm::end()
Tried with post,get,contentType,processData just for any case but still empty array. Any suggestions? Thank you!

You can use Form submit event to submit form using ajax:
jQuery(document).ready(function($) {
$(".formclass").submit(function(event) {
event.preventDefault(); // stopping submitting
var data = $(this).serializeArray();
var url = $(this).attr('action');
$.ajax({
url: url,
type: 'post',
dataType: 'json',
data: data
})
.done(function(response) {
if (response.data.success == true) {
alert("Wow you commented");
}
})
.fail(function() {
console.log("error");
});
});
});
For more info

Related

I am getting error sending status code in laravel apide

When sending response code in laravel api, validation does not enter.
I can view it from the network, but when I send the status code, the console prints an error and I cannot print the validations on the blade page. If I don't send status code I can print validations.
Following my code: StudentController
public function store(Request $request): object
{
$validate = Validator::make($request->all(),[
'name' => 'required',
'course' => 'required',
]);
$data = [
'name' => $request->name,
'course' => $request->course,
];
if ($validate->fails()){
return response()->json(['success' => false, 'errors' => $validate->messages()->all()],422);
}
Student::insert($data);
return response()->json(['success' => true, 'message' => "Registration Successful"]);
}
ajax
$(document).ready(function (){
$('#createBtn').on('click',function (e) {
e.preventDefault();
let form = $('#student-add').serialize();
$.ajax({
'url': "{{ route('students.store') }}",
'data': form,
'type': "POST",
success:function (result) {
$('#ajax-validate ul').text("");
if(result.success === true){
console.log("True");
}else {
result.errors.forEach(function (item) {
$('#ajax-validate ul').append('<li>'+item+'</li>');
});
}
}
});
});
});
console
network
You have your response.errors.forEach inside of your success: function(), but 422 (or any 400) code doesn't get handled by the success function, but rather the error function:
$(document).ready(function () {
$('#createBtn').on('click', function (e) {
e.preventDefault();
let form = $('#student-add').serialize();
$.ajax({
url: "{{ route('students.store') }}",
data: form,
type: 'POST',
success: function (result) {
if (result.success === true) {
// Do whatever on `2XX` HTTP Codes
}
},
error: function (response) {
if (response.status === 422) {
let responseJson = response.responseJSON ? response.responseJSON : { errors: [] };
$('#ajax-validate ul').text('');
responseJson.errors.forEach(function (item) {
$('#ajax-validate ul').append('<li>'+item+'</li>');
});
} else {
console.log('Unhandled Error:', response)
}
}
});
});
});
Now when an 422 error is explicitly triggered, you code can properly handle the validation errors.

Codes are displayed instead of html elements

I have called ajax request in some interval of time. Now, if I pressed the back button after success ajax then, the browser displayed all of my HTML code instead of displaying HTML elements.
<script>
window.setInterval(function () {
$.ajax({
method: 'GET',
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
url: '{{route('devices.index')}}',
dataType: 'json',
success: function (data) {
}
});
}, 1000);
</script>
if($request->ajax()){
foreach ($devices as $device){
$latestUpdate = Carbon::parse($device->updated_at);
$diff = Carbon::now()->diffInMinutes($latestUpdate);
if($diff > 2){
Device::where('id',$device->id)->update(['status'=>'3']);
}
}
return response()->json(['msg' => "successfully checked"]);
}
I had expected to render the HTML elements, but it displayed.
{
"msg": "successfully checked"
}
Same things happened when I send HTML in json.
if($request->ajax()){
$returnHtml = view('alerts.index', compact('threshold'))
->with('alerts', $alerts)->render();
return response()->json(['html' => $returnHtml, 'data' => $alerts]);
}
window.setInterval(function () {
$.ajax({
method: 'GET',
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
url: '{{route('alerts.index')}}',
dataType: 'json',
success: function (data) {
var formatedhtml = $('<div>').html(data.html).find('table');
$('table').html(formatedhtml);
}
});
}, 5000);
In this case it display
Instead of returning as json return data as array:
Try something like this
return ['html' => $returnHtml, 'data' => $alerts];
There's nothing wrong with how you are receiving the data when you use return response()->json(['html' => $returnHtml, 'data' => $alerts]);
If you want to actually put the html that you received from your server into an element in your page, you will need to use Element.innerHTML (https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML) so that the html will not be escaped by the browser.
window.setInterval(function () {
$.ajax({
method: 'GET',
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
url: '{{route('devices.index')}}',
dataType: 'json',
success: function (data) {
// this is the table where you want to place the received table contents
var my_table=$('#my-table')
// we turn the data we received from the server into a jQuery object, then find the table we want data from
var received_table=$(data.html).find('table')
// switch out the table contents
my_table.html(received_table.html())
}
});
}, 1000);
EDIT: Since you are using jQuery, I changed the answer to fit.

Action not found after AJAX request

Before for submitting I want to send the request to an action. But in return I get 404 not found. The action is obviously there. Also got it in the filters of the controller.
JS:
$('#home-contact').on('beforeSubmit', function(){
$.ajax({
method: 'post',
url: '/site/send-contact',
data: new FormData($(this))[0],
success: function(data){
console.log(data)
}
})
return false
})
Controller filters:
'access' => [
'class' => AccessControl::className(),
'only' => ['logout', 'signup', 'send-contact'],
'rules' => [
[
'actions' => ['signup', 'send-contact'],
'allow' => true,
'roles' => ['?'],
],
[
'actions' => ['logout'],
'allow' => true,
'roles' => ['#'],
],
],
],
And the action also :
public function actionSendContact()
{
Yii::$app->response->format = Response::FORMAT_JSON;
$model = new Contact();
if($model->load(Yii::$app->request->post()) && $model->save()){
return $data['success'] = Yii::t('app', 'Successfully sent message.');
}
return $data['error'] = Yii::t('app', 'Something went wrong. Please try again.');
}
The scenario happens in the frontend if that matters somehow. Thank you!
Not sure about the 404 you are having as the url in the request is correct and the url that would be generated for the ajax request will be like http://example.com/site/send-contact but only if you are using the 'enablePrettyUrl' => true, for the urlManager component, otherwise it should be like index.php?r=site/index that could only be the reason behind the 404, a better way is to get the url from the form action attribute.
Apart from above,
You are using the new FormData() to send the data with the request like
data: new FormData($(this))[0]
which isn't correct and won't send any FormData with the request as it will return undefined, you can check the console or by using the print_r($_POST) inside the action sendContact once you are done with the 404, it should be
data: new FormData($(this)[0]),
you need to get the form via $(this)[0] and pass to the new FormData().
But this is not enough you have to set the contentType and processData to be false to correctly submit the FormData or you will get the exception in console
Uncaught TypeError: Illegal invocation
So your code should be like
$('#contact-form').on('beforeSubmit', function(){
let url=$(this).attr('action');
let form=$(this)[0];
let data=new FormData(form);
$.ajax({
method: 'post',
url: url,
data:data,
contentType: false, // NEEDED, DON'T OMIT THIS (requires jQuery 1.6+)
processData: false,
success: function(data){
console.log(data)
}
});
return false;
})
EDIT
Note: Above all you should use data:$(form).serialize() simply rather than using new FormData() until unless you are planning to upload files along with the form using ajax.
URL in JavaScript seems to be not fully specified.
The valid way would be:
url: 'index.php?r=site/send-contact',
But this works only if your index.php is in root folder.
To make it work with any situation (e.g., index.php is not in root), then you have different solutions. I personally like to use this:
Declare action and id in your form:
Example:
$form = ActiveForm::begin([
'action' => ['site/send-contact'],
'id' => 'my-form',
]);
Use a link (that is generated by Yii2 itself) in your JS code:
Example:
$('#home-contact').on('beforeSubmit', function() {
$.ajax({
method: 'post',
url: $('#my-form').attr('action'),
data: new FormData($(this))[0],
success: function(data) {
console.log(data)
}
});
return false;
});
This should work in all cases, whenever your files are.
Hope that helps!
did you add 'enableAjaxValidation' => true or add action name in active form?
$form = ActiveForm::begin([
'action' => ['controller/action'],
'enableAjaxValidation' => true
]);

Populate text box with Json data

Please see my below code,
Controller -
public ActionResult AmountOwed()
{
int vehicleID = Convert.ToInt32(Request.Cookies["VehicleID"].Value);
var amountOwed = _PUSPERSContext.TblEOYPayments.Where(x => x.VehicleID == vehicleID).OrderByDescending(x => x.PaymentID).Take(1).Select(x => x.AmountOwed).ToList().FirstOrDefault();
return Json(amountOwed, JsonRequestBehavior.AllowGet);
}
This gives me the value I want but I now want to display it in a textbox in a partial view (_EOYPaymentsLayout.cshtml) -
<div class='form-group'>
#Html.LabelFor(m => m.TblEOYPayment.AmountOwed, new { title = "Amount Owed" })
#Html.TextBoxFor(m => m.TblEOYPayment.AmountOwed, new { title = "Amount Owed", #class = "form-control inputSizeMedium"})
</div>
I have have tried various things in my ajax code but I can never get the value into the view (this code is in the main view called Payments) -
$(document).ready(function () {
$('#addEOYPayment').click(function () {
$.ajax({
type: "GET",
url: "AmountOwed",
datatype: "Json",
success: function (data) {
$('#TblEOYPayment_AmountOwed').html(data.amountOwed);
}
});
});
});
Would be grateful for some advice. Thanks
Instead of return a json object, you can return a partial view
C#
public ActionResult AmountOwed()
{
int vehicleID =
Convert.ToInt32(Request.Cookies["VehicleID"].Value);
var amountOwed = _PUSPERSContext.TblEOYPayments.Where(x => x.VehicleID == vehicleID).OrderByDescending(x => x.PaymentID).Take(1).Select(x => x.AmountOwed).ToList().FirstOrDefault();
return PartialView("NameOfView.cshtml", amountOwed );
}
js
$(document).ready(function () {
$('#addEOYPayment').click(function () {
$.ajax({
type: "GET",
url: "AmountOwed",
datatype: "Json",
success: function (data) {
$('#TblEOYPayment_AmountOwed').html(data.responseText);
}
});
});
});
and your view may receive the type of thevariable amountOwed.
You must double check your url. Please do include the controller name. For an instance: URL: "\Home\AmountOwed\" + ID,
Thanks for the replies.
Finally got it working, it was just this:
$(document).ready(function () {
$('#addEOYPayment').click(function () {
$.ajax({
type: "GET",
url: "/Home/AmountOwed",
datatype: "Json",
success: function (data) {
$('#TblEOYPayment_AmountOwed').val(data);
}
});
});
});

no display fail message from controller

I need validate user's nickname when the gonna registre in my proyect:
My Controller
$inputData = Input::get('nickname');
parse_str($inputData);
$informacion = array('nickname' => $inputData);
$regla = array('nickname'=>'required|unique:usuarios|alpha_num|min:6|max:15');
if($request->ajax()){
$usuarios = Usuarios::Usuarios();
$validar = Validator::make($informacion,$regla);
if($validar->fails()){
return Response()->json(array(
'fail' => true,
'errors' => $validar->getMessageBag()->toArray()));
}
else{
return Response()->json(array('success' => true, "message" => "Nombre de Usuario Disponible"));
}
}
My Script
$( "#validar" ).click(function( event ) {
var dato = $('#nickname').val();
var route = $('#form-sign-up').attr('action');
var tipo = $('#form-sign-up').attr('method');
var token = $('#form-sign-up #token').val();
$.ajax({
url: route,
headers: {'X-CSRF-TOKEN': token},
type: tipo,
dataType: 'json',
data:{nickname: dato},})
.fail(function(data){
$('#nickname-msj').html(data.errors);
$('#nickname-msj').fadeIn();
})
.done(function(data) {
$('#nickname-msj').html(data.message);
$('#nickname-msj').fadeIn();
});
});
.done works, but .fails not, and i need display that information to my user, because so they can know what is the problem, if someone can help me will be great.
I am using Laravel 5.2
Thank you.
The fails function of Ajax is triggered with a code different from 200. So you can return
if($validar->fails()) {
return response()->json($arrayHere, 400); //HTTP 400 error for bad request
}
So, just basically add 400 after your array, inside of json() function. When you don't specify the code, it defaults to 200.
Maybe also change your ajax request ? Or not
$.ajax({
url: route,
headers: {'X-CSRF-TOKEN': token},
type: tipo,
dataType: 'json',
data:{
nickname: dato
},
success: function (data) {
console.log(data);
},
error: function (data) {
console.log('Error:', data);
}
});