Html.RenderAction using AJAX - c#

Is it possible to use HTMl.RenderAction using ajax to provide the parameter?
I have a controller action like this
[ChildActionOnly]
Public ActionResult EmployeeData(string id)
{
Employee employee = new Employee();
//do work to get data
Return PartialView(employee);
}
The partial view is just a small table with some employee data (name, address, etc)
I then have a page with a drop down list of employees with the data field being the id needed for EmployeeData(string id)
I would like to use ajax so when a employee is selected from a drop down list the EmployeeData partial view will appear below it without refreshing the page. Then again if another employee is selected.
Though i am not sure how to do this, if it is possible.
As was recommended here is what I have now. (please don't mind that this is not the employee data example i mentioned above, that data is not ready in the DB and I have multiple areas that will do this same thing so I decided to work on this one today)
here is my the JS in my view
$("#repList").change(function () {
var id = $("#repList").val();
$.ajax({
url: '/Reporting/GetSalesTargets/' + id,
success: function (result) {
$("#partialdiv").html(result);
},
error: function () {
alert("error");
}
});
});
I am getting to the controller action that will return the view, here is it.
public ActionResult GetSalesTargets(string id)
{
int month = DateTime.Now.Month;
SalesMarketingReportingService mktSrv = new SalesMarketingReportingService();
SalesTargetModel model = mktSrv.GetRSMSalesTargetModel(id, month);
return PartialView(model);
}

It is possible but you have to remove the [ChildActionOnly] attribute. The it becomes a normal action that returns a partial view the you could invoke using AJAX:
$.ajax({
url: '/home/employeedata/123',
success: function(result) {
$('#somedivid').html(result);
}
});

Related

Call Method in Controller from View(cshtml)

Hi im trying to call a method from controller from view just to display the "staff_name"
Controller
public JsonResult getStaffName(int staff_id)
{
var staffname = (from a in db.master_staff where b.staff_id == staff_id
select a.staff_name).SingleOrDefault();
return Json(staffname,JsonRequestBehavior.AllowGet);
}
View
int[] staff_id = { 24,25,26 };
#foreach (var n in staff_id){
//call method getStaffName from Controller to get "staff_name"
}
it suppose to get the "staff_name" according to the "staff_id"
is there any possible method for this situation?
To call method from controller to view you have to use ajax call from view.
here is ajax call syntax in asp.net mvc:
$.ajax({
type: "GET",
url: '#Url.Action("controller method name", "controller name")',
data: { searchText: value },
contentType: "application/json; charset=utf-8",
dataType: 'json',
success: function (result) {
},
error: {
}
});
type can be GET or POST depending on your controller method type.
In URL attribute two parameters are passed the first one is controller method name and second one is controller name.
In data attribute you have to pass the values which are required to pass in controller from view such as parameters in controller method.
In success and error attribute you have to write a block of code which should be executed in both cases. such as display data on UI upon success and error message on failure.
Do not do this. It is the way to the Dark side :) And each JSON request is taking some time.
Create model to store your staff
Fill it in controller (or even better in some business logic class)
Display in your view
public ActionResult Staff()
{
// This would be nice to have as separate Data Access Layery class
var staffs = GetStaffs();
return View(staffs);
}
private static StaffDto[] GetStaffs()
{
// One call to database is better that several
var staffs = db.master_staff
.Where(x => x.staff_id > 0) // Any other condition, if needed
.Select(x => new StaffDto(x.staff_id, x.staff_name))
.ToArray();
return staffs;
}
// Data Transfer Object class to separate database from presentation view
public class StaffDto
{
public int StaffId { get; set; }
public string Name { get; set; }
public StaffDto(int staffId, string name)
{
StaffId = staffId;
Name = name;
}
}
Your view file (Staff.cshtml in my case)
#model IEnumerable<TestMvc.Controllers.StaffDto>
<div>
#foreach (var staff in Model)
{
#staff.Name<br />
}
</div>
And, as bonus, you could unit test it easily
private readonly HomeController _homeController = new HomeController();
[TestMethod]
public void Staff_CheckCount()
{
var result = _homeController.Staff();
Assert.IsInstanceOfType(result, typeof(ViewResult));
var actual = ((ViewResult)result).Model as StaffDto[];
Assert.IsNotNull(actual);
Assert.AreEqual(3, actual.Length);
}
You can do it like this:
#Html.Action("getStaffName", "YourController", staff_id)
For more info, look at child actions: https://haacked.com/archive/2009/11/18/aspnetmvc2-render-action.aspx/
However, I do not know what you are trying to achieve with this.

MVC: When returning from the controller on Ajax call, the result is undefined

I'm making an Ajax call to the controller when clicking on a Kendo button and return the model:
#(Html.Kendo().Button()
.Name("btnSubmit")
.HtmlAttributes(new { type = "button" })
.Icon("rotate")
.Content("View Details"))
<script>
$("#btnSubmit").click(function () {
$.ajax({
url: "/MyController/MyMethod/",
type: 'post',
dataType: "json",
contentType: 'application/json; charset=utf-8',
success: function (result) {
window.location.href = "#Url.Action("RedirectToView", "MyController", new { myModel = "data" })".replace("data", result);
}
})
});
</script>
The controller's method returns the model:
[AcceptVerbs(HttpVerbs.Post)]
public JsonResult MyMethod()
{
var reportDate = Session["FileDate"] == null ? DateTime.Now : Convert.ToDateTime(Session["FileDate"].ToString());
var myModel = new MyModel();
myModel.ColOfData = myModel.GetColOfData(reportDate);
return Json(myModel, JsonRequestBehavior.AllowGet);
}
When I debug my Ajax function, result is undefined. The result should be assigned to MyModel, since I'm returning the model back to an Ajax function. I need to pass that result to another method in the controller that would return my Partial View containing the Grid:
public ActionResult RedirectToView(MyModel myModel)
{
return PartialView("_MyPartialView", myModel);
}
What am I doing wrong?
Your problem isn't related to kendo.
From your controller you have to return a json object like this
return Json(new {result=myModel});
And in your ajax result you will have your entire model.
After that from the code you provided I am afraid you can't pass your entire model in the url of your GET.
You could probably pass the model Id like that
window.location.href = "#Url.Action("RedirectToView", "MyController", new { id= "modelId" })".replace("modelId", result.Id);
And make your action something like that
public ActionResult RedirectToView(string id){
// Get the model data you want .....
return PartialView("_MyPartialView", myModel);
}

Refresh a Partial View after calling a controller method from AJAX

This is my first MVC project and I've been trying to figure out how to refresh a Partial View after calling a controller method from AJAX.
My classes look like this and I want to add as many courses as I want for a semester in one view.
public class CourseViewModel
{
public int SemesterID {get; set;}
public List<Course> Courses {get; set;}
}
public class Course
{
public string CourseID {get; set;}
public string CourseTitle {get; set;}
}
An Example page looks like this:
In my view, I set up a typeahead for the Course textbox. When a user select a course from a list of typeahead suggestion, I call the SaveCourse method in the controller and it successfully saves. The problem is that I cannot refresh the Partial View after the save occurs.
My View (Index.cshtml):
#using Project.ViewModels;
#model Project.ViiewModels.CourseViewModel
<div id="divCourseTypeahead">
<input class="typeahead form-control" type="text" />
</div>
<div id="listCourses">
#{Html.RenderPartial("_CourseList");}
</div>
<script type="text/javascript">
$(document).ready(function () {
$('#divCourseTypeahead .typeahead').typeahead({
//setup typeahead
}).on('typeahead:select', function(obj, datum){
var semesterId = #Model.SemesterID
$.ajax({
type: "GET",
url: "/Course/SaveCourse/",
data: { semesterId: semesterId, courseId: datum.id },
success: function (result) {
alert(result);
}
});
});
</script>
What I've tried (1):
I tried return a PartialVeew from SaveCourse.
public PartialViewResult SaveCourse(int semesterId, string courseId)
{
//Insert course
CourseViewModel data = new CourseViewModel(semesterId);
return PartialView("_CourseList", data);
}
When I do this, the PartialView does not get refreshed and the alert(result); in ajax success function does not get called.
What I've tried (2):
public ActionResult SaveCourse(int semesterId, string courseId)
{
//Insert course
return RedirectToAction("Index", "Course", new {id=semesterId});
//in Index, I return `CourseViewModel`
}
When I do this, the alert(result); in AJAX success function gets called so I added $('#listCourses').html(result); in the success function then the PartialView does refresh but I get two textboxes like the image below.
I've tried many other options but I am so confused. Could someone please help me how I can achieve what I want to do?
You have a couple of problems in your document.ready function.
1. You're passing
courseId: datum.id
However, datum object can't be seen anywhere in the javascript function.
Maybe you're defining it somewhere else.
instead of alert line I suggest write
$('#listCourses').html(result);
Also, Remove #{Html.RenderPartial("_CourseList");}, because since _CourseList partial view requires a list model, and you're not providing it during render. So the page will not load.
I could achieve below result with these changes.

Passing list to javascript to pass back to controller

I'm using ASP.NET MVC and my model has a list as part of it. I want to pass that list to a javascript function and inside this function I turn around and want to pass it back to a controller.
Currently I have:
#Html.ActionLink("Edit", "Edit", "Data", new { onclick = string.Format("EditRecord({0});", Model.Types) })
Model.Types is defined as List
My javascript EditRecord is defined as:
function EditRecord(types)
{
$.post("/Data/Edit/" { myTypes: types });
}
My controller is define as:
[HttpPost]
public ActionResult Edit(string[] myTypes)
{
return View();
}
When I run this I get page can't be found. If I switch this from the list to just a normal data type like an int or string then it all works, so something with the fact that it's an array is throwing this off. Any ideas?
Here goes my solution, Lets say you have a model holding List property in following way -
public class MyModel
{
public List<string> Types { get; set; }
}
This model will be constructed in the following controller action and will be returned to the View -
public ActionResult Index()
{
MyModel model = new MyModel();
model.Types = new List<string>();
model.Types.Add("Admin");
model.Types.Add("User");
model.Types.Add("SuperAdmin");
return View(model);
}
And the View has following Html -
#model Rami.Vemula.Dev.Mvc.Controllers.MyModel
#{
ViewBag.Title = "Home Page";
}
<div class="row">
Click me
</div>
Now the JQuery part which will hold the logic to send the List to the controller action -
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script>
$(document).ready(function () {
$("#ClickMe").click(function () {
var o = new Object();
o.Types = #Html.Raw(Json.Encode(Model.Types));
jQuery.ajax({
type: "POST",
url: "#Url.Action("GetJson")",
dataType: "json",
contentType: "application/json; charset=utf-8",
data: JSON.stringify(o),
success: function (data) {
alert(data);
},
failure: function (errMsg) { alert(errMsg); }
});
});
});
</script>
Then on clicking the button, it will hit the following controller -
public JsonResult GetJson(List<string> Types)
{
return Json(Types, JsonRequestBehavior.AllowGet);
}
When you click the button, and put a breakpoint to check the values -
By this your controller is returning blank view. Make sure that your view is created (right click-go to view). And if you want to return it it should be something like this:
rerurn View(myTypes);
But make sure that myTypes view is set up to accept string[].
if you want to pass your list to client consider ajax call that will send json object array and adjust your backend to accept it.

Why does my action not return a view?

I have this page, where I select an item from a dropdown list, and an ajax call passes along the selected parameter to a new action in my controller, like this:
function select(e) {
var unit = $("#unitList").data("kendoDropDownList").value();
var url = '#Url.Content("~/Reports/UnitRunReport/")';
$.ajax({
url: url,
data: { selectedUnit: unit },
type: 'GET',
dataType: 'json',
success: function (data) {
//
},
error: function () {
//
}
});
}
Here's my controller:
public class ReportsController : BaseController
{
public ReportsViewModel Model { get; set; }
//
// GET: /Reports/
public ActionResult Index()
{
Model = new ReportsViewModel
{
Units = UnitClient.GetListOfUnits(true, "")
};
return View(Model);
}
[HttpGet]
public ActionResult UnitRunReport(string selectedUnit)
{
var unit = Convert.ToInt32(selectedUnit);
Model = new ReportsViewModel
{
UnitRuns = RunClient.GetRunListForUnit(unit)
};
return View(Model);
}
}
I have to separate views for the two actions (Index and UnitRunReport). When debugging, it passes along the correct parameter to the UnitRunReport action, and moves through the return View(Model) statement. Could someone please explain why I'm not redirected to the new UnitRunReport View from the Index page?
You are in an ajax call. The ajax call will not redirect the page.
Redirect to the get method instead:
window.location = "#Url.Content("~/Reports/UnitRunReport")?selectedunit=" + $("#unitList").data("kendoDropDownList").value();
You are not redirected because you are making the call using ajax. This by definition means that the page will not change. The result of the ajax call (in this case the ActionResult returned by the UnitRunReport method) will be returned into the data parameter of the success delegate you are providing to jQuery.
You could fix this by passing in a success delegate to swap the html on the page (or in an element on the page with the result of the call) e.g. If you had an element with the id dataElement then use this in you success callback
success: function (data) {
$("#dataElement").html(data);
}
Note you are returning html back from your controller method. You may want to return a json model and bind that to your page using a library like knockout.
If you want to actually redirect to the page rather than making an ajax call like you are currently doing then you need to set the window.location property when the user changes the selection in the dropdown. This will cause the whole page to reload and render the view that UnitRunReport returns into a new page.
First of all you are making a ajax request which will not redirect the page but just read the data from the action.
Secondly, you are requesting for the json result which will give you the json data.
It looks like you're trying to get JSON data back rather than a view, which is typically HTML. So your controller should look like the following.
public class HomeController : Controller
{
public ReportsViewModel Model { get; set; }
//
// GET: /Reports/
public ActionResult Index()
{
Model = new ReportsViewModel
{
Units = UnitClient.GetListOfUnits(true, "")
};
return View(Model);
}
[HttpGet]
public ActionResult UnitRunReport(string selectedUnit)
{
var unit = Convert.ToInt32(selectedUnit);
Model = new ReportsViewModel
{
UnitRuns = RunClient.GetRunListForUnit(unit)
};
return this.Json(Model, JsonRequestBehavior.AllowGet);
}
}
You can test the data coming back in your javascript by doing a console.log. Also instead of doing Url.Content try Url.Action because your routes may not be setup correctly and url.action will make sure that the correct route will get generated.
function select(e) {
var unit = $("#unitList").data("kendoDropDownList").value();
var url = '#Url.Action("UnitRunReport", new { controller = "Home" })';
$.ajax({
url: url,
data: { selectedUnit: unit },
type: 'GET',
dataType: 'json',
success: function (data) {
console.log(data);
// do something with the data coming back
},
error: function () {
// show some sort of message
}
});
}
To view the console just hit F12 to get your tools to pop up in your favorite browser (I'm still a firebug fan). Just be careful about deploying anything with console.log into production, these days it doesn't usually matter because people have newer browsers but you may still get those one or two that will slip by and have issues. If you want to keep the code in there and put it into production you can launch a script with your pages into production to override console.log
<script type="text/javascript">
console = {
log: function (s) {
// empty method to override console
}
};
</script>
Put that in your site.master and remove it during development, you can keep all your console.logs and when going to production they'll stop showing up.
Because you're doing an Ajax call to the action method, so the view will be returned in the data parameter here: function (data)
It will not redirect the browser.

Categories