I have a problem with updating database using AJAX and CodeIgniter. When someone posts AJAX form I retrieve data about user from database this way:
class MY_Controller extends CI_Controller
{
public $memberData;
public function __construct()
{
parent::__construct();
$this->memberData= $this->membermodel->getmemberData();
}
}
(Every controller extend MY_Controller, not CI_Controller).
Then I operate on user data and insert it to database. The problem is that if I send AJAX post really fast (few at same time), few inserted rows are identical (except auto-increment row ID). It looks like CodeIgniter did not receive new user data from database (or don't update it before), and I operate on old one.
I send AJAX like this:
$("#form_id").submit(function(event)
{
$form = $(this);
$.post($form.attr('action'), $(this).serialize(), function(HTML)
{
//do something
});
return false;
});
then I operate on something like this:
$CI =& get_instance();
$CI->load->model('membermodel', 'member');
$variab['value3'] = $CI->memberData->member_value3 + 1; //this is the line that need to be new on every call, but it doesnt
$variab['result'] = $this->calculatedata($variab['value3']);
$parameters = array(
'member_value3' => $variab['value3']
);
//update that variable to database, so it should have new value new on next call
$CI->member->updateinfo($parameters);
return $variab['value3'];
At the end I get that value3, base on it my whole script and insert last query to database. Unfortunately like I said if I send many POST requests in the same time that value is constant.
I use this, it should work out of clipboard, I found it a while ago on SO don't remember the source. (will search for it) source.
Please do read comments and do debug using console.
var r;
$("#form_id").submit(function(event){
if (r) {
r.abort(); //abort all previous requests
}
var $form = $(this);
var $inputs = $form.find("input, textarea, select, button"); //serialize all elements in form
var serializedData = $form.serialize(); //serialize data (prep data)
$inputs.prop("disabled", true); //disable inputs
r = $.ajax({
url: $form.attr('action'), //whatever.php
type: "post",
data: serializedData
});
// Callback handler that will be called on success
r.done(function (response, textStatus, jqXHR){
console.log("Form works: " + response);
});
// Callback handler that will be called on failure
r.fail(function (jqXHR, textStatus, errorThrown){
console.error(
"Error: "+
textStatus, errorThrown
);
});
r.always(function () {
$inputs.prop("disabled", false); //enable inputs
});
// Prevent default posting of form
event.preventDefault();
});
Regard to comment: But if somebody change this JS code he still will be able to bug my whole script, I have to get it secured.
Please consider following order of developing.
create form using HTML
create php file that accepts this form and VALIDATES it; debug all possible inputs etc.
create AJAX part
style using CSS, show errors etc.
This way you will never (rarely) have problems in matter you just did.
Related
I am trying to validate list of dynamic text fields.
Validation needs an AJAX call to interact with server.
At the backend I have written just one php file that reads the input request data and performs operation. Below is the example.
abc.js
row_count = 6
for (i = 1; i <=row_count; i++) {
id = "#val"+i.toString() ;
$(id).change(function(){
input_val="random";
$.ajax({
url:"url.php",
type:post,
async:true,
dataType: 'json',
data : {temp:input_val},
success:function(result){},
error: function (request, status, error) {}
});
});
}
url.php
<?php
$random_val = $_POST['temp'];
$cmd = 'systemcommand '.$random_val;
$flag = exec($cmd);
if ($flag == 0){
echo json_encode(array("status"=>'Fail'));
}
else{
echo json_encode(array("status"=>'Success'));
}
?>
It works fine when the row_count = 1 (Just one text field) but fails when the input is more than 1.
When the count is more than 1, the php script is not able to read the request data(The key in JSON data "temp"). it is blank in that case.
Any lead or help should be appreciated.
Thanks
Your javascript bit needs some adjusting, because you do not need to define an ajax for every single element. Use events based on a class. Also, since input behave differently than select, you should setup two different event class handlers.
function validateAjax ( element ) {
var input_val = element.val();// get the value of the element firing this off
$.ajax({
url: "url.php",
type: 'post',
async: true,
dataType: 'json',
data : { temp: input_val },
success: function(result) {
// check your result.status here
},
error: function (request, status, error) { }
});
}
$(".validate_change").on("change",function() { // for selects
validateAjax( $(this) );
});
$(".validate_input").on("input",function() { // for text inputs
validateAjax( $(this) );
});
And for your select or input you add that appropriate class.
<select class="validate_change" name="whatever"><options/></select>
<input class="validate_input" name="blah">
PS
I really worry about this code you have:
$cmd = 'systemcommand '.$random_val;
$flag = exec($cmd);
So, you are just executing anything that is coming in from a webpage POST var??? Please say this website will be under trusted high security access, and only people using it are trusted authenticated users :-)
I'm using Laravel 5.2. On my index page, I've got a button to add a new entry, which brings up the form in a lightbox. This form then submits via the create method.
I also have each entry listed on this page, with the ability to edit them inline, which submits via the update method.
I've setup validation via a Request. This means when someone misses something on the add, it redirects to the index method with errors. The errors only show though, when the lightbox is triggered by the user.
I know I can use $errors to see any errors, but I don't see how I can differentiate between the create and update forms for the sake of forcing the lightbox to appear on reload with create errors. Is there a way to do that?
Update:
Suggestion was made to use AJAX to bypass the reload issue, but now I'm getting a 422 return:
AJAX call:
(function(){
var submitAjaxRequest = function(e){
var form = $(this);
var method = form.find('input[name="_method"]').val() || 'POST';
$.ajax({
type: method,
url: form.prop('action'),
data: form.serialize(),
success: function(data){
console.log(data)
}
});
e.preventDefault();
}
$('form[data-remote]').on('submit', submitAjaxRequest);
})();
Request:
public function response(array $errors)
{
$response = parent::response($errors);
if ($this->ajax() || $this->wantsJson()) {
return $response;
}
return $response->with('requestMethod', $this->method());
}
I've also tested the ajax call and it works fine when the validation rules are met. It only fails if the validation comes back with something incorrect in the input.
You could override the response method so that you can flash the type of request.
In you Request class you could add
public function response(array $errors)
{
$response = parent::response($errors);
if ($this->ajax() || $this->wantsJson()) {
return $response;
}
return $response->with('requestMethod', $this->method());
}
(With ajax you wouldn't need to worry about the page reload so we can just return the original response.)
In the above I'm assuming you're using POST for your create methods and PUT or PATH for your update methods. If this is not the case you could use a way that make sense to you to differentiate between the requests.
Then in your view you could do something like:
#if(session('requestMethod') == 'POST')
https://laravel.com/docs/5.2/responses#redirecting-with-flashed-session-data
If you are going to use ajax, as I mentioned in the comment above, you will need to make sure you use the error method within the ajax call:
$.ajax({
type: method,
url: form.prop('action'),
data: form.serialize(),
success: function (data) {
console.log('success', data)
},
error: function (data) {
console.log('error', data)
}
});
Hope this helps!
At this moment I am using laravel. In this context I am having a form which is successfully submitted by using ajax to a controller. and that controller make it to the database. But the problem is as the ajax is doing its job the whole page remain unmoved / unchanged after the submission even the database is updated.
Now what I want
I want to give feedback to the user that your post is successfully submitted there. or what I want to do in further, I want to refresh the section in which the post is collected from the database as this post can be retrieved from there. But by using ajax only.
So there is no need to collect the whole page or refresh.
here is my form structure
`
{{ Form::open(array('route' => array('questions.store'), 'class' => 'form-horizontal' )) }}
blah blah blaaa .......
<script type="text/javascript">
$(".form-horizontal").submit(function(e){
$(this).unbind("submit")
$("#ask").attr("disabled", "disabled")
var that = $(this),
url = that.attr('action'),
type = that.attr('method'),
data = {};
that.find('[name]').each(function(index, value){
var that = $(this),
name = that.attr('name'),
value = that.val();
data[name] = value;
});
$.ajax({
url: url,
type: type,
data: data,
success: function(response){
console.log(response);
}
});
return false;
});
</script>
{{ Form::close() }}
`
As it is very much visible that the post is updated through a route & controller I want to have another dive and a success message at this script to be displayed after the success of posting. I am looking for some professional structure using what there is minimal need to have interaction with the server side and give user a better page viewing experience.
Thanks a lot for helping me in this research.
I am not sure if I understand you well, but if you want to notify the user about the result of an ajax-called db update you need to have
a route for the ajax save db call - it should point to a method that does the db update.
the db update method should return some value indicating the success/failure of update (for example OK or FAIL)
the only result of calling the method will be just plain text page with OK or FAIL as body
fetch the result by ajax and inform user accordingly (after form submit button)
check out the below code for ajax call itself (inside the form submit handler) to see what I mean
var db_ajax_handler = "URL_TO_YOUR_SITE_AND_ROUTE";
var $id = 1; //some id of post to update
var $content = "blablabla" //the cotent to update
$.ajax({
cache: false,
timeout: 10000,
type: 'POST',
tryCount : 0,
retryLimit : 3,
url: db_ajax_handler,
data: { content: $content, id: $id }, /* best to give a CSRF security token here as well */
beforeSend:function(){
},
success:function(data, textStatus, xhr){
if(data == "OK")
{
$('div.result').html('The new Question has been created');
}
else
{
$('div.result').html('Sorry, the new Question has not been created');
}
},
error : function(xhr, textStatus, errorThrown ) {
if (textStatus == 'timeout') {
this.tryCount++;
if (this.tryCount <= this.retryLimit) {
//try again
$.ajax(this);
return;
}
return;
}
if (xhr.status == 500) {
alert("Error 500: "+xhr.status+": "+xhr.statusText);
} else {
alert("Error: "+xhr.status+": "+xhr.statusText);
}
},
complete : function(xhr, textStatus) {
}
});
EDIT: as per comment, in step 2 (the method that is called with AJAX) replace
if($s)
{
return Redirect::route('questions.index') ->with('flash', 'The new Question has been created');
}
with
return ($s) ? Response::make("OK") : Response::make("FAIL");
EDIT 2:
To pass validation errors to the ajax-returned-results, you cannot use
return Response::make("FAIL")
->withInput()
->withErrors($s->errors());
as in your GIST. Instead you have to modify the suggested solution to work on JSON response instead of a plain text OK/FAIL. That way you can include the errors in the response and still benefit from the AJAX call (not having to refresh the page to retrieve the $errors from session). Check this post on the Laravel Forum for a working solution - you will get the idea and be able to fix your code.
I have a function which saves an array each time the button is clicked to localStorage.The button will be clicked multiple times and I need to put this Array list into PHP somehow which is on another page from this file.
Thanks
a.js
(this function listens onLoad of the page)
function doFirst(){
var button = document.getElementById("button");
button.addEventListener("click", save, false);
var buttons = document.getElementById("clear");
buttons.addEventListener("click", clear, false);
var buttonss = document.getElementById("submittodb");
buttonss.addEventListener("click", toPHP, false);
$.ajax({
method: 'post',
dataType: 'json',
url: 'edit.php',
data: { items: oldItems }, //NOTE THIS LINE, it's QUITE important
success: function() {//some code to handle successful upload, if needed
}
});
}
function save(){
var oldItems = JSON.parse(localStorage.getItem('itemsArray')) || [];
var newItem = {
'num': document.getElementById("num").value,
'methv': document.getElementById("methv").value,
'q1': document.getElementById("q1").value,
'q2':document.getElementById("q2").value,
'q3':document.getElementById("q3").value,
'q4':document.getElementById("q4").value,
'comm':document.getElementById("comm").value,
};
oldItems.push(newItem);
localStorage.setItem('itemsArray', JSON.stringify(oldItems));}
edit.php
$parsed_array = json_decode($_POST['items']);
and i get the error: Notice: Undefined index: items in /home/project/edit.php on line 9
In order to pass this array to PHP you need to:
JSon-encode it
Make an AJAX or POST request to PHP
Parse the passed array into PHP array
If you're using jQuery (if you're not you should start - it is really handy tool) steps (1) and (2) is as simple as
$.ajax({
method: 'post',
dataType: 'json',
url: 'the URL of PHP page that will handle the request',
data: { items: oldItems }, //NOTE THIS LINE, it's QUITE important
success: function() {//some code to handle successful upload, if needed
}
});
In PHP you can parse the passed array with just
$parsed_array = json_decode($_POST['items']);
There is a direct connection between { items: oldItems } and $_POST['items']. The name of variable you give to the parameter in javascript call will be the name of key in $_POST array where it ends up. So if you just use data: oldItems in javascript you'll have all your entities scattered around the $_POST array.
More on $.ajax, and json_decode for reference.
You can create an AJAX function (use jQuery) and send the JSON data to the server and then manage it using a PHP function/method.
Basically, you need to send the data from the client (browser) back to the server where the database hosted.
Call JSON.stringify(oldItems); to create the json string
Do a Do a POST request using AJAX.
Probably the simplest way is using jQuery:
$.post('http://server.com/url.php', { items: JSON.stringify(oldItems) }, function(response) {
// it worked.
});
I have a form that uses ajax to submit data to a mysql database, then sends the form on to PayPal.
However, after submitting, if I click the back button on my browser, change some fields, and then submit the form again, the mysql data isn't updated, nor is a new entry created.
Here's my Jquery:
$j(".submit").click(function() {
var hasError = false;
var order_id = $j('input[name="custom"]').val();
var order_amount = $j('input[name="amount"]').val();
var service_type = $j('input[name="item_name"]').val();
var order_to = $j('input[name="to"]').val();
var order_from = $j('input[name="from"]').val();
var order_message = $j('textarea#message').val();
if(hasError == false) {
var dataString = 'order_id='+ order_id + '&order_amount=' + order_amount + '&service_type=' + service_type + '&order_to=' + order_to + '&order_from=' + order_from + '&order_message=' + order_message;
$j.ajax({ type: "GET", cache: false, url: "/gc_process.php", data: dataString, success: function() { } });
} else {
return false;
}
});
Here's what my PHP script looks like:
<?php
// Make a MySQL Connection
include('dbconnect.php');
// Get data
$order_id = $_GET['order_id'];
$amount = $_GET['order_amount'];
$type = $_GET['service_type'];
$to = $_GET['order_to'];
$from = $_GET['order_from'];
$message = $_GET['order_message'];
// Insert a row of information into the table
mysql_query("REPLACE INTO gift_certificates (order_id, order_type, amount, order_to, order_from, order_message) VALUES('$order_id', '$type', '$amount', '$to', '$from', '$message')");
mysql_close();
?>
Any ideas?
You really should be using POST instead of GET, but regardless, I would check the following:
That jQuery is executing the ajax call after you click back and change the information, you should probably put either a console.log or an alert calls to see if javascript is failing
Add some echos in the PHP and some exits and go line by line and see how far it gets. Since you have it as a get, you can just load up another tab in your browser and change the information you need to.
if $j in your jQuery is the form you should be able to just do $j.serialize(), it's a handy function to get all the form data in one string
Mate,
Have you enclosed your jquery in
$j(function(){
});
To make sure it is only executed when the dom is ready?
Also, I'm assuming that you've manually gone and renamed jquery from "$" to "$j" to prevent namespace conflicts. If that isn't the case it should be $(function and not $j(function
Anyway apart from that, here are some tips for your code:
Step 1: rename all the "name" fields to be the name you want them to be in your "dataString" object. For example change input[name=from] to have the name "order_from"
Step 2:
Use this code.
$j(function(){
$j(".submit").click(function() {
var hasError = false;
if(hasError == false) {
var dataString = $j('form').serialize();
$j.ajax({ type: "GET", cache: false, url: "/gc_process.php?uu="+Math.random(), data: dataString, success: function() { } });
} else {
return false;
}
});
});
You'll notice i slapped a random variable "uu=random" on the url, this is generally a built in function to jquery, but to make sure it isn't caching the response you can force it using this method.
good luck. If that doesn't work, try the script without renaming jquery on a fresh page. See if that works, you might have some collisions between that and other scripts on the page
Turns out the problem is due to the fact that I am using iframes. I was able to fix the problem by making the page without iframes. Thanks for your help all!