I am trying to change a value in a table from one view, and then redirect to another view using Flash FSCommand and Json, using the following code:
if (command == "nameClip") {
var url = '<%= Url.Action("Index", "Home") %>';
var clip = [args];
try {
$.post(url, {
MovieName: clip
}, function(data) {
;
}, 'json');
} finally {
// window.location.href = "/Demo/SWF";
}
}
In the controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(SWF movietoplay) {
var oldmovie = (from c in db.SWFs where c.ID == "1" select c).FirstOrDefault();
var data = Request.Form["MovieName"].ToString();
oldmovie.SWFName = data;
db.SubmitChanges();
return RedirectToAction("Show");
}
All works well except Redirect!!
You need to perform the redirect inside the AJAX success callback:
$.post(url, { MovieName: clip }, function(data) {
window.location.href = '/home/show';
}, 'json');
The redirect cannot be performed server side as you are calling this action with AJAX.
Also you indicate in your AJAX call that you are expecting JSON from the server side but you are sending a redirect which is not consistent. You could modify the controller action to simply return the url that the client needs to redirect to using JSON:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(SWF movietoplay)
{
...
return Json(new { redirectTo = Url.Action("show") });
}
and then:
$.post(url, { MovieName: clip }, function(data) {
window.location.href = data.redirectTo;
}, 'json');
Related
I have a div block in my view like this:
<div id="divStatus" style="margin-top:10px;width: 200px; height: 100px; overflow-y: scroll;">
</div>
then from the view, user clicks on a button that calls the controller. In the controller some tasks are executed so from the controller I want to update a div block within the view. In this div I print out phrasses.
How to do this?
example:
public ActionResult()
{
// Do something
Update_DIV_in_View("some thing has been done"); <--- DIV in the view must be updated by appending this message
// Do another thing
Update_DIV_in_VIEW("another thing has been done");<--- DIV in the view must be updated by appending this message
.... and so on
// All things done
Update_DIV_in_VIEW("All things have been done");<--- DIV in the view must be updated by appending this message
return View();
}
Create a second action in your controller which only shows the updated content of the div and on your normal page when you press the button load the status with an AJAX call (for example the jQuery.load() method).
You can do it as follows:
In your view use Ajax Form as follows:
#using (Ajax.BeginForm("ActionName", "ControllerName", new AjaxOptions { OnBegin = "beforeSubmitFunction()", HttpMethod = "POST",UpdateTargetId = "divStatus", OnComplete = "InsertRow()" }))
{
.. //your Html form Controls
}
function beforeSubmitFunction()
{
//Your code for before submitting...
}
Then in your controller return your partial view as result which will get updated in your div with id divStatus
[HttpPost]
public ActionResult Index(TypeName model)
{
return PartialView("PartialViewName", model);
}
Here are 3 examples what I am using:
example 1:
button (here with telerik css styling):
<a class="t-button t-button-icontext" onclick="ajaxCreateEquipment()"><span
class="t-icon t-add"></span>Create</a>
javascript: #equipment-table-container is the id of the target div:
<script type="text/javascript">
function ajaxCreateEquipment() {
$.ajax({
type: 'GET',
url: '#Url.Action("ShowCreate", "Equipment")',
dataType: 'html',
success: function (data) {
$('#equipment-table-container').html(data);
}
});
}
</script>
EquipmentController.cs:
[HttpGet]
public ActionResult ShowCreate()
{
// some calculation code, fetch model from DB something else
ViewData.Add("FormAction", "Create"); // some ViewData
return PartialView("Create", model); // returns the View html file
}
example 2:
function call here with id argument and Json return:
#{
var supplierQuoteId = Model.ID.ToString();
<a id="#supplierQuoteId" onclick="updateDiv(this.id)"></a>
}
javascript:
function updateDiv(id) {
var strUrl = "/LicenseTerm/UpdateUsedQuantity/" + id;
$.ajax({
type: "GET",
url: strUrl,
cache: false,
dataType: "json",
success: function (data) {
$('#licenseterm-usedquantity').html(data.sum);
}
});
}
LicenseTermController.cs
[HttpGet]
public JsonResult UpdateUsedQuantity(Guid id)
{
var licenseTerm = _repository.GetAll<LicenseTerm>().Where(l => l.ID == id).First();
int sum = 0;
foreach (LicenseAllocation l in licenseTerm.LicenseAllocations.Where(o => o.Deleted == false))
sum = sum + l.LicenseQuantity;
return Json(new { sum = sum }, JsonRequestBehavior.AllowGet);
}
example 3: simple get
function ajaxFieldDefinitionCreate(id) {
var strUrl = '/FieldDefinition/Create' + '/' + id.toString() + '?isRefreshAction=true';
$.get(strUrl, function (data) {
$('#equipmenttype-fielddefinition-createeditarea').html(data);
});
}
[HttpGet]
public ActionResult Create(Guid id, [Optional, DefaultParameterValue(false)] bool isRefreshAction)
{
var equipmentType = _equipmentTypeRepository.GetById(id);
var fieldDefinitionDto = new FieldDefinitionDto
{
ID = Guid.NewGuid(),
ParentName = equipmentType.Name,
};
return PartialView("Create", fieldDefinitionDto);
}
In response to the changes of the question, especially that the questioner would like to have more returns in the same Action:
the concept of HTTP request is to transmit relatively small pieces of data from the server to the client, which invoked the e.g. HTTP GET request.
You can not keep open the HTTP GET request for more transmissions.
I searched the web and extracted that especially HTML5 will address this requirement with the HTTP stream, but this is another topic. e.g.: I got this url: http://socket.io/ .
Bypass:
But as an idea of mine,
I would make a first ajax call to determine the count of the next requests, addressed in the controller Action1.
And then invoke several new requests in the success part of the first ajax request, with the url of the Action2, e.g. Calculate etc., which appends then the several pieces of data to the div content.
here some quickly invented javascript code:
function updateDiv() {
var strUrl = "/Home/RequestCount/";
$.ajax({
type: "GET",
url: strUrl,
cache: false,
dataType: "json",
success: function (count) {
var strUrlCalc = "/Home/Calc/";
for (var i = 0; i < count; i++) {
$.ajax({
type: "GET",
url: strUrlCalc,
cache: false,
dataType: "json",
success: function (data) {
$('#test').append(data);
}
});
}
}
});
}
How to use $.post or $.getJSON to get json from mvc controlller but not working below? Would you like help me?
var controlRole = function () {
var _url = 'IsStudent/';
console.log('IsStudent');
$.post(_url, {}, function (data) {
console.log('IsStudent2');
if (data == "true") {
$('#btnSent_').hide();
$('#btnDraft_').hide();
$('#btn_Inbox_').show();
$('#btnTrash_').show();
$.post('FillProgramListByUser/', {}, function (result) {
console.log('IsStudent3');
console.log(result);
$("#liProgramContainer ul").append('<li ><a class="btn" href="javascript:;" data-title="Sent">'+result.Name+'</a><b></b></li>');
});
// $.getJSON("FillProgramListByUser/", user, updateFields);
}
else {
$('#btnSent_').show();
$('#btnDraft_').show();
$('#btn_Inbox_').show();
$('#btnTrash_').show();
}
});
}
Controller side:
public JsonResult FillProgramListByUser()
{
string UserName = SessionVariables.CurrentUser.UserName;
int OrganizationId = SessionVariables.CurrentUser.OrganizationId;
IList<Program> programs = new List<Program>();
if (UserName != "system_admin")
{
programs = Uow.Programs.GetAll().Where(q => q.OrganizationId == OrganizationId).ToList();
}
return Json(programs, "application/json", Encoding.UTF8, JsonRequestBehavior.AllowGet);
}
[HttpPost]
public string IsStudent()
{
string UserName = SessionVariables.CurrentUser.UserName;
if (UserName != "system_admin")
{
return "true";
}
else
{
return "false";
}
}
Your controller action should return a JsonResult and not some strings:
[HttpPost]
public ActionResult IsStudent()
{
string UserName = SessionVariables.CurrentUser.UserName;
if (UserName != "system_admin")
{
return Json(new { success = true });
}
return Json(new { success = false });
}
Also in your FillProgramListByUser action you don't need to be explicitly setting the content type response header nor the encoding:
public ActionResult FillProgramListByUser()
{
string UserName = SessionVariables.CurrentUser.UserName;
int OrganizationId = SessionVariables.CurrentUser.OrganizationId;
IList<Program> programs = new List<Program>();
if (UserName != "system_admin")
{
programs = Uow.Programs.GetAll().Where(q => q.OrganizationId == OrganizationId).ToList();
}
return Json(programs, JsonRequestBehavior.AllowGet);
}
Also adapt your script so that the urls are not hardcoded as in your example but you used URL helpers to generate them:
<script type="text/javascript">
var controlRole = function () {
var isStudentUrl = '#Url.Action("IsStudent")';
$.post(isStudentUrl, function (data) {
if (data.success) {
$('#btnSent_').hide();
$('#btnDraft_').hide();
$('#btn_Inbox_').show();
$('#btnTrash_').show();
var fillProgramListByUserUrl = '#Url.Action("FillProgramListByUser")';
$.post(fillProgramListByUserUrl, function (result) {
$("#liProgramContainer ul").append('<li><a class="btn" href="javascript:;" data-title="Sent">'+result.Name+'</a><b></b></li>');
});
} else {
$('#btnSent_').show();
$('#btnDraft_').show();
$('#btn_Inbox_').show();
$('#btnTrash_').show();
}
});
};
</script>
Next put breakpoints in your controller actions and see if they are hit. Also don't forget to look at the network tab of your javascript debugging tool (FireBug or Chrome Developer Toolbar) which is where you will see the exact AJAX request being sent to the server and what does the server respond to. You will see the HTTP status code returned and you could also see the contents of the response. If the status code is non 2xx the success callback of your AJAX request will not be executed.
Another thing you should check is the Program model which is being returned by your FillProgramListByUser controller action. In there you are attempting to JSON serialize an IList<Program> but be careful: if this Program class has some circular references (often happens if you don't use view models but are directly passing your EF domain models to the views) you won't be able to JSON serialize it. The answer is of course obvious: use a view model.
I have an ajax call to MVC which returns a partialview. This is all fine until the session ends or the cookie expires. When I make the ajax call it displays the content inside a div that was meant to be for the partialview. How can I detect that my session has expired during the ajax call and redirect properly to a full screen/page
I would recommend encapsulating all your requests into a wrapper element:
public class JsonResponse<T>
{
public JsonResponse()
{
}
public JsonResponse(T Data)
{
this.Data = Data;
}
public T Data { get; set; }
public bool IsValid { get; set; }
public string RedirectTo { get; set; }
}
What model you want to send to your client is in Data.
To get the RedirectTo populated, I use a GlobalAuthorize attribute in the Global.Asax and added a handle for HandleUnauthorizedRequests.
public sealed class GlobalAuthorize : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest
(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.Result = new JsonResult
{
Data = new JsonResponse<bool>
{
IsValid = false,
//RedirectTo = FormsAuthentication.LoginUrl
RedirectTo = "/"
},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}
Additionally, I've encapsulated all my Ajax requests into a single function which checks for the RedirectTo.
function global_getJsonResult(Controller, View, data, successCallback, completeCallback, methodType)
{
if (IsString(Controller)
&& IsString(View)
&& !IsUndefinedOrNull(data))
{
var ajaxData;
var ajaxType;
if (typeof (data) == "string")
{
ajaxData = data;
ajaxType = "application/x-www-form-urlencoded"
}
else
{
ajaxData = JSON.stringify(data);
ajaxType = "application/json; charset=utf-8";
}
var method = 'POST';
if (!IsUndefinedOrNull(methodType))
{
method = methodType;
}
var jqXHR = $.ajax({
url: '/' + Controller + '/' + View,
data: ajaxData,
type: method,
contentType: ajaxType,
success: function(jsonResult)
{
if (!IsUndefinedOrNull(jsonResult)
&& jsonResult.hasOwnProperty("RedirectTo")
&& !IsUndefinedOrNull(jsonResult.RedirectTo)
&& jsonResult.RedirectTo.length > 0)
{
$.fn.notify('error', 'Login Expired', 'You have been inactive for a prolonged period of time, and have been logged out of the system.');
window.setTimeout(function() { window.location = jsonResult.RedirectTo }, 5000);
}
else if (IsFunction(successCallback))
{
successCallback(jsonResult, Controller + '/' + View);
}
},
error: function(jqXHR, textStatus, errorThrown)
{
if (errorThrown != 'abort')
{
$.fn.notify('error', 'AJAX Connection Error', textStatus + ': ' + errorThrown);
}
},
complete: function(jqXHR, textStatus)
{
if (IsFunction(completeCallback))
{
completeCallback(jqXHR, textStatus, Controller + '/' + View);
}
}
});
return jqXHR;
}
}
You could create a timer on the client with javascript that will show a dialog to the user when the session has timed out. You would just set the timer's value to whatever your session time out. Then on ajax request, it will reset the count down as well.
var g_sessionTimer = null;
function uiSessionInit() {
id = "uiTimeout";
timeout = 3600000 * 24; // 1 day timeout
uiSessionSchedulePrompt(id, timeout);
$('body').ajaxStart(function () {
// reset timer on ajax request
uiSessionSchedulePrompt(id, timeout);
});
}
function uiSessionSchedulePrompt(id, timeout) {
if (g_sessionTimer)
clearTimeout(g_sessionTimer);
g_sessionTimer = setTimeout(function () { uiSessionExpiring(id); }, timeout);
}
function uiSessionExpiring(id) {
// create a dialog div and use this to show to the user
var dialog = $('<div id="uiTimeout"></div>').text("Your session with has timed out. Please login again.");
$('body').append(dialog);
$('#uiTimeout').dialog({
autoOpen: true,
modal: true,
title: 'Expired Session',
buttons: {
"OK": function(){
$(this).dialog('close');
}
},
close: uiSessionDialogClose
});
}
function uiSessionDialogClose(){
// take user to sign in location
location = 'http://www.mypage.com';
}
It's been 8 years but I've just encountered a similar problem whereby an Ajax call to load a partial view into a modal, made after the user's authentication cookie had expired, would result in the full login page being loaded into the modal. This is how I got around it.
Firstly, I added a hidden control on my login page. The value isn't strictly required but it makes for more readable markup, I think:
<input id="isLoginPage" type="hidden" value="true" />
Then I modified the Ajax call like this. I'm using jQuery but the same principle will work in plain old Javascript too:
$.ajax({
url: `/mypartialview`,
type: "GET",
success: function (data) {
var $modal = $("#myModal");
$modal.find(".modal-content").html(data);
if ($modal.find("#isLoginPage").length > 0) {
window.location.replace("/");
}
$modal.modal("show");
}
});
This works on the basis that if the user's authentication has expired MVC's default behaviour is to return to the login page, so I "sniff" the view returned by the Ajax call for the isLoginPage hidden input and, if it's found, I know that the login page has been returned so I just redirect the user to the root of the application, which MVC will then redirect to the main login page.
If your application's root allows anonymous access you could replace window.location.replace("/") with the path to your application's login page, e.g. window.location.replace("/account/login").
With this working, I encapsulated the solution in a function to simplify things and avoid repeating myself:
function handleAjaxData($container, data) {
$container.html(data);
if ($container.find("#isLoginPage").length > 0) {
window.location.replace("/");
}
}
Which I can then use in my Ajax call like this:
$.ajax({
url: `/mypartialview`,
type: "GET",
success: function (data) {
var $modal = $("#myModal");
handleAjaxData($modal.find(".modal-content"), data);
$modal.modal("show");
}
});
You could obviously go further and include the Ajax call itself in the function, but in my case that would have involved some complicated callbacks so I didn't bother.
I have the following to get the Json abject passed from the controller and populate the various textboxes in the view. However, nothing is happening even though controller is passing a valid Json object. What is wrong with this code???
<script language="javascript" type="text/javascript">
$(document).ready(function() {
var url = '<%=Url.Action("DropDownChange") %>';
$("#vendorID").change(function() {
var selectedID = $(this).val();
if (selectedID != "New Vendor Id") {
//$.post('Url.Action("DropDownChange","Refunds")', function(result) {
$.post(url, { dropdownValue: selectedID }, function(result) {
alert(selectedID);
$("#name").val(result.Name);
$("#city").val(result.City);
$("#contact").val(result.Contact);
$("#address2").val(result.Address2);
$("#address1").val(result.Address1);
$("#state").val(result.State);
$("#zip").val(result.Zip);
});
}
});
});
This is the code in my controller;
public JsonResult DropDownChange(string dropdownValue)
// This action method gets called via an ajax request
{
if (dropdownValue != null && Request.IsAjaxRequest() == true)
{
paymentApplicationRefund =
cPaymentRepository.PayableEntity(dropdownValue);
paymentApplicationRefund.Address1.Trim();
paymentApplicationRefund.Address2.Trim();
paymentApplicationRefund.Name.Trim();
paymentApplicationRefund.City.Trim();
paymentApplicationRefund.Contact.Trim();
paymentApplicationRefund.State.Trim();
paymentApplicationRefund.Zip.Trim();
return Json(paymentApplicationRefund,"application/json");
}
else
{
return null;
}
}
You probably just need to tell it to expect JSON data back. By default it assumes it's HTML.
$.post(url, { dropdownValue: selectedID }, function(result) {
alert(selectedID);
$("#name").val(result.Name);
$("#city").val(result.City);
$("#contact").val(result.Contact);
$("#address2").val(result.Address2);
$("#address1").val(result.Address1);
$("#state").val(result.State);
$("#zip").val(result.Zip);
}, 'json');
I prefer sending Json to a ActionResult with my DTO as the parameter and use the JsonValueProviderFactory do the deserialization for me.
Sending JSON to an ASP.NET MVC Action Method Argument
Try this...
Add the ".change()" at the end of the function.
$(document).ready(function() {
var url = '<%=Url.Action("DropDownChange") %>';
$("#vendorID").change(function() {
.....
}).change();
});
I have used jquery ajax function to submit a form.
The users have to be logged in else they must redirect to a login page.I have used Authorize() attribute for it.
[Authorize]
public ActionResult Creat()
{
....
}
If the user is not login the action return login page to jquery's ajax functions and it is displayed on the same page but I want to redirect the user to login page.
Is there any solution?
Working example: https://github.com/ronnieoverby/mvc-ajax-auth
Important parts:
AjaxAuthorizeAttribute:
using System.Web.Mvc;
namespace MvcApplication1
{
public class AjaxAuthorizeAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext context)
{
if (context.HttpContext.Request.IsAjaxRequest())
{
var urlHelper = new UrlHelper(context.RequestContext);
context.HttpContext.Response.StatusCode = 403;
context.Result = new JsonResult
{
Data = new
{
Error = "NotAuthorized",
LogOnUrl = urlHelper.Action("LogOn", "Account")
},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
else
{
base.HandleUnauthorizedRequest(context);
}
}
}
}
Javascript:
$(function () {
$(document).ajaxError(function (e, xhr) {
if (xhr.status == 403) {
var response = $.parseJSON(xhr.responseText);
window.location = response.LogOnUrl;
}
});
});
Use the attribute in a controller:
[AjaxAuthorize]
public ActionResult Secret()
{
return PartialView();
}
Do some ajax:
#Ajax.ActionLink("Get Secret", "Secret", new AjaxOptions { UpdateTargetId = "secretArea", })
<div id="secretArea"></div>
Just a handy addition to #Ronnie's answer
if you want to keep the page url on redirect.
var pathname = window.location.pathname;
if (xhr.status == 403) {
var response = $.parseJSON(xhr.responseText);
window.location = response.LogOnUrl + '?ReturnUrl=' + pathname;
}
As another extension to Ronnie Overby's answer.
His solution doesn't work with webapi, but this is fine because you can use normal Authorize
attribute instead and then handle the 401 status in the ajaxError function as follows.
$(document).ajaxError(function (e, xhr) {
//ajax error event handler that looks for either a 401 (regular authorized) or 403 (AjaxAuthorized custom actionfilter).
if (xhr.status == 403 ||xhr.status == 401) {
//code here
}
});