I often use the patchEntity function to hydrate my entity with form data, and it works fine, even with an ajax request.
But when I tried to insert data from an an ajax request with JSON data, patchEntity failed to retrieve the data.
My ajax request is very simple:
var rate = function (user, rate, success, error) {
$.ajax({
type: "POST",
url: baseUrl + 'rate/add',
data: {
id: this.id,
user: user.id
rate: rate
},
dataType: 'json',
success: success,
error: error
});
});
In my Rate controller, my add function looks like:
public function add()
{
if ($this->request->isAjax()) {
$this->layout = 'ajax';
$rate = $this->Rate->newEntity();
if ($this->request->is('post')) {
$rate = $this->Rate->patchEntity($rate, $this->request->data);
if ($rate->errors()) {
$this->set([
'status' => 500,
'message' => $rate->errors()
]);
} else {
if ($this->rate->save($rate)) {
$this->set([
'status' => 200
]);
} else {
$this->set([
'status' => 500,
'message' => $rate->errors()
]);
}
}
return $this->render('/Ajax/result');
}
}
This throw an exception:
Cannot insert row, some of the primary key values are missing. Got (,
, ), expecting (id, user)
I can save my data using this instead of $this->Rate->patchEntity($rate, $this->request->data);
$rate['id'] = $this->request->data['id'];
$rate['user'] = $this->request->data['user'];
$rate['rate'] = $this->request->data['rate'];
What sort of array do I have to pass to patchEntity function to makes this works?
Thanks to ndm's comment, I've checked the Rate Entity and just removed this part which was automatically generated by bake:
protected $_accessible = [
'rate' => true,
];
Related
I have the below ajax js. I am trying to make a POST to my controller with the id . In the line starting with let id ... when I log it to console, I can see the id number but the controller doesn't receive it. Also in XHR/payload I see [object Object] which do not know why.
$(document).on('click', '.delete-task', function(event){
// id comes from data-id
let id = $(event.currentTarget).attr('data-id');
$.ajax({
url: ajaxUrl+'/admin/tasks/delete',
type: 'POST',
// what data you passing.
data: {
'id' : id
},
processData: false,
contentType: false,
dataType: 'json',
success: function(data) {
console.log(data);
}
});
});
Route is; $routes->match(['get', 'post'], '/admin/tasks/delete', 'Admin\Task\Task_Controller::task_delete');
For my controller, I have the below. As it is a post, I expect to be able to get the id by using $this->request->getVar('id') but doesn't work. I always get 'success' => '0 'msg' => "No Task To Delete" returned. Any pointers appreciated.
```
public function task_delete(){
$id = $this->request->getVar('id');
if(empty($id)){
$response = [
'success' => 0,
'msg' => "No Task To Delete",
];
echo json_encode($response);
} else {
$task = new TaskModel();
$task->task_delete($id);
$response = [
'success' => 1,
'msg' => "Task Deleted",
];
echo json_encode($response);
}
}```
So I can see id=103 in the payload in the console but for somereason but reaching the controller. Interesting also is when I log log_message('error', $request->getMethod()); it is a critical error as blank. Even log_message('error', $request->isAjax()); is critical error as blank.
I'm working on a project in CodeIgniter4. I'm trying to make an Ajax call to an endpoint (/adjustments/store). I'm validating the form using CodeIgniter and showing the validation errors in my view. The issue is when the first time, i submit the form, it works and shows some validation errors. But when i fill the form correclty (to get not validation errors) and resubmit it again it gives me 403 forbidden error in the console.
Ajax call
$.ajax({
type: 'post',
url: '/adjustments/store',
dataType: 'html',
data: {
number,
date,
type,
account,
description,
adjData,
csrf_test_name
},
success: function (res) {
if (IsJsonString(res)) {
const response = JSON.parse(res);
if (response.hasOwnProperty('validation_errors')) {
const errors = response.validation_errors;
for (err in errors) {
$(`input[name=${ err }]`)
.parent()
.append(`<small class="text-danger">${ errors[err] }</small>`)
}
}
}
function IsJsonString(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
console.log(res);
}
CodeIgniter Controller
public function store () {
$data = $this->request->getPost(NULL);
// Validate
if (! $this->validate([
'number' => 'required',
'date' => 'required',
'type' => 'required',
'adjData' => 'required',
]))
{
echo json_encode(['validation_errors' => $this->validator->getErrors()]);
return;
}
echo json_encode($data);
}
Any solution to this?
If you are resubmitting a form then you have update csrf token on every request with ajax.
Whenever validation fails pass csrf token and update it every time.
In your controller -
public function store () {
$data = $this->request->getPost(NULL);
// Validate
if (! $this->validate([
'number' => 'required',
'date' => 'required',
'type' => 'required',
'adjData' => 'required',
]))
{
echo json_encode(['validation_errors' => $this->validator->getErrors(), 'csrf' => csrf_hash()]);
return;
}
echo json_encode($data);
}
In you ajax -
$.ajax({
type: 'post',
url: '/adjustments/store',
dataType: 'html',
data: {
number,
date,
type,
account,
description,
adjData,
csrf_test_name
},
success: function (res) {
if (IsJsonString(res)) {
const response = JSON.parse(res);
$("input[name='csrf_test_name']").val(response ["csrf"]);
if (response.hasOwnProperty('validation_errors')) {
const errors = response.validation_errors;
for (err in errors) {
$(`input[name=${ err }]`)
.parent()
.append(`<small class="text-danger">${ errors[err] }</small>`)
}
}
}
function IsJsonString(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
So once you update csrf then it will work fine.
Thanks.
I've got 6 different routes that can be chosen from an input select. Each selected route then posts to its own database.
The problem is I get a 500 error back for all of them, but on half of them, it actually posts to the database. I've gone through line-by-line, and other than the variable names, the code is identical. Here's an example of one that doesn't work at all.
submit.js
$('#submit-event').on('click', function() {
event.preventDefault()
let title = $('#title').val()
let type = $('#type').val() // for selecting which DB
let start = $('#start').data('DateTimePicker').date()
let end = $('#end').data('DateTimePicker').date()
let data = {
'_token': token,
'title': title,
'start': start,
'end': end
}
console.log(type); // logs the correct POST route
$.ajax({
method: 'POST',
url: type,
data: data,
success: function(data) {
console.log(data);
},
error: function(err) {
console.log(err)
}
});
})
routes.php
Route::post('/createmeeting', [
'uses' => 'MeetingController#postCreateMeeting',
'as' => 'createmeeting'
]);
MeetingController.php
class MeetingController extends Controller
{
// Get Meeting from DB - works
public function getMeetings()
{
$meetings = Meeting::orderBy('created_at', 'desc')->get();
return $meetings;
}
// Add new Meeting to DB - doesn't work (500 error)
public function postCreateMeeting(Request $request)
{
if (!request['_token']) {
return redirect()->route('calendar')->with(['message' => "You must be logged in"]);
}
// Save Meeting
$meeting = new Meeting();
$meeting->title = $request['title'];
$meeting->start = $request['start'];
$meeting->end = $request['end'];
if ($request->user()->meetings()->save($meeting)) {
$message = 'Event successfully added to calendar';
return redirect()->route('calendar')->with(['message' => $message]);
}
return redirect()->route('calendar')->with(['message' => $message]);
}
}
Responses to similar problems suggest a problem with the token, but I test for that here. Any idea where the mistake could be happening?
There is my form:
$form = ActiveForm::begin([
'id' => 'user-create-form',
'enableAjaxValidation' => true,
'enableClientValidation' => false,
'validationUrl' => Url::toRoute(Yii::$app->controller->id . '/validation'),
'validateOnType' => true,
]);
JS-script is registered on this form and performed Russian to English transliteration according to some rules on .keyup() event. Transliteration result is added to samname field.
There is validation rule in UserCreateForm model:
public function rules()
{
return [
[['samname'], 'validateUserExist'],
];
}
public function validateUserExist()
{
$check = Yii::$app->CustomComponents->checkUserExist($this->samname);
if ($check) {
$errorMessage = 'User exists: ' . $check;
$this->addError('samname', $errorMessage);
}
}
Function checkUserExist() checks existing of created name and returns an error in matching case.
There is action on controller:
public function actionValidation()
{
$model = new UserCreateForm();
if (\Yii::$app->request->isAjax && $model->load(\Yii::$app->request->post())) {
\Yii::$app->response->format = Response::FORMAT_JSON;
echo json_encode(ActiveForm::validate($model));
\Yii::$app->end();
}
}
It works great, validation is performed, matching case returns an error...
But!
It's required that JS-script is run again and added next letter to the name on error (JS-script provides this functionality). How to run JS-script again after validator was return an error?
#yafater Thanks for help! I find solution.
$('form').on('afterValidateAttribute', function (event, attribute, message) {
if (attribute.name === 'samname')
{
$.ajax({
url: "url-to-action",
type: "POST",
dataType: "json",
data: $(this).serialize(),
success: function(response) {
if ( typeof(response["form-samname"]) != "undefined" && response["form-samname"] !== null ) {
// code here
}
},
});
return false;
}
});
I am sending values from view to controller
Here is my Script :
<script>
$(document).ready(function() {
var vehicle_data = [];
$("#vehicle_submit").click(function(event) {
event.preventDefault();
vehicle_data.push($("#_token").val());
vehicle_data.push($("#VehicleNo").val());
vehicle_data.push($("#VehicleName").val());
$.ajax({
type: "POST",
url: "{{ URL::to('vehicle-process') }}",
data: "vehicle_arr=" + vehicle_data,
async: true,
success: function(data) {
console.log(data);
}
}, "json");
});
});
</script>
I am sending the values VehicleNo and VehicleName to the vehicle-process controller as a single array named as vehicle_arr using POST Method.
Now in the controller :
public function vehicle_process()
{
$a = Input::except(array('_token')) ;
$rule = array(
'VehicleNo' => 'required',
'VehicleSeats' => 'required'
);
$validator = Validator::make($a, $rule);
if ($validator - > fails()) {
$messages = $validator - > messages();
return $messages;
}
else
{
$table = new VehicleModel;
$table->VehicleNo=$VehicleNo; // How can i get the value of VehicleNo and Vehcle Name
$table->save();
}
The Validator can't able to analyze the name of the element i.e., VehicleNo or VehicleSeats,
So whenever i pass the data from view it was showing VeihcleNo required validator messages all the time.
Can i make the validator like
$rule = array(
$a['VehicleNo'] => 'required',
$a['VehicleSeats'] => 'required'
);
as i am storing the all the values in $a.
I even tested return $a; to view all elements in the controller it shows like
Object {vehicle_arr: "wBNTzuTY20GL6BR147TIM9l8mxpCbgMAM7ok7fD4,EZ-55,35"}
Is it possible to get values like
$value = Input::post('VehicleNo');
So, How can i get the values extract so that i can done with the validation and store in db
My Model just has the Table Name
So i just need the way to get the value of $VehicleNo to store in db. So that i can construct this
$table->VehicleNo=$VehicleNo;
$table->save();
Update : It is ok even if i change the method to POST to GET in order to achieve my Result