Call Method in Controller from View(cshtml) - c#

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.

Related

How to pass data like an anonymous object from Jquery datatable in asp.net mvc

I have a Jquery datatable in my ASP.NET MVC view. The columns are like this :
"columns": [
{ "data": "Vote", "autoWidth": true },
{ "data": "Answer1", "autoWidth": true },
{ "data": "View", "autoWidth": true },
{
"data": "Title", "autoWidth": true,
'render': function (Title)
{
//return '<a href=' + Title + '>' + Title + '</a>';
return '<a href=/Questions/GoForAnswer/?idForAnswer='+ 2+'&title=dfg&question=dfg&view=59&date=08%2F10%2F2016%2023%3A39%3A17&answerNumber=13&vote=113>' + Title + '</a>';
}
}
]
Here in title column, I have hard coded the url that returns bunch of objects.But these objects are dynamic. I want to send these into the query string. Like I used to send them like this :
#Html.ActionLink(item.Title, "GoForAnswer", new { idForAnswer = item.ID, title = item.Title, question = item.Question, view = item.View, date = item.Date, answerNumber = item.Answer1, vote = item.Vote })
How can I send the objects from my Jquery function.
What you can do is you can make a model with the same names as your object example:
public class PeopleObject
{
public string name {get;set;}
public int age {get;set;}
}
then all you have to do is make you jquery object with the same names example:
var uniqueObjectName = [{name:'example1',age:20},{name:'example2',age:30}];
then after that you send the jquery object to you controller with ajax and pass the object as a variable example of ajax:
var uniqueObjectName = [{name:'example1',age:20},{name:'example2',age:30}]; // #1
$.ajax({
type: 'POST',
data: uniqueObjectName , // #2
url: '/Home/SubmitMyData',
//contentType: 'application/json', #3
//dataType: 'json', #2
success: alert('Youhou'),
error: alert('not good')
});
in you controller you receive the object like :
public ActionResult Index(PeopleObject uniqueObjectName )
{
return View();
}
notice the controller parameter name and the jquery variable name is the same...
The controller will automatically map the object to the model
Better construct your query in a different way, instead of passing the url directly to $.ajax, modify it to meet your needs.
So, essentially you store the razor generated URL, from #Html.RouteUrl method, in a JavaScript variable. Then you append the query string.
Because, in this case, the query string contains dynamic values, meaning some might not be listed in every request you need to have them listed in a placeholder variable, and replace values accordingly.
After you done with that, you just append the query string to the base URL and provide it to $.ajax.
Take a look at the following example (I have included a fiddle link to see it in action). I store the #Route.Url generated URL in the url variable. I also have declared all the keys of the model in keys table, as well as defined a placeholder string to replace values accordingly.
In fixPlaceholder method I just replace all the {key}=${placeholder} occurrences with the value of my data object (from there you get your dynamic values) or empty (if the value is not set for that particular property).
Finally, I append the placeholder to the url and pass it to $.ajax. Binding will do its magic on the ASP.NET MVC side, so do not worry about that, just declare your controller's action normally, expecting a complex object, like in this example:
[HttpGet]
public JsonResult GetModelAction(SampleViewModel model) {
// Your code here...
}
For your client code you can have something like this:
function fixPlaceholder (keys, data, placeholder) {
for(var i = 0; i < keys.length; i++) {
placeholder = placeholder.replace(keys[i] + "=${PLACEHOLDER}", keys[i] + "=" + (data[keys[i]] || ""));
}
return placeholder;
}
$(function(){
$("button").on("click", function () {
var keys = ["Title", "Question", "AnswerNumber", "View", "Date", "Vote"];
var data = {Title:"Myitle", Question:"MyQuestion", Vote:"10"};
var placeholder = "?Title=${PLACEHOLDER}&Question=${PLACEHOLDER}&AnswerNumber=${PLACEHOLDER}&View=${PLACEHOLDER}&Date=${PLACEHOLDER}&Vote=${PLACEHOLDER}";
var url = '#Url.RouteUrl(new{ action="GetModelAsJson", controller="Home"})';
placeholder = fixPlaceholder(keys, data, placeholder);
url = url + placeholder;
$.ajax({
url: url,
type: "GET",
contentType: "application/json; charset=utf-8"
}).then(function(resp) {
console.log("Response");
console.log(resp);
});
});
Here is a dotnetfiddle, check it and try to work your way based on that. Hope this helps.
Note
Because you are using values that might not be set in the model in every request, meaning they might be null, you need to pay attention to your back-end model. That said, if you have any properties with types like int, DateTime, etc. you might need to mark them as nullable, in order to avoid hairy situations. Like the model below.
using System;
namespace HelloWorldMvcApp
{
public class SampleViewModel
{
public string Title { get; set; }
public string Question { get; set; }
public int? AnswerNumber { get; set; }
public string View { get; set; }
public DateTime? Date { get; set; }
public string Vote { get; set; }
}
}

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 dosen't this javascript object convert to a C# class object?

I'm working on a little test bed app, where you give the app a note name, sign, and octave, and it spits out the frequency the note should sound at.
I'm having a problem with a JavaScript object that is sent to a server via AJAX. However, it does not map at all to the class on the action.
The sender code is a piece of JavaScript:
$someContainer.on('click', '.raise-pitch', function (e) {
e.preventDefault();
var $line = $(this).parents('.item-line'),
// Cache GUI elements for this line. Not pertinent.
var data = {
'model': {
'NoteName': $noteName.val(),
'Sign': $noteSign.val(),
'Octave': $noteOctave.val()
},
'steps': 1
};
var dataString = JSON.stringify(data);
$.ajax({
type: 'POST',
url: '#Url.Action("AlterPitch", "Home")',
data: dataString,
async: true,
dataType: 'json',
success: function (result) {
// Unimportant things.
}
});
});
In the data object, you can see that I have two things: the model and the steps. The steps determines how far we alter the musical note. I have verified that the values for note name, sign, and octave are making it into the data object. The steps are pre-determined.
The data object, however, maps to a ViewModel on the C# side, which looks like this:
public class NoteViewModel
{
public enum NoteSign
{
Natural,
Sharp,
Flat
}
public string NoteName { get; set; }
public NoteSign Sign { get; set; }
public int Octave { get; set; }
public float Frequency { get; set; }
private static readonly Dictionary<string, float> FrequencyLookup = new Dictionary<string, float>
{
{"C", 16.35f},
{"C#", 17.32f},
{"D", 18.35f},
{"D#", 19.45f},
{"E", 20.60f},
{"F", 21.83f},
{"F#", 23.12f},
{"G", 24.50f},
{"G#", 25.96f},
{"A", 27.50f},
{"A#", 29.14f},
{"B", 30.87f}
};
// Methods...not important for reasons below.
}
...which itself is encapsulated in a unique view model:
public class AlterPitchViewModel
{
public NoteViewModel model;
public int steps;
public NoteViewModel AlterPitch()
{
model.ChangeStep(steps);
return model;
}
}
...or at least it should. I set a break point in my controller method:
[HttpPost]
public ActionResult AlterPitch(AlterPitchViewModel model)
{
return Json(model.AlterPitch(), JsonRequestBehavior.AllowGet);
}
...But the model is null, which leads to a NullReference exception.
the model isn't serializing to an object that gets sent along in this context. Obviously I am still doing something wrong. Question is...what?
This approach has worked for me.
Server Side:
First, create your ViewModel
public class TestViewModel
{
public string Id { get; set; }
public string Description { get; set; }
}
Then, in the Controller:
[HttpPost]
public ActionResult TestingViewModel(TestViewModel udata)
{
// Stuff.
}
Client Side:
function CallTestingViewModel() {
// We create the javascript object based on the
// definition of our C# ViewModel class.
var udata = {
Id: 1,
Description: 'This is a test.'
};
// Calling the C# method via AJAX.
$.when(GenericAjaxCall('Home/TestingViewModel', false, udata)).then(function (result) {
// do stuff
});
}
// Return the AJAX call as a Promise Object
function GenericAjaxCall(controllerUrl, async, clientData) {
return $.ajax({
type: 'POST',
async: async,
url: controllerUrl,
data: JSON.stringify(clientData),
contentType: 'application/json;',
dataType: 'json'
});
}
Hope it helps.
Your HttpPost Method must have one unique parameter which is your ViewModel. My advice: create a viewmodel per post WebMethod.
So here:
public class AlterPitchViewModel
{
public NoteViewModel note { get; set; };
public int Steps { get; set; };
}
And adapt your Javascript accordingly. No need to name your javascript model instance as the parameter in the ASP method -> one object arrives and only one parameter is available so no ambiguity.

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.

jQuery allways Post null to Action in MVC 4

I have a problem and I don't know what is the issue.
I am constructing a Json object and I want to post it back with $.ajax. The problem is I always get null in my Action.
here is Ajax Part :
$("input[type=button]#ajax-editor-save").click(function() {
var hotelPropertyAssignModel = new Object();
hotelPropertyAssignModel.Hotel_Id = 1;
hotelPropertyAssignModel.HotelProperties = new Array();
$("input.ajax-editor[data-edited=true]").each(function() {
var hotelPropertyValue = new Object();
hotelPropertyValue.HotelProperty_Id = $(this).attr("data-hotelPropertyId");
hotelPropertyValue.Language = $(this).attr("data-lang");
hotelPropertyValue.Value = $(this).attr("value");
hotelPropertyAssignModel.HotelProperties.push(hotelPropertyValue);
});
$.ajax({
url: '#Url.Action( "SetProperties" )',
type: 'POST',
dataType: 'json',
data: JSON.stringify(hotelPropertyAssignModel)
});
});
and here is Action:
[AcceptVerbs( HttpVerbs.Post )]
[HttpPost]
public void SetProperties ( string hotelPropertyAssignModel )
{
}
I changed the parameter to string to validate how json is coming. I get null when I replace it with correct model too!
anybody can help?
Make sure you set the proper contentType:
$.ajax({
url: '#Url.Action( "SetProperties" )',
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(hotelPropertyAssignModel)
});
The dataType parameter that you were using indicates the response type, not the request type. You don't need it if your controller action properly sets the Content-Type response header which it normally does if you are returning for example a JsonResult.
But from what I can see your controller action is declared as void which obviously is wrong. Controller actions must return action results. If you don't care about the content, simply use an EmptyResult:
[AcceptVerbs( HttpVerbs.Post )]
[HttpPost]
public ActionResult SetProperties ( string hotelPropertyAssignModel )
{
...
return new EmptyResult();
}
Also there's another very serious problem with your controller action. It is taking a string argument instead of a view model!!! I don't know how you were possibly expecting to bind a JSON request to some string.
So, immediately define a view model that will match the JSON structure you are willing to send:
public class HotelAssignmentViewModel
{
public int Hotel_Id { get; set; }
public HotelPropertyViewModel[] HotelProperties { get; set; }
}
public class HotelPropertyViewModel
{
public int HotelProperty_Id { get; set; }
public string Language { get; set; }
public string Value { get; set; }
}
and then have your controller action take this view model as parameter:
[AcceptVerbs( HttpVerbs.Post )]
[HttpPost]
public ActionResult SetProperties ( HotelAssignmentViewModel model )
{
...
return new EmptyResult();
}
I also notice another problem with your code. You seem to have subscribed to the click event of some DOM element to trigger the AJAX request but you never cancel the default action by returning false from this event. So for example if this is a submit button or an anchor, it will simply redirect the browser away from the page leaving no time for your AJAX request to execute. So make sure you cancel this default action by returning false from your click handler:
$("input[type=button]#ajax-editor-save").click(function() {
...
return false;
});

Categories