Updating textarea in asp.net razor while performing tasks - asp.net-mvc

I am using asp.net mvc 4 razor and I have a main view that has some checkboxes and a submit button. Those checkboxes indicates the tasks to be performed. User selects the tasks to be performed through the checkboxes and then he launch the process by clicking on the submit button.
Once the submit button is clicked, a the controller associated to this view is called. Within the controller I want to do the following:
1) Open another different view which has a textarea.
2) While controller is performing the tasks selected by the user, I want to update the textarea of the new view just opened (step 1).
3) When controller finishes the tasks I want to stay in the new view just opened (step 1) to wait user action through buttons (return to the previous main view).
Note: The update of the textarea is synchronous.
For example:
Controller:
public ActionResult PerformTasks(ViewModel model)
{
// model contains the values of the checkboxes. With this I know which tasks to perform.
UpdateTextArea("Beginning tasks...");
// ##### Do first task
UpdateTextArea("Doing task #1...");
// Do some stuff for task #1
// ##### Do second task
UpdateTextArea("Doing task #2...");
// Do some stuff for task #2
(...)
// ##### Doing last task
UpdateTextArea("Doing task #N...");
// Do some stuff for task #N
UpdateTextArea("Tasks completed.");
// At the end of the process, new view just opened with contains the textarea
// must remain to user action.
return ¿?
}
The Output in the textarea for the new view just opened would be:
- Textarea content at the end of the process -
Beginning tasks...
Doing task #1...
Doing task #2...
Doing task #3...
...
Doing task #N...
Tasks completed.
How can I do this in an easy way? I do not want to use any third-party frameworks as this web app is very little.
To make it easier, the textarea could be in the same main view rather than in another different new view.
FIRST ATTEMPT (AminSaghi solution):
The main view has the following aspect now (simplified to 2 tasks):
(see at the end my issues when trying to implement it)
#using (Html.BeginForm(
"PerformTasks", "Tests", FormMethod.Post,
htmlAttributes: new { id = "frm" }))
{
(...)
#Html.CheckBoxFor(m => m.task01)<span>Task 1</span><br />
#Html.CheckBoxFor(m => m.task02)<span>Task 2</span><br />
(...)
<input type="submit" value="Do Tasks" />
<div id="divStatus">
</div>
}
<script type="text/javascript">
// First ajax script
$("#frm").submit(function (event) {
$("#frm").validate();
if ($("#frm").valid()) {
$.ajax({
url: "/Tests/PerformTasks/",
type: 'POST',
data: $("#frm").serialize(),
success: function() {
perFormTask1();
},
beforeSend: function() {
$("#divStatus").append('<br/>Begginig tasks...<br/>');
}
});
event.preventDefault();
}
});
// second ajax script
function performTask1() {
$.ajax({
url: "/Tests/Task1/",
type: 'POST',
data: $("#frm").serialize(),
success: function() {
$("#divStatus").append('Task1 completed.<br/>');
perFormTask2();
},
beforeSend: function() {
$("#divStatus").append('<br/>Begginig task 1...<br/>');
}
});
};
function performTask2() {
$.ajax({
url: "/Tests/Task2/",
type: 'POST',
data: $("#frm").serialize(),
success: function() {
$("#divStatus").append('Task2 completed.<br/>');
},
beforeSend: function() {
$("#divStatus").append('<br/>Begginig task 2...<br/>');
}
});
};
</script>
Controller (TestsController.cs under \Controllers):
public class TestsController : Controller
{
[HttpPost]
public ActionResult PerformTasks(ViewModel model)
{
// Nothing to do here, tasks are done individually in the methods below.
// To stay in the same page after submit button is clicked
return Redirect(this.Request.UrlReferrer.AbsolutePath);
}
[HttpPost]
public ActionResult Task1(ViewModel model)
{
// Task 1 should be done if checkbox in the main view is checked, otherwise not.
bool doTask1 = model.task01;
if (doTask1 )
{
// Do some stuff
}
// To stay in the same page after submit button is clicked
return Redirect(this.Request.UrlReferrer.AbsolutePath);
}
[HttpPost]
public ActionResult Task2(ViewModel model)
{
// Task 2 should be done if checkbox in the main view is checked, otherwise not.
bool doTask2 = model.task02;
if (doTask2)
{
// Do some stuff
}
// To stay in the same page after submit button is clicked
return Redirect(this.Request.UrlReferrer.AbsolutePath);
}
}
The model:
public class ViewModel
{
public bool task01{ get; set; }
public bool task02{ get; set; }
}
Things I do not understand and I do not kwnow how to do:
1.- Once submit button is clicked, how to launch first ajax script in order to start the tasks sequence?
2.- Action PerformTasks as I understand should be leave empty, only return to the same page line should be put, am I right, because it
only launches the others in the ajax script.
3.- What is #frm in the ajax script? should i replace with something?
4.-I think for the last task, in this case task 2, is not necessary to do another ajax script as this is the last, Am I right?
5.-If some task fails, for example task 1, below tasks should be done, in this case task 2. How to do this?
6.-For each task I should pass some data, the status of all checkboxes and the within each action in the controller check if
this task has been checked to be done. If so, task is performed, if
not, task is not performed. How to pass this data to tasks, 1 and 2?
through data element in ajax?

One way is to brick your action method into separate task:
public ActionResult PerformTasks(ViewModel model)
{
//
}
public ActionResult Task1(string param1, string param2, ...)
{
//
}
public ActionResult Task2((string param1, string param2, ...)
{
//
}
// and so on...
Then, in your view, put each of them into the ajax success option of its previous task ajax request:
$.ajax({
url: "/Controller/PerformTasks/",
type: 'POST',
data: $("#frm").serialize(),
success: function() {
perFormTask1();
},
beforeSend: function() {
$("#divStatus").append('<br/>Begginig tasks...<br/>');
}
});
And function performTask1 can be like the following:
$.ajax({
url: "/Controller/Task1/",
type: 'POST',
data: ... // here or by query string,
success: function() {
$("#divStatus").append('Task1 completed.<br/>');
perFormTask2();
},
beforeSend: function() {
$("#divStatus").append('<br/>Begginig task 1...<br/>');
}
});
And so on for other tasks...
So, the semi-complete how-to is like the following:
1) Change your Html.BeginForm() like this:
#using(Html.BeginForm(
"action", "controller", FormMethod.Post,
htmlAttributes: new { id = "frm"}))
{
// in fact, in our situation,
// there is no matter to put correct values in action and controller parameters
// because we'll override them and do our job through ajax...
}
2) Add the following script into your view:
<script>
$("#frm").submit(function (event) {
$("#frm").validate();
if ($("#frm").valid()) {
$.ajax({
url: "/Controller/PerformTasks/",
type: 'POST',
data: $("#frm").serialize(),
success: function () {
perFormTask1();
},
beforeSend: function () {
$("#divStatus").append('<br/>Begginig tasks...<br/>');
}
});
event.preventDefault();
}
});
function performTask1() {
$.ajax({
url: "/Controller/Task1?param1=data1&param2=data2 ...",
type: 'POST',
success: function() {
$("#divStatus").append('Task1 completed.<br/>');
perFormTask2();
},
beforeSend: function() {
$("#divStatus").append('<br/>Begginig task 1...<br/>');
}
});
}
// and also for other task, add similar performTask functions...
</script>

Related

Print out to a div in the view from the controller

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);
}
});
}
}
});
}

Return PartialView from JsonResult ActionMethod back to ajax post and display that PartialView as a Modal pop-up

I am trying to return back PartialView or any other view from action method back to ajax post. I wanted to display the contents ParitalView as a Jquery Modal pop-up from ajax success function or whichever way its possible.
'MyRegistrationView' with Registration Form on it has below mentioned ajax post call on form submit button.
$.ajax({
url: url, //http://localhost/MyRegistration/RegisterUser
type: 'POST',
dataType: 'json',
data: ko.toJSON(RegistrationInfoModel),
contentType: "application/json; charset=utf-8",
success: function (result) {
//Do something
},
error: function (request, status, error) {
//Do something
}
});
The above ajax call goes to my Controller named " MyRegistrationController" with the action method as below.
[HttpPost]
public JsonResult RegisterUser(RegistrationInfo model)
{
//Register User
....
if(successful)
{
return Json(new { data = PartialView("_ShowSuccessfulModalPartial") });
}
}
Now
how can i get back the 'content' of '_ShowSuccessfulModalPartial' in
'Success' function of ajax and show that as the Modal Pop up on that
same registration page.
If i want to return/redirect it to some other view how can i do it
if i have JsonResult as return type of my ActionMethod.
How I can send back the ModalErrors from registration process back
to my view and show them under ValidationSummary.
(Note: If I don't use JsonResult as return type i get ajax 'parseerror' Unexpected token <)
You can return a partial view instead of a json.
In your main view you shoudl add the dialog html like this (assumming you're using jQueryUI):
<div id="dialog-confirm" title="Your title">
<div id="dialog-content"></div>
</div>
Make sure you initialize the dialog.
$(document).ready(function() {
$("#dialog-confirm").dialog();
});
In the controller you might need to return a partial view:
[HttpPost]
public virtual ActionResult RegisterUser(RegistrationInfo model)
{
var model = //Method to get a ViewModel for the partial view in case it's needed.
return PartialView("PartialViewName", model);
}
Then when you do your ajax request, you append the partial view to the dialog and then show it.
$.ajax({
url: url,
type: 'POST',
dataType: 'json',
data: ko.toJSON(RegistrationInfoModel),
contentType: "application/json; charset=utf-8",
success: function (result) {
$("#dialog-content").empty();
$("#dialog-content").html(result);
$("#dialog-confirm").dialog("open");
},
error: function (request, status, error) {
//Do something
}
});
Hope this helps.

Ajax form validation

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;
});
});

How to manage MVC AJAX responses when in a jQuery dialog

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.

MVC: I delete a row from my grid, but my page does not refresh

I have a Html.Helper that I use to delete rows from my grid.
It calls the following method on my controller;
[AcceptVerbs(HttpVerbs.Delete)]
public ActionResult Delete(int _employeeOtherLeaveId)
{
EmployeeOtherLeaf.Delete(_employeeOtherLeaveId);
return RedirectToAction("Payroll");
}
This calls the GET method on my controller which I would expect to refresh the view of my grid, but it doesn't. When I manually refresh I see the row has in fact been deleted. Why is this?
[HttpGet]
public ActionResult Payroll()
{
if ((SessionObjects.PeriodStartDate > DateTime.MinValue) && (SessionObjects.PeriodEndDate > DateTime.MinValue))
if (SessionObjects.PayrollSelectedEmployeeId == 0)
return View(new PayrollViewModel()
{
PeriodStartDate = SessionObjects.PeriodStartDate,
PeriodEndDate = SessionObjects.PeriodEndDate
});
else
return View(new PayrollViewModel(
SessionObjects.PeriodStartDate,
SessionObjects.PeriodEndDate,
SessionObjects.PayrollSelectedEmployeeId
));
return View();
}
This will depend how you are calling the DELETE action. Judging from your previous question and the answer you accepted I suppose that you are doing the following:
onclick="$.ajax({url: this.href, type: 'DELETE'}); return false;"
which obviously is insufficient as you are sending the AJAX request to delete but you aren't handling the success event to update the DOM. So you might need to do this:
$.ajax({
url: this.href,
type: 'DELETE',
success: function(result) {
// update some DOM element with the result returned by the
// server. So supposing that you have some <div id="someContainer">
// that will contain the part of the DOM you want updated:
$('#someContainer').html(result);
}
});
return false;
Now obviously stuffing all this javascript inside the HTML as you were using your custom helper is ugly. Personally I would use unobtrusive javascript. I would have my helper generate a normal anchor with a class and then in a completely separate javascript file I would AJAXify this link:
$(function() {
// AJAXify the anchor with the delete class that would
// be generated by your custom helper
$('.delete').click(function() {
$.ajax({
url: this.href,
type: 'DELETE',
success: function(result) {
// update some DOM element with the result returned by the
// server. So supposing that you have some <div id="someContainer">
// that will contain the part of the DOM you want updated:
$('#someContainer').html(result);
}
});
return false;
});
});

Resources