We would like to implement a web form that automatically saves content at regular intervals.Something similar to gmail/google docs auto save funcationality.
Can some one suggest how to implement this using ASP.NET MVC + jQuery?
jQuery Forms plugin and an ASP.NET MVC action should do the job:
public ActionResult SaveDraft(FormCollection form)
{
// TODO: Save the form values and return a JSON result
// to indicate if the save went succesfully
return Json(new { success = true });
}
And in your View just invoke this action periodically:
setInterval(function() {
$('#theFormToSave').ajaxSubmit({
url : 'SaveDraft',
success: function (data, textStatus) {
if (data.success) {
alert('form successfully saved');
}
}
});
}, 30000);
Related
I have a dropdownlist in my razor view MVC like
#Html.DropDownListFor(n => n.EMP_ID, (SelectList)ViewBag.EmployeeList, new { #id = "ddlemployee" },"---choose an Employee Name--").
I have applied select change event to drop-down using jquery, when select Employee name getting Employee names and realted data, but problem is when i select a value in drop-down, dropdownlist setting again set to default first value,
It is not sticking to particular selected value, in terms of Asp.net terminology, how to prevent postback to dropdownlist?
//Redirected to Controller
<script>
$(document).ready(function () {
$("#ddlemployee").change(function () {
location.href ='#Url.Action("GetEmployeeDetails", "Employer")'
});
});
</script>
//Action Method in Employer Controller
public ActionResult GetEmployeeDetails(Timesheetmodel model)
{
try
{
ViewBag.EmployeeList = objts.getEmployeeNames();
var emps = from n in db.TIMESHEETs
where n.RES_ID == model.EMP_ID
select n;
int count = emps.Count();
foreach (TIMESHEET ts in emps)
{
model.PROJ_ID = ts.PROJ_ID;
model.SUN_HRS = ts.SUN_HRS;
model.MON_HRS = ts.MON_HRS;
model.TUE_HRS = ts.TUE_HRS;
model.WED_HRS = ts.WED_HRS;
model.THU_HRS = ts.THU_HRS;
model.FRI_HRS = ts.FRI_HRS;
model.SAT_HRS = ts.SAT_HRS;
}
}
catch (Exception ex)
{
throw ex;
}
return View("Timesheet", model);
}
ASP.Net Webforms achieve StateFullness by using Some thing called ViewState
It is implemented as hidden fields in the page to hold data between requests.
This way , asp.net webforms achieves post back mechanism and was able to hold values in bewteen the requests.
Since Http is a stateless protocol , which means it has no relation between requests.
View State is absent in ASP.Net MVC.
So, you have to stop postback by partially posting back . Which means that you need to send an asynchronous request with out refreshing whole page.
It is possible by using AJAX. You can either use
MVC Ajax or Jquery Ajax.
By using AJax, we can eliminate the post back and then do the partial post back.
Solution:
$("#dropdownid").change(function(event e)
{
//Make your ajax request here..
});
Hope this helps
Updated:
$("#dropdownid").change(function () {
$.ajax({
type: "post",
contentType: "application/json;charset=utf-8",
url: /*Your URL*/,
success: function (data) {
//do your callback operation
}
});
});
Got it.
Passing Empid as querystring from jquery like:
<script>
$(document).ready(function () {
$("#ddlemployee").change(function () {
debugger;
var empid = $("#ddlemployee").val();
location.href = '#Url.Action("GetEmployeeDetails", "Employer")?empid=' + empid ;
});
});
</script>
and assign "empid " to model "Empid" in Action method before foreach loop like
model.EMP_ID = empid;//in Controller Action Method before foreachloop of my code
// and this model.EMP_ID binded to dropdownlist.
this EMP_ID passes same id to dropdownlist which was selected. Thats it.
I have a view (Index.cshtml) with a grid (Infragistics JQuery grid) with an imagelink. If a user clicks on this link the following jquery function will be called:
function ConfirmSettingEnddateRemarkToYesterday(remarkID) {
//Some code...
//Call to action.
$.post("Home/SetEnddateRemarkToYesterday", { remarkID: remarkID }, function (result) {
//alert('Succes: ' + remarkID);
//window.location.reload();
//$('#remarksgrid').html(result);
});
}
Commented out you can see an alert for myself and 2 attempts to refresh the view. The location.reload() works, but is basically too much work for the browser. The .html(result) posts the entire index.cshtml + Layout.cshtml double in the remarksgrid div. So that is not correct.
This is the action it calls (SetEnddateRemarkToYesterday):
public ActionResult SetEnddateRemarkToYesterday(int remarkID) {
//Some logic to persist the change to DB.
return RedirectToAction("Index");
}
This is the action it redirects to:
[HttpGet]
public ActionResult Index() {
//Some code to retrieve updated remarks.
//Remarks is pseudo for List<Of Remark>
return View(Remarks);
}
If I don't do window.location.reload after the succesfull AJAX post the view will never reload. I'm new to MVC, but i'm sure there's a better way to do this. I'm not understanding something fundamental here. Perhaps a nudge in the right direction? Thank you in advance.
As you requesting AJAX call, you should redirect using its response
Modify your controller to return JSONResult with landing url:
public ActionResult SetEnddateRemarkToYesterday(int remarkID) {
//Some logic to persist the change to DB.
var redirectUrl = new UrlHelper(Request.RequestContext).Action("Index", "Controller");
return Json(new { Url = redirectUrl });
}
JS Call:
$.post("Home/SetEnddateRemarkToYesterday", { remarkID: remarkID }, function (result) {
window.location.href = result.Url
});
After Ajax post you need to call to specific Url..
like this..
window.location.href = Url
When using jQuery.post the new page is returned via the .done method
jQuery
jQuery.post("Controller/Action", { d1: "test", d2: "test" })
.done(function (data) {
jQuery('#reload').html(data);
});
HTML
<body id="reload">
For me this works. First, I created id="reload" in my form and then using the solution provided by Colin and using Ajax sent data to controller and refreshed my form.
That looks my controller:
[Authorize(Roles = "User")]
[HttpGet]
public IActionResult Action()
{
var model = _service.Get()...;
return View(model);
}
[Authorize(Roles = "User")]
[HttpPost]
public IActionResult Action(object someData)
{
var model = _service.Get()...;
return View(model);
}
View:
<form id="reload" asp-action="Action" asp-controller="Controller" method="post">
.
.
.
</form>
Javascript function and inside this function I added this block:
$.ajax({
url: "/Controller/Action",
type: 'POST',
data: {
__RequestVerificationToken: token, // if you are using identity User
someData: someData
},
success: function (data) {
console.log("Success")
console.log(data);
var parser = new DOMParser();
var htmlDoc = parser.parseFromString(data, 'text/html'); // parse result (type string format HTML)
console.log(htmlDoc);
var form = htmlDoc.getElementById('reload'); // get my form to refresh
console.log(form);
jQuery('#reload').html(form); // refresh form
},
error: function (error) {
console.log("error is " + error);
}
});
I'm wondering if it is possible to achieve the following.
Within an MVC application -
Have a link which queries a database for some values, sets those values as session variables and then opens a pop-up window(which is an asp.net webform within the MVC app)
It's basically to allow us to run Crystal Reports, the link would set the Report ID in a session variable which would then be accessible in the asp.net webform.
My confusion is the setting of the session variable on click of the link and then opening the popup.
Can it be done and if so any links or pointers?
Edit:
Javascript
<script language="javascript" type="text/javascript">
function flagInappropriate(postId) {
var url = "/Home/FlagAsInappropriate/" + postId;
$.post(url, function(data) {
if (data) {
alert("True")
} else {
// callback to show error/permission
}
});
}
Controller
namespace MvcApplication1.Controllers
{
[HandleError]
public class HomeController : Controller
{
[AcceptVerbs("POST")]
public bool FlagAsInappropriate(int id)
{
// check permission
bool allow = true;
// if allow then flag post
if (allow)
{
// flag post
return true;
}
else
{
return false;
}
}
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
return View();
}
}
}
It can be done, yes. I've achieved something similar for the purposes of generating reports (predominantly so the report URL is hidden from the user and so some tracking and authentication could be achieved using once-off tokens). My solution was as follows:
Perform an AJAX call to a Web Method in your application to set the relevant session variable(s).
Return a value from the Web Method to indicate whether it was successful.
For the "success" event handler of the AJAX call, open your relevant ASPX page to generate the report.
Simple as that. :)
Here's some sample code to attach the click event and do the AJAX call, based on your amended question:
Click to test AJAX call
<script type="text/javascript">
$(document).ready(function () {
$(".flag").click(function () {
flagInappropriate($(this).attr("id").split("-")[1]);
});
});
function flagInappropriate(postId) {
var url = "/Home/FlagAsInappropriate/" + postId;
alert(url);
$.post(url, function (data) {
if (data) {
alert(data);
} else {
// callback to show error/permission
}
});
}
</script>
Is there any convenient way to integrate ASP.NET MVC validation (I am primarily interested in Fluent Validation) with forms submitting by Ajax?
The easiest way to achieve this is to place those forms inside partials and then submit them using AJAX. The controller action which will handle the POST will check if the model is valid and if not return the partial in order to show the validation errors. For example:
<div id="myform_container">
<!-- The _Foo partial will contain a form -->
#Html.Partial("_Foo")
</div>
and a controller action which will handle the submission:
[HttpPost]
public ActionResult Foo(SomeViewModel model)
{
if (!ModelState.IsValid)
{
return PartialView("_Foo", model);
}
// TODO: process the results and inform the user that everything went fine:
return Json(new { success = true });
}
Now all that's left is to AJAXify this form in a separate javascript file:
$(function() {
// Use delegate to preserve the .submit handler when we refresh the container
$('#myform_container').delegate('form', 'submit', function() {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function(result) {
if (result.success) {
// the server returned JSON
alert('thanks for submitting');
} else {
// the server returned the partial => update the DOM
$('#myform_container').html(result);
}
}
});
return false;
});
});
Here is my problem:
Inside a jQuery dialog I have the following code:
<%:Ajax.ActionLink("Yes", "SendClaim", "Claim", new { id = Model.ExpenseId }, new AjaxOptions { UpdateTargetId = "dialog" }, new { #class = "button" })%>
When stuff fails in the controller based on roles I return a partial view that replaces the existing dialog (see UpdateTargetId = "dialog").
When everything works I want to do a redirect to another page (an index of all claims) to stop the user performing additional actions but this entire page is rendered inside the jQuery dialog due to it being an ajax request with an update id.
What is the correct way to approach the problem?
I'm a bit of a novice, but I find I have more control with the following approach instead of using Ajax.ActionLink. Hopefully it helps and I have understood what you want to do correctly.
Claim Controller:
[AcceptVerbs(HttpVerbs.Post)]
public Json Send(int expenseId)
{
// Check user stuff
if(valid)
// do stuff
return new Json(true, JsonRequestBehavior.AllowGet);
else
return new Json(false, JsonRequestBehavior.AllowGet);
}
jQuery
function submitClaim() {
$.ajax({
url: "/Claim/Send",
type: "POST",
dataType: "json",
data: { 'expenseId': <%=Model.ExpenseId> },
success: function (data) {
if(data) { // if successful, redirect
document.location = "Claim/Index";
}
else { //load your partial view into your dialog
$("#idOfYourDialog").load('Claim/Error/');
}
},
error: function (xhr) { }
});
}
html
Submit
Returned an 'All OK' dialog and had the following javascript when the user clicks the ok button:
function redirect() {
document.location = "<%:(String)ViewBag.Redirect %>";
}
$(document).ready(function() {
$(".ui-dialog-titlebar-close").click(function() {
redirect();
});
});
Seems unavoidable - you can't seem to do an RedirectToAction when the controller action has been called from Ajax.ActionLink as the response will be stuck into the updatetargetid.