I am using ASP.NET MVC 3.
I have a view that accepts a view model of type EditGrantApplicationViewModel. In this view model I have properties. When the view is loaded for the first time I pass it an instance of this view model:
public ActionResult Create()
{
EditGrantApplicationViewModel viewModel = new EditGrantApplicationViewModel();
return View(viewModel);
}
On this view I have my submit button that takes the form values and adds it to the database. I also have another button on this view, but it doesn't have to be clicked, and when clicked, it takes the employee number, does a database lookup and gets the employee's details. This data is returned to te same view and prepopulates this view with the data so that the user doesn't have to type in the data. The data can either be retrieved this way or can be manually entered.
Then the user can go on and type in the other fields and edit any of the fields that were returned from the lookup. When doen then the user can click submit to add it to the database. How would I do something like this? Would I require to forms on my page, one going to the Create action method and the other going to GetEmployee action method to do the database lookup? Should I use multiple form on my page? If so is having multiple forms a best practice? Any code samples would be appreciated :)
You can use jquery to fire an AJAX call to return some JSON data when you click a button:
$("someButton").click(function() {
$.ajax({
url: "/Service/GetData",
data: {}, // pass data here
dataType: "json",
type: "POST",
success: function() {
// manipulated return JSON data here
}
});
});
You could have a controller that calls the service and returns JSON or have the service do it and skip the controller. If you do it in a controller:
public ActionResult GetData() {
var someData = service.GetData();
return Json(someData);
}
Assuming the employee details are part of the EditGrantApplicationViewModel you should be able to just populate the fields on the form with the results of the web service call. Basically it should work just like a user manually entering the values. As long as your fields are named correctly the model binder will pick it up.
I'm making an assumption that your web service call is an asynch call from the page using javascript.
Related
I am having a controller that return model objects like below
model.addAttribute("list", list);
When i click a button ajax call happens and it is goes to controller executing everything and it returns. But i don't know how to access this model object in my jsp on ajax response. When i use alert for success ajax response , I am just seeing a html kind of page.
Please give me some example or reference to achieve this
Thanks in advance
Please find my sample code snippet
Controller.java
#RequestMapping(value='/ajax' value="POST")
Public #ResponseBody String displayDropdown(MyForm myform,Model model) {
//logic to fetch details from DB
List<String> list = fetchFromDB();
model.addAttribute("list" list);
return "ajaxResponse";
}
My JSP
In a button click, having the below ajax call
$.ajax {
url:'/ajax',
type:'POST',
data: $("#myform").serialize();
success:function(data) {
alert(response);
}
}
I want to get my model from this ajax response and use it in my jsp.
I am not sure, but from JSP all model attribute variables are accessible simply using ${attribute_name}. In your case it is ${list}
Maybe you can use
console.info(model)
I am not sure that you can access response with JSP. JSP is the server side and response you receive when the page is already sent to client. The only thing you can try is to use COOKIES. Set response in cookies and then access it from the server.
Yes You can easily get Model data from controller, simply
#RequestMapping(value='/ajax' value="POST")
Public String displayDropdown(MyForm myform,Model model) {
//logic to fetch details from DB
List<String> list = fetchFromDB();
model.addAttribute("list" list);
return "yourjsppage";
}
$.ajax {
url:'/ajax',
type:'POST',
data: $("#myform").serialize();
success:function(data) {
$("#page-wrapper").html( data );
}
}
page-wrapper is your content div in jsp page. this returns all jsp page including your model. in this scenario it is also useful when you want (partial rendering) not wanting to refresh whole page but targeting specific page.
I am intending to pass a Hotel model to my Controller Action - Do some checks/processing on it, then return a potentially different Hotel model rendered in a Partial View.
The problem I'm getting is that if I pass the oHotelParameter Model to the Action then the PartialView uses the model passed to the Action instead of the one passed to the PartialView method.
If I remove the oHotelParameter Parameter from the Action then the View is Rendered as expected using oHotel.
public ActionResult _SaveMasterDetails(Hotel oHotelParameter)
{
//Do some processing on oHotelParameter
//........
Hotel oHotel = new Hotel();
oHotel.GetHotelInfoById(14); //This gets a different Hotel object just for a test
//For some reason oHotel is ignored and oHotelParameter is used instead unless I remove oHotelParameter
return PartialView("_MasterDetails", oHotel);
}
When I debug the View I see that the Model is set to the value I pass to PartialView (oHotel), yet the result I see coming back from the Action contains data from the oHotelParameter object.
In case it makes a difference, I am calling the Action from jQuery ajax.
Can anyone explain why this should happen?
when mvc handles a form post, it fills the ModelState object with the details of the model.
This is when used when the view is rendered again from the post action, this is incase you have thrown the view back out because it has failed validation.
If you want to pass out a new model and not use the view state, then you can call ModelState.Clear() before returning the view and that should let you rebind the view to the new model.
I think that it would help if you had a better understanding of how model binding works when you post back to an action method. In most cases, it is unecessary and inefficient to pass a view model as a parameter to a POST action method. What you are doing is loading the view model into memory twice when you pass your view model as a parameter (assuming a strongly typed view). When you do a post back the model becomes part of the form collection (through model binding) in the request object in the BaseController class that every controller inherits from. All that you need to do is to extract the model from the Form collection in the Request object in the BaseController. It just so happens that there is a handy method, TryUpdateModel to help you do this. Here is how you do it
[POST]
public ActionResult Save()
{
var saveVm = new SaveViewModel();
// TryUpdateModel automatically populates your ViewModel!
// TryUpdateModel also calls ModelState.IsValid and returns
// true if your model is valid (validation attributes etc.)
if (TryUpdateModel(saveVm)
{
// do some work
int id = 1;
var anotherSaveVm = GetSaveVmBySomeId(id);
// do more work with saveVm and anotherSaveVm
// clear the existing model
ModelState.Clear();
return View(anotherSaveVm);
}
// return origonal view model so that the user can correct their errors
return View(saveVm);
}
I think that the data in the form collection contained in the request object is being returned with the view. When you pass the model back to the post action method as a parameter, I believe it is passed in the query string (see Request.QueryString). Most of the time, it is best to only pass one or two primitive type parameters or primitive reverence types such as int? to an action method. There is no need to pass the entire model as it is already contained in the Form collection of the Request object. If you wish to examine the QueryString, seee Request.QueryString.
Let's say we have a standard Ajax form with the following Syntax:
#using(Ajax.BeginForm("AddCityJson", "City",new AjaxOptions
{
HttpMethod = "post",
OnSuccess = "JScriptOnSuccess();",
OnFailure = "JScriptOnFailure"
}))
{
...form fields go here...
}
A simple form that gathers some information about a city, submits and saves it.
On the controller side we receive the info. If everything went well we return true in order for OnSuccess AjaxOption to trigger and if failed false is returned:
public JsonResult AddCityJson(Formcollection collection)
{
var city = new City
{
...populate city fields from passed in collection
}
var cityRepository = new CityRepository;
city = cityRepository.SaveOrEdit(city);
if(city==null)
{return Json(false)}
return Json(true);
}
Inside of the controller AddCityJson method I need to add various checks. Possibly to check if the city name already exists or any other validation and if I ran into an Error or a Warning return it back to UI.
How can I pass any error/warning messages up to UI if my Ajax form expects to get back ajax true or false and whether that post was successful?
I would like to avoid using ViewData, ViewBags.
Thank you.
You can return any number of values in your JSON result, for example:
return Json(new { success = false, message = errorMessage });
And then interpret this on the client side. No need to use ViewData, ViewBags, etc. Just format the result on the client side, so you're just transmitting data over JSON.
EDIT:
I didn't realize you were using Ajax.BeginForm(). You should still be able to hook into the JSON results client side to parse the results. See How to use Ajax.BeginForm MVC helper with JSON result?.
Although I would suspect most people would use jQuery to accomplish the same thing, such as described on various StackOverflow posts like Darin's response at Using Ajax.BeginForm with ASP.NET MVC 3 Razor. Which is what I would recommend as well, since the jQuery library is very robust and cross platform tested.
I am new to MVC, so hopefully my question will be straight forward. I am thinking of a scenario where the user submits a form (that is a partial view) and it undergoes server validation. I am wondering how I will know the result of the validation on the client side (javascript) after the form is submitted. For example, if validation fails I will obviously want to return the partial view again with validation messages set, but if it passes validation I may not necessarily want to return the partial view. I may want to return a json object with a message or hide a div or something. I want to be able to determine the validation result on the client. Is something like that possible? Or can I approach this a different way?
The tricky part with AJAX is that the client and server both have to agree on what's supposed to come back from the server in any circumstance. You have a few options:
Your server will always return HTML, and jQuery will always replace the editor content with the HTML that comes back. If the model is invalid, you return a PartialView result. If the model is valid, you return a <script> tag that tells the page what it needs to do (e.g. close a dialog, redirect to a different page, whatever). jQuery will automatically run any script it finds in the results when it tries to insert them into the DOM.
Your server will always return a JSON object representing what happened. In this scenario, your client-side javascript code has to be complex enough to take the results and modify your page to match. Under normal circumstances, this will mean that you don't get to take advantage of MVC's validation features.
Same as 2, except that you use a custom utility method to render the partial view you want into a string, and you make that entire string part of the JSON that comes back. The javascript code then just has to be smart enough to check whether the JSON shows a valid or invalid result, and if the result is valid, replace the contents of your editor area with the partialview HTML that is returned as part of the JSON object you got back.
Same as 3, except you develop an event-based architecture where all your AJAX requests will always expect to get back a JSON object with one or more "events" in it. The AJAX code can then be consolidated into one method that hands the events off to an Event Bus. The event bus then passes the event information into callbacks that have "subscribed" to these events. That way, depending on what kind of events you return from the server, you can have different actions occur on the client side. This strategy requires a lot more up-front work to put in place, but once it's done you can have a lot more flexibility, and the client-side code becomes vastly more maintainable.
Partial views would not have a Layout page. You may use this code to check if the view is rendered as partial view.
#if (String.IsNullOrWhiteSpace(Layout))
{
// Do somthing if it is partial view
}
else
{
// Do somthing if it is full page view
}
If you are using the MVC Data Annotations for validating your Model, then the controller will have a property called ModelState (typeof(ModelStateDictionary) which as a property of IsValid to determine if your Model passed into the Controller/Action is valid.
With IsValid you can return a Json object that can tell your Javascript what to do next.
Update
Here is a really basic example (USES jQuery):
[SomeController.cs]
public class SomeController : Controller
{
public ActionResult ShowForm()
{
return View();
}
public ActionResult ValidateForm(MyFormModel FormModel)
{
FormValidationResults result = new FormValidationResults();
result.IsValid = ModelState.IsValid;
if (result.IsValid)
{
result.RedirectToUrl = "/Controller/Action";
}
this.Json(result);
}
}
[FormValidationResult.cs]
public class FormValidationResults
{
public bool IsValid { get; set; }
public string RedirectToUrl { get; set; }
}
[View.js]
$(document).ready(function()
{
$("#button").click(function()
{
var form = $("#myForm");
$.ajax(
{
url: '/Some/ValidateForm',
type: 'POST',
data: form.serialize(),
success: function(jsonResult)
{
if (jsonResult.IsValid)
{
window.location = jsonResult.RedirectToUrl;
}
}
});
});
});
I have a partial view that when the user clicks a button, some data is passed to the database and the results returned. The results must be displayed in another partial view. The results are obtained using the following Controller method and Ajax script:
public ActionResult GetResultData(Models.SelectedFilterValues selectedFilters)
{
resultData = resultRepository.GetResultData(
selectedFilters.Projects,
selectedFilters.ExperimentTypes,
selectedFilters.StudySet,
selectedFilters.Species,
selectedFilters.Strain,
selectedFilters.Department,
selectedFilters.Location);
return PartialView("Results", resultData);
}
function GetResultData(selectedProjects, selectedExperiments, selectedStudySets, selectedDepartments, selectedLocations, selectedSpecies, selectedStrain) {
$.ajax({
type: "GET",
url: "/Search/GetResultData",
data: { projects: selectedProjects, experimentTypes: selectedExperiments, studySet: selectedStudySets,
department: selectedDepartments, location: selectedLocations, species: selectedSpecies, strain: selectedStrain
},
error: function (data) {
},
success: function (data) {
}
});
}
I keep getting the error when the data is returned into the Ajax method, is this because it is returning a partial view? What I want is for the Ajax method to accept the data, and then for me to pass that data into the new partial view. Is this possible?
Thanks.
I think you are mixing up client-side and server-side logic.
A partial view can contain logic that is executed on the server. Typically you would execute business logic in a Controller, and UI logic in the PartialView. For instance, any markup using Razor is actually executed on the server. The result then is HTML which is sent to the browser.
This HTML may contain client-side (JavaScript) code. So typically you would create a PartialView which contains JavaScript code that calls jQuery methods such as $.ajax(). When it does, it doesn't matter anymore how the JavaScript got to the browser -- as part of a PartialView or not, that doesn't matter. The JS code is executed on the client side, and it calls logic on the server side.
When the Ajax call returns data to the client side, the JS code there can then render the data into a grid, or apply a jQuery template, or do whatever with it that it wants. What it cannot do, is execute server-side PartialView code, because any PartialView has long since executed.