Ive created a bootstrap wizard with several steps. When a user clicks the 'save & continue' button on the second wizard step, I want to commit the form data entered to the underlying data store before moving to the third step. I cant seem to get the form submission to work, the actionmethod on the controller isnt being called. This is the javascript on the page, it is being hit, but the controller action isnt
$("#scheduleReport").on("click", function () {
// Get the record's ID via attribute
//var id = $(this).attr('data-id');
$('#frmAddSchedule').validate();
$('#frmAddSchedule').submit();
});
$('#frmAddSchedule').on('submit', function (e) {
var $form = $(e.target);
if ($form.valid()) {
e.preventDefault();
$.ajax({
url: '#Url.Action("Create", "ReportScheduler")',
data: $form.serialize(),
async: true,
type: 'POST',
success: function (returnval) {
if (returnval.success == true) {
$("#schedulerGrid").igGrid("dataBind");
}
if (returnval.success == false) {
//$form.parents('.bootbox').modal('hide');
bootbox.alert({ title: '<div class="text-center text-danger"><i class="fa fa-exclamation-triangle"></i> ERROR</div>', message: returnval['responseText'] });
}
},
error: function (returnval) {
//$form.parents('.bootbox').modal('hide');
bootbox.alert(returnval['responseText']);
}
});
}
});
and the controller action method
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create([Bind(Prefix = "Schedule")]ReportScheduleViewModel item)
{
are there any 'best practices' for doing this ? what am I doing wrong ?
I found out the isue in the end, the wizard example I used already had a form element inside it (hadnt noticed it) which I had wrapped in my own form which was stopping the form submiting. It works fine now
Well, as a start I can maybe help you with the part of beeing able to call the controller action. As for the question "best practices", you gave to little details.
So:
/**
* On document ready.
*
* #return void
*/
$(document).ready(function () {
activateScheduleReport();
activateAddScheduleFormSubmit();
});
/**
* Activate schedule report click event.
*
* #return void
*/
function activateScheduleReport() {
$("#scheduleReport").on("click", function () {
// Get the record's ID via attribute
//var id = $(this).attr('data-id');
validateAddScheduleForm();
submitAddScheduleForm();
});
}
/**
* Activate add schedule form submit.
*
* #return void
*/
function activateAddScheduleFormSubmit() {
$('#frmAddSchedule').submit(function (e) {
var $form = $(this);
var ajax = $.ajax({
async: true, // Please don't use this! :-)
method: 'post',
dataType: 'json',
url: '#Url.Action("Create", "ReportScheduler")',
data: $form.serialize()
});
ajax.done(function (response, textStatus, jqXHR) {
if (response.success) {
$("#schedulerGrid").igGrid("dataBind");
} else {
//$form.parents('.bootbox').modal('hide');
bootbox.alert({
title: '<div class="text-center text-danger"><i class="fa fa-exclamation-triangle"></i> ERROR</div>',
message: response.responseText
});
}
});
ajax.fail(function (jqXHR, textStatus, errorThrown) {
//$form.parents('.bootbox').modal('hide');
bootbox.alert(textStatus + ' ' + errorThrown);
});
ajax.always(function (response, textStatus, jqXHR) {
// Do whatever you want here...
});
// Use this to prevent page refreshing. No need for preventDefault().
return false;
});
}
/**
* Validate add schedule form.
*
* #return void
*/
function validateAddScheduleForm() {
$('#frmAddSchedule').validate();
}
/**
* Submit add schedule form.
*
* #return void
*/
function submitAddScheduleForm() {
$('#frmAddSchedule').submit();
}
In the action you should use:
echo json_encode('whatever response string');
or
echo json_encode(array(responseText: 'whatever response string'));
Nota bene:
I used dataType: json. You can also use dataType: html. If, then
echo the string or the array without the json_encode.
I renamed your returnval to response.
Watch the parameters of ajax fail(), e.g of the old error().
I structured the js code in functions.
As I come from the PHP world I used echo to print and json_encode to encode in the JSON format.
Good luck!
Related
I have a generic AJAX form submit JS class:
$(function() {
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$('.ajax-form').submit(function() {
var form = $(this);
var url = form.attr('action');
var data = form.serialize();
if (!form.hasClass('valid')) {
$.ajax({
url: url,
type: 'post',
data: data,
dataType: 'json',
success: function(result) {
$('.field').removeClass('has-error');
form.addClass('valid');
form.submit();
},
error: function(result) {
var errors = result.responseJSON;
$('.field').removeClass('has-error');
$.each(errors, function(key, value) {
var field = $('.field.' + key);
field.addClass('has-error').children('.error-message').text(value[0]);
});
}
});
return false;
}
});
});
This works great for AJAX validation on all my forms. I am now trying to implement this on the default "forgot password" form that is generated with the auth scaffold (resources/views/auth/passwords/email.blade.php).
<form class="ajax-form" method="POST" action="{{ route('password.email') }}">
...
</form>
Although the AJAX validation is working here, the problem I am having is that when the validation passes, it is also performing the "forgot password" functionality. So basically it sends the reset password email twice (once during the AJAX submit and once during normal form submit).
I only want the AJAX submit to perform validation. If validation is successful it should (as it currently does) perform a normal form submit which will send the email.
Did you want to keep the Ajax submit but remove the normal form submit? If so then assuming you have a button to submit the form, you can keep the form from submitting in this answer:
Want html form submit to do nothing
If I understand the issue correctly you need to prevent Form Default behavior and validate and if everything is validated, resume the default form behavior to submit the data.
$('.ajax-form').submit(function(evt) {
evt.preventDefault(); // This would prevent default form submission functionality
var form = $(this);
var url = form.attr('action');
var data = form.serialize();
if (!form.hasClass('valid')) {
$.ajax({
url: url,
type: 'post',
data: data,
dataType: 'json',
success: function(result) {
$('.field').removeClass('has-error');
form.addClass('valid');
form.unbind('submit').submit(); // Submit the Form If everything is validated
},
error: function(result) {
var errors = result.responseJSON;
$('.field').removeClass('has-error');
$.each(errors, function(key, value) {
var field = $('.field.' + key);
field.addClass('has-error').children('.error-message').text(value[0]);
});
}
});
return false;
}
});
Here is the correct way to resolve this. In Auth\ForgotPasswordController override the sendResetLinkEmail function as follows:
/**
* Send a reset link to the given user.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\RedirectResponse
*/
public function sendResetLinkEmail(Request $request)
{
$this->validate($request, ['email' => 'required|email']);
// Inserted this piece of code which checks for AJAX request
if ($request->ajax()) {
return response()->json();
}
// We will send the password reset link to this user. Once we have attempted
// to send the link, we will examine the response then see the message we
// need to show to the user. Finally, we'll send out a proper response.
$response = $this->broker()->sendResetLink(
$request->only('email')
);
return $response == Password::RESET_LINK_SENT
? $this->sendResetLinkResponse($response)
: $this->sendResetLinkFailedResponse($request, $response);
}
By doing if ($request->ajax()) we allow it to check for ajax request and only return a json response. Then in the subsequent request when it does a regular form post it will perform the forgot password functionality.
I am trying to user ajax to insert into the database for my laravel project but each time i insert i see duplicates of every item with a unique id.
Inserting normally with the form itself, this behavior doesn't repeat.
My ajax code s below.
`$('#saveCat').on('click', function (e) {
e.preventDefault();
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
var url = '/admin/storecat';
var type = "post";
var data = {spec: $('#cat').val() };
$.ajax({
type: type,
url: url,
data: data,
dataType: 'json',
success: function (data) {
console.log(data);
$('#catform').trigger('reset');
//show success alert msg
$('#alert-suc').html(data);
$('#ac-alert').show('slow', function () {
setTimeout(function () {
$('#ac-alert').hide('slow');
}, 3000);
});
},
error: function (data) {
console.log('Error:', data);
}
});
});
My controller action here
public function storeCat(Request $request) {
$Category = new Category;
$Category->name = $request->spec;
$Category->save();
return response()->json('New service category ' . $request->spec . ' has been added.');
}
try to use:
e.stopImmediatePropagation();
stopImmediatePropagation will prevent any parent handlers and also any other handlers from executing.
In my MVC application I don't want the layout page to reload everytime a view is selected. It would be great if the views could be loaded using ajax to keep things nice and fast and allow me to persist certain interface states that are wiped out when you move around.
My initial approach was to add some ajax to the _Layout.cshtml and then whent he view was requested pass that request to the controller method which will grab that page. All I ended up doing however was returning the WHOLE view again.
Here is the code I have so far, am I on the right tracks here or is this totally wrong?
Layout Ajax Script
<script>
$(function () {
var content = document.getElementById('content');
//When a user selects a link, pass the data attribute and
//use it to construct the url
$('#sidebar a').on("click", function () {
var page = $(this).data('page');
console.log("Data Attrib : " + page);
$.ajax({
type: 'GET',
url: '#Url.Content("~/Home/")' + page,
success: function (data) {
$('#content').html(data);
console.log("Success");
},
error: function (xhr, ajaxOptions, thrownError) {
console.log("Error: " + thrownError);
}
})
})
});
</script>
As I say, this sort of works, but it's not perfect as it returns the whole page into the content area including layout, ideally I just want the core view data.
you can create a Single Page Application that have 1 layout and in home controller and index action method create menu or user setting or another things
and now you can load other action with Ajax call with data-content html that does not have layout file and append that in container
when user click another menu clean older content and add new or you can create tab strip or window
Layout.cshtml
<script>
$(function () {
//When a user selects a link, pass the data attribute and
//use it to construct the url
$('#sidebar a').on("click", function () {
var page = $(this).data('page');
$.ajax({
type: 'POST',
url: '/Home/Pages',
data: { pageValue: page },
success: function (data) {
$('#content').html(data);
console.log("Success");
},
error: function (xhr, ajaxOptions, thrownError) {
console.log("Error: " + thrownError);
}
})
})
});
Controller
public class HomeController : Controller
{
[HttpPost]
public string Pages(string pageValue)
{
string result = //Whatever
return result;
}
}
Controller
public ActionResult SomeAction(String someparams)
{
//Make the model
SomeModel someModel = new SomeModel();
someModel.someparams = someparams;
return PartialView("SomePartialView", someModel);
}
In View
$.ajax({
url: "/Home/SomeAction",
type: "POST",
dataType : "html",
data: json,
contentType: 'application/json; charset=utf-8',
success: function(data){
$('#SomeDivID').html(data);
}
});
From client side, I wanna send some data to server and receive some <div> tags which responding from View (another controller).
My ajax code looks like this:
var sortTopic = function () {
var $list = [],
$address = '',
$formData = new FormData();
/* do something here to set value to $list and $address */
$formData.append('Category', $list);
$formData.append('Address', $address);
$formData.append('Tags', '[KM]');
$formData.append('Skip', 0);
$.ajax({
url: '/Topic/Sort',
type: 'POST',
data: $formData,
dataType: 'json',
contentType: false,
processData: false,
success: function (data) {
if (!data.success) {
$('.jumbotron').html(data.ex);
} else {
$('.jumbotron').html(data);
}
},
error: function (xhr) {
alert(xhr.status); //xhr.status: 200
}
});
};
In TopicController, action Sort was:
[AllowAnonymous]
[HttpPost]
public ActionResult Sort(SortTopicViewModel model)
{
try
{
if (model.IsValidSortTopicModel())
{
return PartialView("../Home/_Timeline", new TopicMaster().Sort(model));
}
return Json(new { success = false, ex = "Invalid model." });
}
catch (Exception e) { return Json(new { success = false, ex = e.Message }); }
}
I'm sure that the model is valid and method new TopicMaster().Sort(model) was working fine (because I had put breakpoint to view the return data). And the partial view _Timeline is a partial view of HomeController.
My problem is: I don't understand why I get error with status code 200 in ajax:
error: function (xhr) {
alert(xhr.status); //xhr.status: 200
}
Can you explain to me?
Thank you!
as you told you receive <div> in response that is not json and you mention dataType:"json" in your ajax just remove it. this will solve your problem. error 200 occur when you did not get valid response which is you mention in ajax.
for mor information you can read it documentation
I've been trying for ages to get Json working in Joomla and I just can't do it. I think I've tried every combination of URL etc so any help would be great:
this is for the admin side structure looks like
admin
-controllers
--orderitem.php
-views
--orderitem
---tmpl
----orderitem.php
-controller.php
function updateNow(newrefresh) {
var dataJSON = JSON.encode (newrefresh);
var request = new Request.JSON({
method: 'post',
url: 'index.php?option=com_customersitedetails&view=orderitem&task=refreshscreen&format=raw',
data: {
json: dataJSON
},
onComplete: function(jsonObj) {
alert("Your form has been successfully submitted ");
}
}).send();
};
Although runs the alert box it doesn't retun JSON just
View not found [name, type, prefix]: orderitem, raw, customersitedetailsView
Any ideas where I can start? thanks
You're missing views/orderitem/view.raw.php containing a CustomersitedetailsViewOrderitem class.
views/orderitem/view.raw.php
class CustomersitedetailsViewOrderitem extends JViewLegacy
{
public function display($tpl = null)
{
$response = 'Your magic response here';
echo $response;
JFactory::getApplication()->close();
}
}
You can look here for proper ajax call in joomla
How to Write PHP in AJAX
inside your controllers you should have a file "mycall.json.php" this file will process and return a json format of your ajax call
Joomla doesn't gives a build in AJAX as part of it's system. my answer is from Josef Leblanc course in lynda.com
http://www.lynda.com/Joomla-1-6-tutorials/Joomla-1-7-Programming-and-Packaging-Extensions/73654-2.html
As I said :
Write this i the frontend JS :
$.ajax({
type: 'GET',
url: 'index.php',
data: {option: 'com_componenetname', task: 'taskname.youroperation', format: 'json', tmpl: 'raw'},
dataType: 'json',
async: true, // can be false also
error: function(xhr, status, error) {
console.log("AJAX ERROR in taskToggleSuceess: ")
var err = eval("(" + xhr.responseText + ")");
console.log(err.Message);
},
success: function(response){
// on success do something
// use response.valuname for server's data
}
,
complete: function() {
// stop waiting if necessary
}
});
in the backend you should have a file under com_componentname/controllers/taskname.json.php
the file should look like this
class ComponentnameControllerTaskname extends JControllerLegacy (Legacy only J3.0)
{
public function __construct($config = array())
{
parent::__construct($config);
$this->registerTask('operationname', 'functionname');
}
public function functionname() {
// do something in backend
echo json_encode(array(''var1' => val1, 'var2' => val2 ) );
}
}
nibra - I use this in all my joomla sites and its working perfect. your comment was wrong, pease give me my credit back