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.
Related
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 :)
I've created a partial view that allows a user to enter their email and get added to a subscriber list. Originally I had this working as standard post and everything worked fine.
However now I'm trying to make this an ajax call and for some reason, even though the form is posting to the correct controller, the model is always coming through as null and I can't figure out why.
Here are my views:
Parent view:
#Html.Partial("Shared/Newsletter/NewsletterForm", new NewsletterSubscriber())
Form partial:
#using (Ajax.BeginForm("NewsletterSignUp", "Newsletter", new AjaxOptions { HttpMethod = "POST" }))
{
<input type="text" name="EmailAddress" id="newsletter-email" class="basic-input" placeholder="Email Address">
<button id="submit-newsletter" class="basic-submit">Sign Up</button>
<p id="status"></p>
}
Controller:
[HttpPost]
public ActionResult NewsletterSignUp(NewsletterSubscriber model)
{
if (!ModelState.IsValid)
{
return Content("Please enter a valid e-mail address");
}
// Do logic...
}
The model:
public class NewsletterSubscriber
{
[Required]
[EmailAddress]
[StringLength(300)]
public string EmailAddress { get; set; }
}
Scripts:
<script src="/scripts/jquery.validate.min.js"></script>
<script src="/scripts/jquery.validate.unobtrusive.min.js"></script>
<script src="/scripts/jquery.unobtrusive-ajax.min.js"></script>
<script>
$(function() {
$('#submit-newsletter').on('click', function(e) {
e.preventDefault();
$.post('/umbraco/surface/Newsletter/NewsletterSignUp', function (data) {
console.log(data);
$('#status').show().text(data);
});
});
});
</script>
Like I said, when I step through the code the post is hitting the correct controller, however the model is always coming through as null.
Where am I going wrong?
I just realised I had the ajax form handling the submission for me and I was trying to manually post the form in another script. Once I removed the additional script it worked.
(It's the end of a long day and I missed this obvious mistake!)
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.
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.
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);
}
});