C# MVC 3 Partial View not hitting controller method - c#

I have a create user page - it currently list a table with all current users in system. I can click create new button - this does a jQuery ajax submit which calls my controller method and returns a partial view and loads the new modal jQuery dialog box which contain all the fields i.e Forename, Surname, etc. So I have my table in the background and this dialog box on centre of screen in modal view so it takes precedence. If a username is clicked the same method is called excpet a uniquie user id is passed in so the dialog form is not loaded blank - it is loaded with the current details of the user from the DB and as a user id was there a Delete button is added to the User dialog box as well as Save and Cancel which are there on create new.
Now for the problem - I have enclosed my Partial view page as below - I have also added its own js to the partial view as I need to show/hide diff dropdown boxes based on some choices made by user.
#using (Html.BeginForm("UserAction", "Admin", FormMethod.Post, new { id = "userActionForm" }))
{
//Fields on the dialog box....
}
on the dialog box then - I have buttons i.e
<input id="DoDeleteUser" type="button" class="dialog-button" value="Delete User" style="margin: 5px" />
and then in the JS file for my page I have the following:
$('#DoDeleteUser').click(function (event) {
//alert("Delete Button Pressed"); - In for debugging
$('#userID').val($(event.target).attr("userId")); - get id value into hidden field on page
$('action').val('Delete'); - put action string into hidden field on page
$('#userActionForm).submit();
});
$('#userActionForm').submit(function () {
var formData = $("#userActionForm").serializeArray();
$.ajax({
url: this.action,
type: this.method,
data: formData,
success: function (result) {
$('#dialogContainer').html(result);
}
});
return false;
});
My dialog container is the same container which the first page loads which I want to update when I come back from the UserAction method with a simple message saying "User Updated" or "User Deleted" and an OK button which when clicked would refresh the whole page (so the main table would be updated)
Then on my controller I have the method like:
public ActionResult UserAction(UserModel model)
{
if (ModelState.IsValid)
{
if(model.Action == "Delete")
//Go and do delete
return PartialView ("UserActionSuccess", model);
//close if etc etc
However I set a breakpoint on my UserAction method in my controller but it is never getting hit when I hit the Delete User button or the Save User button which is were I am stuck.

You're sending your post with form data, but you're expecting a model (json object) on your UserAction. You should use parameters instead to match the form input.
public ActionResult UserAction(string id)
{
...
}

You should consider using message classes for CRUD methods. It should make the logic a bit cleaner.
public class CreateUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class DeleteUser
{
public int UserId { get; set; }
}
Then you would have a controller action for each CRUD method, like so:
public ActionResult Create(CreateUser message)
{
}
public ActionResult Delete(DeleteUser message)
{
}
In jQuery, you would prepare the AJAX call as follows:
$.ajax({
url: "/yourcontroller/create",
type: "POST",
data: formData,
success: function() { console.log('success'); },
error: function() { console.log('error'); }
});
$.ajax({
url: "/yourcontroller/delete/" + $("#userId").val(),
type: "DELETE",
success: function() { console.log('success'); },
error: function() { console.log('error'); }
});
Finally, once you wire those up, you can use Firebug to check the jQuery side of things, and then use breakpoints in VS administrator mode to make sure the calls are populating your message objects correctly.

Related

Display Values based on dropdown selection MVC

I have a requirement which I need to display details based on drop down selection. These details coming from database. when I click one user all then all the details belong to that user has to be displayed.
Model class
public class TaskDetails
{
public string ProjectID { get; set; }
public string ProjectName { get; set; }
public DateTime StartDate { get; set; }
public DateTime EstimatedDate { get; set; }
public string TaskDescription { get; set; }
}
Controller
List<SelectListItem> query = DE.tblEmployees.Select(c => new SelectListItem
{ Text = c.Name, Value = c.Name }).ToList();
ViewBag.Categories = query;
return View();
View
<div class="dropdown">
#Html.DropDownList("CategoryID", (List<SelectListItem>)ViewBag.Categories, "--User Name--")
</div>
In the View I am loading all the user values inside the drop down. But when admin selects any of the user then all the details of user has to be displayed under a table. Upto here I am perfect but from here got strucked. How to move forward how to show the details of the user based on dropdown selection.
Steps
Create A view Where you can display all details of particular user.
Make Ajax call on user change and fetch specific user details from that use with partial view from controller.
Than append that html result to your html.
As Here
Drop Down Html
<div class="dropdown">
#Html.DropDownList("CategoryID", (List<SelectListItem>)ViewBag.Categories, "--User Name--")
</div>
Ajax
$("#CategoryID").change( function (event) {
var userId = $(this).val();
$.ajax({
url: "#Url.Action("GetUser","Controller")",
data: { id : userId },
type: "Get",
dataType: "html",
success: function (data) {
//Whatever result you have got from your controller with html partial view replace with a specific html.
$("#divPartialView").html( data ); // HTML DOM replace
}
});
});
Controller
public PartialViewResult GetUser(int id /* drop down value */)
{
var model = db.Users.find(id); // This is for example put your code to fetch record.
return PartialView("MyPartialView", model);
}
Create a partial view, which is basically to bind data for user details. For example you created a partial view called, userDetails.cshtml.
Add the model reference inside your partial view like bellow,
#model Your_Project_Name.ModalFolderName.TaskDetails
You need to write the html code inside details partial view to bind data.
Suppose you have a div with id="mydetailsTable" inside your main view, where you want to load the user details data after drop down select.
Then call an ajax method in drop down change event, and get the data and load it inside mydetailsTable div. check my bellow code,
$(".myDropdown").change(function() {
var id = $(this).val();
$.ajax({
type: 'GET',
url: '/ControllerName/GetUserDetails/'+id,
contentType: 'application/html; charset=utf-8',
datatype: 'html',
success: function (data) {
$('#mydetailsTable').html('');
$('#mydetailsTable').html(data);
})
});
See, .myDropdown is my class of drop down. You need to add.
Your Action method will be like this,
public ActionResult GetUserDetails(int userId)
{
//fetch the data by userId and assign in a variable, for ex: myUser
return PartialView("userDetails",myUser);
}
That's it. Hope it helps :)

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.

Html.RenderAction using AJAX

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

Categories