Populate variable from a JSON Result in ASP.NET MVC - c#

I don't know if this is a basic stuff but I'm a having a hard time on populating a variable from a JSON result. I can't just find a right keyword on it.
What I want to do is populate this variable.
Js File
var opts = [
{ key: 1, label: 'High' },
{ key: 2, label: 'Normal' },
{ key: 3, label: 'Low' }
];
Layer
public IEnumerable<DropdownModel> ToLayerLevel()
{
List<DropdownModel> data = new List<DropdownModel>();
using (SqlConnection con = new SqlConnection(Conn.MyConn()))
{
SqlCommand com = new SqlCommand("SELECT id, desc FROM PriorityLevel", con);
con.Open();
SqlDataReader reader = com.ExecuteReader();
while (reader.Read())
{
DropdownModel value = new DropdownModel();
value.key = reader.GetInt32(0);
value.label = reader.GetString(1);
data.Add(value);
}
}
return data;
}
Controller
public JsonResult ddlToLayerLevel()
{
DropdownLayers ddl = new DropdownLayers();
var data = ddl.ToLayerLevel();
return Json(data, JsonRequestBehavior.AllowGet);
}

You can make an ajax call to the server action method where it will return the data you need
public JsonResult ddlToLayerLevel()
{
var ddl = new DropdownLayers();
var data = ddl.ToLayerLevel().ToList();
return Json(data, JsonRequestBehavior.AllowGet);
}
This will return an array of items with key and label properties, in JSON format
[{"key":1,"label":"High"},{"key":2,"label":"Normal"},{"key":3,"label":"Low"}]
Now you can call this action method using ajax . Here is a sample using jQuery $.get method.
var url="/YourControllerName/ddlToLayerLevel";
$.get(url).done(function(resultArray) {
// resultArray is an array of items.
// Use it inside this callback method scope
var opts=resultArray;
console.log(opts);
});
To avoid 404 Not found errors, when making ajax call's from external js files, you may use the Url.Action method to generate the correct relative path in your view file(where you can execute C# methods like Url.Action) and use that in your external js file.
For example, you can do like this in your razor view file
<script>
var myProject= myProject|| {};
myProject.layerLevelUrl ="#Url.Action("ddlToLayerLevel","YourControllerName")";
</script>
<script src="pathToYourExternalJsFile.js"></script>
Now in your external js file you can use it like
$.get(myProject.layerLevelUrl)
.done(function(resultArray) {
// resultArray is an array of items. Use it inside this callback method
var opts=resultArray;
console.log(JSON.stringify(opts));
});

Getting data using jQuery:
var opts = [];
$.getJSON("<your url here>", function(res){
opts = res;
});
There is an alternate simplified way I use when I need to get objects created in c# directly into a js variable. It does come with pros and cons though
pros
Much quicker to code rather than having to create a controller and call a js ajax function every time.
Loads the entire page in one go and overall loads the data into js faster.
cons
The code doesn't go into your js file but instead into a cshtml file.
The information is only fetched in load time and the code can't be reused in real time when the page is still open.
If you don't need the js variable on page load, not using this would speed up the initial page load speed and will load the js information later.
First I create an extension function in static class as follows:
public static IHtmlContent ToJS(this IHtmlHelper htmlHelper, object obj)
{
return htmlHelper.Raw(JsonConvert.SerializeObject(obj));
}
Now in any cshtml file I can define the js variable by simply using the following:
#{
DropdownLayers ddl = new DropdownLayers();
var data = ddl.ToLayerLevel();
}
<script>
var opts = #Html.ToJS(data);
</script>

Related

calling controller action from Vuejs, from different views

I have (topbar + sidebar + bottombar) as Vuejs components that are part of page layout within every View is rendered.
In top bar vuejs file i have a method that is loading "some" data via API request to one of my controller:
beforeMount() {
this.loggedUserDeputies.userDeputies = [];
console.log("calling LoadLoggedUserDeputies");
$.get('api/Timesheets/LoadLoggedUserDeputies')
.then(response => response as Promise<LoggedUserDeputies>)
.then(data => {
this.loggedUserDeputies = data;
});
},
API controller method:
[Route("api/[controller]/[action]")]
public object LoadLoggedUserDeputies()
{
if (ActualUserContract.LoggedUserDeputies == null)
{
return null;
}
var result = ActualUserContract.LoggedUserDeputies
.ToList()
.Select(x => new
{
userContractId = x.UserContract.Id,
userContractFullName = x.UserFullName,
userContractPersonalNumber = x.UserContract.PersonalNumber
});
return new { userDeputies = result };
}
but i have an issue, that the url for fetch the data is always modified based on current view i am in.
(so instead of always call: https://localhost:44380/api/Timesheets/LoadLoggedUserDeputies
it is transformed to: https://localhost:44380/Activities/api/Timesheets/LoadLoggedUserDeputiesor https://localhost:44380/Reports/api/Timesheets/LoadLoggedUserDeputies
). Even when its called by the same layout component (which was new to me, so apologies for my ignorance).
Is there any way i can always call the same url: https://example.com/api/Timesheets/LoadLoggedUserDeputies from every view ?
You are using a relative path to load the file:
$.get('api/Timesheets/LoadLoggedUserDeputies')
You need a slash on the front of it to make it an absolute path
$.get('/api/Timesheets/LoadLoggedUserDeputies')
that will load from the current server. If you want to specify the server, too:
$.get('https://example.com/api/Timesheets/LoadLoggedUserDeputies')

ASP.Net C# POST not returning view

Using ASP.NET, C# and Javascript, I'm trying to dynamically get Data for the user, POST it to a controller, and return a view that changes depending on the Data.
Here's the code :
Javascript function :
function editEntry(id) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", "Edit?id=" + id, true);
xmlhttp.send({ id: id });
//xmlhttp.send();
}
Controller handling post (a portion) :
[HttpPost]
public ActionResult Edit(EditEvenementiel edit)
{
var contexte = new intranetEntities1();
SqlParameter Id_viewBag = new SqlParameter("#id", edit.id);
ViewBag.edit = contexte.evenementiel
.SqlQuery("SELECT * FROM evenementiel WHERE id_evenementiel = #id", Id_viewBag);
return View();
}
when i fire the javascript, i can see the POST in the firebug console (working fine), i can see the variable getting the correct value in Visual Studio's Debugger, but the view doesn't change.
I even see the expected view (with all the treatements expected) returned in the firebug console; but my page still doesn't change.
How can i do that ?
By default, you should have 2 Actions, one that should process/get the data through a Post method and one that collects data for the View. (it's called Post/Redirect/Get - more details on wiki)
Having this in mind, you can leave your post method as :
[HttpPost]
public ActionResult Edit(int id)
{
var contexte = new intranetEntities1();
SqlParameter Id_viewBag = new SqlParameter("#id", id);
EditEvenementiel edit = contexte.evenementiel.SqlQuery("SELECT * FROM evenementiel WHERE id_evenementiel = #id", Id_viewBag);
return RedirectToAction("Edit",new { edit = edit} );
}
and create a new action which sends the data to the view.
Something like:
public ActionResult Edit(EditEvenementiel edit)
{
//logic here
return View(edit);
}
Please be aware that this is just an example, modify it according to your scenario.
As you are using Ajax (XMLHttpRequest) to fetch this data you also need to present it on your page, it wont happen automatically.
Maybe something like this?
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
alert(xmlhttp.responseText); // or put the responseText in a HTML element of your choice to do whatever you want to do
}
}
Where do you actually update anything on the page? All you do is send the request:
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", "Edit?id=" + id, true);
xmlhttp.send({ id: id });
But you ignore the response. The browser isn't going to know what you want to do with that response, you have to tell it. Which could be something as simple as:
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
document.getElementById('someElement').innerHTML = xmlhttp.responseText;
}
}
Basically, use the AJAX response (which is an HTML view?) to update the page content.

What is the best way to pass data from ASP.NET to AngularJS?

I am using ng-grid in an ASP.NET web application to display data from a WCF Service. In this Plunker example the data is stored in a JSON file and then converted by the Angular module.
var app = angular.module('myApp', ['ngGrid']);
app.controller('MyCtrl', function($scope, $http) {
$scope.setPagingData = function(data, page, pageSize){
var pagedData = data.slice((page - 1) * pageSize, page * pageSize);
$scope.myData = pagedData;
$scope.totalServerItems = data.length;
if (!$scope.$$phase) {
$scope.$apply();
}
};
$scope.getPagedDataAsync = function (pageSize, page, searchText) {
setTimeout(function () {
var data;
if (searchText) {
var ft = searchText.toLowerCase();
$http.get('largeLoad.json').success(function (largeLoad) {
data = largeLoad.filter(function(item) {
return JSON.stringify(item).toLowerCase().indexOf(ft) != -1;
});
$scope.setPagingData(data,page,pageSize);
});
} else {
$http.get('largeLoad.json').success(function (largeLoad) {
$scope.setPagingData(largeLoad,page,pageSize);
});
}
}, 100);
};
$scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage);
$scope.gridOptions = {
data: 'myData',
enablePaging: true,
showFooter: true,
enableCellSelection: true,
enableCellEdit: true,
enableRowSelection: false,
totalServerItems:'totalServerItems',
pagingOptions: $scope.pagingOptions,
filterOptions: $scope.filterOptions
};
});
Plunker
This piece of code was interesting because it read dicrectly from a JSON file and dynamically bound it to the ng-grid. I was hoping that I would be able to use the ASP.NET (C#) codebehind to pass a JSON file to the AngularJS code and let it do all of the work to parse it.
It seems like you cannot do this, so what is the best way to pass data to AngularJS from ASP.NET?
Thanks in advance.
The question you're really asking is, how do I pass some server-side information to Javasript? Angular is irrelevant here.
Solution 1: just write it to a client-side variable. Something like:
If you're using MVC:
var myJson = '#ViewBag.MyJson';
var json = JSON.parse(myJson);
If you're using WebForms:
var myJson = '<% Response.Write(MyJson); %>';
var json = JSON.parse(myJson);
Solution 2: define a server-side method that returns your json string, and call it from the client side using Ajax. Then parse it as previously. There's a decent example here.
Solution 3: can't you write to your Json file from the server side, before loading it into Angular?
You could create an Angular directive that handles parsing, and then pass it a JSON file name in your ASP.NET page, like this:
// ASP.NET page
<%
JSONFile.Text = "path/to/json/file.json";
%>
<!DOCTYPE html>
<html>
<head runat="server">
// including our parse-json directive as "metadata" in the head
<parse-json data-json-file="<%JSONFile%>"></parse-json>
</head>
<body>
...
...
</body>
</html>
And then your angular directive could look something like this:
app.directive('parseJson', ['$http', function ($http) {
return {
restrict: 'E',
scope: {
jsonFile: '#'
}
link: function (scope) {
$http.get('my/url/' + scope.jsonFile)
.success(function (data) {
// your parsing logic would go here.
});
}
};
}]);
The data prefix on the data-json-file attribute is the HTML5 standard for custom data attributes.
So, to summarize the code above. In our ASP.NET page we are including a custom tag (our angular directive) named <parse-json> in the <head> of our html page (it doesn't have to be there, but it is sorta metadata so I figured it fit). We are setting the attribute data-json-file to equal the path of the JSON file on our server. When angular loads on the client, it will request this JSON file, and then from there you can do whatever you want with it (in your case, parse it).
Hope this helps!

Url.Action and two variables

I have #Html.PagedListPager(Model, page => Url.Action("GetTabData", new { page })
and inside my js file I have ready to use myTab variable which I need to send together with page in above example.
How can I do that?
Update:
I'm using js variable to determine which tab is user click and based on that value I'm quering data. Now I have implemeted pagination which uses above generated link. With this in place my ajax call for sending activeTab is broken, I need to send this value together with page inside above Url.Action.
This is js variable which I use to send over ajax to determine which tab is user click
$(function () {
var activeTab = null;
$('#tabs .tabLink').click(function (event) {
var activeTab = $(this).attr('href').split('-')[1];
GetTabData(activeTab);
});
GetTabData(ommitted on purpse)
});
I don't get the question clearly, but I am taking a guess here. Don't know if this is what you are looking for.
Note - You have GetTabData in both your javascript as well as cshtml code, I am hoping this is just coincidence, because the js function cannot be invoked via #Url.Action in this manner.
If you need to send two values as part of your URL, you could do it either in a RESTful way or have querystrings.
Option 1 -
Url.Action("GetTabData", new { page=2, tab="blah" })
Your corresponding controller action would look like
public ActionResult GetTabData(int page, string tab)
{
...
}
Option 2 -
create a querystring and append it to the URL
/GetTabData?page=2&tab=blah
In this case the controller action would look like this
public ActionResult GetTabData()
{
var params = Request.QueryString;
...
}

How to implement file download with AJAX and MVC

I would like to provide a file download operation by using the jQuery AJAX call with some params under MVC
Example
(javascript)
function DoDownload(startDate) {
$.ajax({
url:"controller/GetFile/",
data: {startDate:startDate}
...
});
}
C# Controller Code
public void GetFile(string startDate) {
var results = doQueryWith(startDate);
// Create file based on results
....
// How do I tell the server to make this a file download??
}
I typically would just make my file download a link such as:
<a h r e f="mycontroller/getfile/1"/>Download</a>
but in the case above the date will be dynamic.
If I don't use ajax, what would be a preferred way to pass in the params to the MVC controller using javascript?
Example:
window.location = "mycontroller/GetFile/" + $("#fromDate").val();
assuming the date is 12-25-2012
Would this produce
mycontroller/GetFile/12/25/2012
would MVC treat this as three params?
What I ended up doing is calling my controller from my javascript like:
var url = "/mycontroller/GetFile?startDate=" + $("#mydate").val() + etc...
window.location = url;
mycontroller.cs
public void GetFile(DateTime startDate)
{
}
My original concern was with the date parameters. I didnt want to have to parse it.
Using the ActionLink helper, you can pass multiple params to your controller:
HtmlHelper.ActionLink(
string linkText,
string actionName,
string controllerName,
object routeValues,
object htmlAttributes
)
So in your case:
#Html.ActionLink("Download file", "GetFile", "MyController", new { startDate = "##" }, new { id="mydownloadlink" })
Using jQuery you can change the value of the startDate in the link with the content of your date picker or textbox.
$("#mydownloadlink").attr("href").replace("##", $("#yourdatetexbox").val);
Then, in your controller, just use one of the other answers here, about FileResult.
Hope this help you...
You can use the File method of controller class to return a file back to the browser.
The below sample returns a pdf file.
public ActionResult GetFile(int id)
{
var fileInfo=repositary.GetFileDedetails(id);
var byteArrayOFFile=fileInfo.FileContentAsByteArray();
return File(byteArrayOFFile,"application/pdf","yourFriendlyName.pdf");
}
Assuming repositary.GetFileDedetails method returns the details of the file from the id.
You may also return the file from a physical location(a path) or a stream. Check all the overloads of the File method and use appropriate one.
This has nothing to do with ajax. this is normal GET request over a browser.
Your controller action method should return a FileResult instead of void. And there is no need to do this via AJAX - in fact, you don't want to do this with AJAX. You'll need the browser involved so it knows to provide a download dialog for the user.
See these links:
Handling an ASP.NET MVC FileResult returned in an (jQuery) Ajax call
File download in Asp.Net MVC 2
I hope this helps.
This works for me. Make sure you return a File from your controller action with contentType as "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" and file name as e.g. "List.xlsx" which should be the same as in the AJAX success call. I have used ClosedXML NuGet package to generate the excel file.
public IActionResult GetFile(DateTime startDate)
{
var results = doQueryWith(startDate);
DataTable dt = new DataTable("Grid");
//populate dt here.
//if you result is a data table you can assign it to dt
dt = results;
string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
string fileName = "List.xlsx";
using (var workbook = new XLWorkbook())
{
workbook.Worksheets.Add(dt);
using (var stream = new MemoryStream())
{
workbook.SaveAs(stream);
workbook.SaveAs(stream);
var content = stream.ToArray();
return File(content, contentType, fileName);
}
}
}
//.cshtml (JQuery AJAX call to the controller action)
$.ajax({
url:"ControllerName/GetFile/",
data: {startDate:startDate}
contentType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
xhrFields: { responseType: 'blob' },
success: function (data) {
var a = document.createElement('a');
var url = window.URL.createObjectURL(data);
a.href = url;
a.download = 'List.xlsx';
a.click();
window.URL.revokeObjectURL(url);
}
});

Categories

Resources