I have the following URL.Action in my cshtml:
<a href="#Url.Action("ShowStudent", "Student", new { studentCode = item.StudentCode, newPrivateStudent = Model.PrivateStudent })">
<i class="icon-arrow-right"></i>
</a>
The action in my controller is:
public ActionResult ShowCShowStudentlient(studentCode studentCode , PrivateStudentModel newPrivateStudent )
{ *some actions*}
When the action is hit in the controller the newPrivateStudent is set as null.
Any idea why?
The newPrivateStudent properties are set as hidden in the cshtml.
First, you should look at this #Url.Action helper:
#Url.Action("ShowStudent", "Student", new { studentCode = item.StudentCode, newPrivateStudent = Model.PrivateStudent })
The helper above will generate URL with query string like the following example (already tested):
...
As you see at the last parameter (newPrivateStudent), instead of adding contents of the complex object, the helper implicitly calls ToString() which returns fully-qualified name of that object (and subsequently newPrivateStudent has null value in action method). Hence, the proper way to do so is using AJAX callback to post corresponding key together with model contents to controller action and sends back its response as partial view to target DOM element.
Here is an example for sending model contents inside a form with AJAX postback (assumed using HTML helpers to generate input elements):
$('#triggerElementId').click(function () {
// this example sets string parameter as hardcoded string
// change it to actual value by jQuery selector with val() or text() function
var sCode = "XXX";
var modelData = $('form').serialize();
// or serializeArray() if you want to push additional data
// if model contents should left unchanged, use 'var modelData = #Html.Raw(Json.Encode(Model.PrivateStudent))'
$.ajax({
type: 'POST',
url: '#Url.Action("ShowStudent", "Student")',
data: { studentCode: sCode, newPrivateStudent: modelData },
success: function (result) {
$('#targetResultElement').html(result);
},
error: function (xhr, status, error) {
// error handling
}
});
});
Then setting controller action to retrieve key & serialized model contents as in example below:
[HttpPost]
public ActionResult ShowStudent(string studentCode, PrivateStudentModel newPrivateStudent)
{
// some actions
return PartialView("_ShowStudent", viewModelName); // mention partial view & viewmodel name here
}
Related
I am coding a MVC 5 internet application and would like to know how to pass values from a ViewModel into a jQuery function where I have a list of data to pass.
Usually, I would create a hidden field in the MVC View code, and then retrieve this value in the jQuery code. However, in this situation, there is not just one value from the ViewModel, but a List of objects, where each object has many values.
My ViewModel has a List<MapMarker>, where each MapMarker has the following attributes:
latitude
longitude
title
draggable
This is the jQuery function that I need to call for each MapMarker object:
function LoadMapMarker(latitude, longitude, title, draggable)
How can I call the LoadMapMarker function, with data from each of the MapMarker objects in the ViewModel list?
Thanks in advance
You can serialize your list and storage it in a hidden field. Then call LoadMapMarker by means of Javascript on client side.
Server:
using System.Web.Script.Serialization;
var MapMarkers = new List<MapMarker>();
var jsonSerialiser = new JavaScriptSerializer();
var json = jsonSerialiser.Serialize(MapMarkers);
return View(new MyViewModel({JsonList = json }));
View:
<input type="hidden" id= "MyHiddenFieldForMapMarker" value="#Model.JsonList" >
Client:
var MapMarkers = $("#MyHiddenFieldForMapMarker").val();
for (var MapMarker in MapMarkers) {
LoadMapMarker(MapMarker["latitude"],
MapMarker["longitude"],
MapMarker["title"],
MapMarker["draggable"]);
}
You can serialize to JSON and then store in a hidden field, or as a Javascript object like :
myJsonData= [{"id":"15aea3fa","firstname":"John","lastname":"Doe"}];
Alternatively, you can retrieve the data via an ajax call.
If you don't want to use JSON and use the data you have on your page you can do this:
You can add class (or some other attribute, for me it is easier to use classes, but it is better "programming" to use another attribute)
#foreach ()...
{
<div class="main_Marker">
<input ... class="lat"/> //using the #Model render ofc...
<input ... class="long"/>
</div>
}
Then jQuery:
$("main_Marker").each(function(index, item)) {
var lat = $(item).child(".lat");
.
.
LoadMapMarker(lat, long....);
}
If your jQuery function is present in a view, use #Html.Raw(Json.Encode(Model.JSonData)) like this
//JavaScript or jQuery function
function javascriptFunction()
{
var data = #Html.Raw(Json.Encode(Model.JSonData))
}
In the above code, JSonData is the name of the collection variable that contains data from model. In your case a List.
If your jQuery function is in a separate JavaScript file, then an AJAX request can be used to get the data from model
Controller Code
public ActionResult GetData()
{
//Your logic to get data from model
//Here data is the variable that holds the collection List<MapMarker>
return Json(data);
}
JavaScript Code for AJAX Request
function myJavaScriptFunction()
{
$.ajax({
url: '/GetData',
type: 'post',
success: function (data) {
alert("data retrieved successfully");
},
error: function () {
alert("Error retrieving data");
}
});
}
Well I have simple ajax form:
This is MyPartialView
#using(Ajax.BeginForm("action", "controller", new AjaxOptions
{
OnBegin = "beginRequest",
OnComplete = "completeRequest",
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "div-to-replace"
}, }))
{
<input type="text" id="my-input" />
...
}
This is parent view:
<div id="div-to-replace">
#Html.RenderPartial("MyPartialView")
</div>
In my controller I have:
[HttpPost]
public ActionResult action(Model model)
{
if (ModelState.IsValid)
{
// do staff with model
// return partial view
return PartialView("MyPartialView");
}
// else add error and return json result
return Json(new {error = "invalid data"});
}
And my javascript on ajax complete method:
function completeRequest(data) {
var result = $.parseJSON(data.responseText);
if (result != 'undefined' && result != null && result.error) {
// just display error and not replace all content
// attachModelError is my custom method, it just adds vlaidation-error class to inputs, etc.
attachModelError("my-input", result.error);
return;
}
// or show returned html (depending on returned model form inputs will be modified:
// select box with different items in my case
$('#div-to-replace').html(data.responseText);
}
But the problem is I have empty #div-to-replace if model state is invalid. If model state is ok every thing works fine. If I use different insertion mode it creates duplicates of div's content before or after div.
Summary:
I want different InsertionMode behavior depending on json result. I don't need replace data if (result != 'undefined' && result != null && result.error).
I had to solve this problem once so very long ago. I came up with a simple solution, which today, may not be the best solution but it gets the job done.
My solution involved setting up a controller action that would render just the partial with data that it would need and have my JavaScript request it.
C#
MyController: Controller
{
public ActionResult GetPartialViewAction()
{
return PartialView("mypartialview", new partialViewModel());
}
}
JavaScript
$.ajax({
url: "/my/getpartialaction/"
}).done(function(data) {
$("#partialViewDiv").html(data);
});
HTML
<div id="partialViewDiv"></div>
A better solution would be to use a MVVM/MVC JavaScript library that would allow you to leverage html templates and only have to transmit the data over your ajax solution. I recommend looking into knockout.js or backbone.js for this more accepted pattern.
I have the same problem with the default c# ajax forms. I have a solution what might work.
jQuery:
$(function () {
var ajaxFormSubmit = function () {
var $form = $(this);
var options = {
url: $form.attr("action"),
type: $form.attr("method"),
data: $form.serialize(),
cache: false
}
$.ajax(options).done(function (data) {
data.replaces.each(function (replace) {
$(replace.id).replaceWith(replace.html);
});
});
return false;
};
$("form[data-ajax='true']").submit(ajaxFormSubmit);});
form.cshtml
#using (Html.BeginForm("Create", "Menu", FormMethod.Post, new { data_ajax = "true" }))
{}
model sample
public string Id {get;set;}
public string Html {get;set;}
The last thing you need to do in your controller is return a json result with a list of your model sample, id is target element to update, for the html you must use a render partial / or view as string.
For render view to partial see [question]: https://stackoverflow.com/questions/434453
I have two controller actions that target the same view. That is, I have specified a view name on the call to View from controller action. The second action puts an html string in a ViewBag. I simply just want to display this html string in the view. I have tried
#ViewBag.HtmlDoc
and
#Html.Raw(ViewBag.HtmlDoc)
but nothing is rendered.
Any help would be appreciated. Thanks in advance.
--controller code---
public ActionResult ShowReport(string URL)
{
string tableString = "";
[Code to Create table called ReportTable and add rows etc]
tableString = RenderControlToString(ReportTable );
ViewBag.Table= tableString;
return View("ShowReport");
}
I debugged the ViewBag.Table on the View and can see the html string. But the View never gets updated / rendered. I tested with a simple text like:
#if (ViewBag.Table != null)
{
//#ViewBag.Table;
#:The day is: #DateTime.Now.DayOfWeek.
}
It goes into the code so I know ViewBag.Table is not null, but the string doesn't get rendered, either.
Do I need to refresh RenderBody() in the _layout.cshtml??? or something to that effect?
-- ajax call--
a button onclick event calls this ajax method:
$.ajax({
url: "/Home/ShowReport",
data: { URL: urlString} ,
type: 'POST',
success: function(data) {
alert(data);
},
error: function (e, textStatus, jqXHR) {
alert(e.statusText);
}
});
Change your action method to return JSON content
public ActionResult ShowReport(string URL)
{
string tableString = "";
[Code to Create table called ReportTable and add rows etc]
tableString = RenderControlToString(ReportTable );
//ViewBag.Table= tableString;
return this.Content(tableString, "application/json");
}
alter your JQuery to reutilize your return value
success: function(data) {
$('#divTable').innerHTML(data);
and add a div to your view where you want to render the html
<div id='divTable'></div>
I have this Kendo UI dropdownlist with a select event that is handled by a JavaScript function.
I need to call an action result from a controller that runs a LINQ query to populate a Kendo UI grid on my page. My problem is the only way I can find to handle this even is with JavaScript and I have been unable to figure out how to call my action result from my controller from the JavaScript event function.
This is what the DropDownList looks like...
#(Html.Kendo().DropDownList()
.Name("Options")
.DataTextField("Text")
.DataValueField("Value")
.BindTo(new List<SelectListItem>() {
new SelectListItem() {
Text = "Policies Not Archived",
Value = "1"
},
new SelectListItem() {
Text = "View All Policies",
Value = "2"
},
new SelectListItem() {
Text = "Filter Policies",
Value = "3"
}
})
.Events(e =>
{
e.Select("select");
})
)
and my JavaScript event handler that needs to call the action result
function select(e) {
}
and depending on the selection an ActionResult like this,
public ActionResult ViewAllPolicies()
{
//mycode
}
see this post
var url = '#Url.Action("ViewAllPolicies","YourController")';
$.ajax({ url: url, success: DataRetrieved, type: 'POST', dataType: 'json' });
in controller
public ActionResult ViewAllPolicies()
{
//Should return json format
}
url – this is the URL where request is sent. In my case there is
controller called contacts and it has action calles
ListPartiesByNameStart(). This action method takes parameter
nameStart (first letter of person or company). success – this is the
JavaScript function that handles retrieved data. You can write there
also anonymous function but I suggest you to use functions with names
because otherwise your code may get messy when functions grow. type –
this is the type of request. It is either GET or POST. I suggest you
to use POST because GET requests in JSON format are forbidden by
ASP.NET MVC by default (I will show you later how to turn on GET
requests to JSON returning actions). dataType – this is the data
format that is expected to be returned by server. If you don’t assign
it to value then returned result is handled as string. If you set it
to json then jQuery constructs you JavaScript object tree that
corresponds to JSON retrieved from server.
Instead of returning json, you can also return a PartialView and in the .done function grab an element and replace it with the results from the partial view. PartialView actions basically return a fragment of HTML, and so you can just stuff that anywhere you want on the page:
$.ajax({
url: urlToPartialViewAction,
type: 'POST',
dataType: 'JSON',
data: '123'
})
.done(function (result) {
$('#someDivPlaceholder').replaceWith(result);
});
You could have something like a link or grey div and wire up to it's click event and then call this, the link might say "View Receipt" and when you click it you call an action that returns a partial view with the receipt, and so when they click it the div/link is replaced with the result. Kind of like the "View More Comments" links you see on social sites.
Note that you can't have a partial view by itself, it must be called through an action
public PartialViewResult _GetReceipt(string id)
{
ReceiptViewModel vm = //query for receipt data
return PartialView(vm);//render partial view and return html fragment
}
Once the select function executes, you need to make an AJAX call back to your Controller. You can use jQuery.ajax() (a wrapper for the most common AJAX operations) in the select function,
function select(e) {
var url = '#Url.Action("ViewAllPolicies", "PolicyController")';
var selectedPolicy = $('#Options').val(); // The option selected
$.ajax({
url: url,
type: 'POST',
dataType: 'JSON',
data: selectedPolicy
})
.done(function (data) {
// Display the data back from you Controller
});
}
You can look at the Kendo site for more info on how the DropDownList works.
I would like to pass a javascript variable in a #Url.Action method as a route parameter.
I like to pass the screenmode javascript variable as a route parameter to my action method.
I have a view model with ScreenMode enum property and based on it i
should call a action in Ajax. I also need to pass a javascript
variable as a parameter for route.
This is what i tried and got compilation error.
The name 'screenMode' does not exist in the current context
$("#role-detail-form").submit(function (e) {
if ($(this).valid()) {
var screenMode = 0;
#{
if (Model.ScreenMode == UI.ViewModel.ScreenMode.New)
{
<text>
screenMode =2;
</text>
}
}
$.post('#Url.Action("SaveRoleDetail", new { mode=screenMode})',
$(this).serialize(), function (data) {
$("#role-detail").html(data);
$.validator.unobtrusive.parse($("#role-detail"));
});
}
e.preventDefault();
});
My Action is
public ActionResult SaveRoleDetail(RoleModel viewModel, ScreenMode screenMode)
{
}
You'd have to split that out and build the query string yourself, in order to incorporate the Javascript variable.
Something like this is what you need:
$.post('#(Url.Action("SaveRoleDetail"))?screenMode=' + screenMode)
EDIT: Although probably best practice, you should store the ScreenMode variable in your Model, then put a HiddenFor in your view for it. Then, whenever you change the value in Javascript, simply update the value of the hidden input, that way your action method only needs to take the view model as a parameter. If you are posting the form in JavaScript and you can call $("#form").serialize() to send all the data back within your post call.
Also it's possible to create a place holder and then replace it:
var url = '#Url.Action("GetOrderDetails", "Home", new { id = "js-id" })'
.replace("js-id", encodeURIComponent(rowId));
If you use T4MVC and jQuery, you can call the ActionResult doing the following:
In the controller:
public ActionResult SaveRoleDetail(RoleModel viewModel, ScreenMode screenMode)
{
}
In the view:
$.post("#Url.Action(MVC.Home.SaveRoleDetail())", { viewModel: param1, screenMode: param2) }, function (data) {
//Do Work
});
Access your route values (perhaps in html.HiddenFor). Values from JavaScript and Build your URL without #Url.Action. Use the URL to post.