ASP MVC send an Array object to a JavaScript function - javascript

I am using ASP MVC for my university coursework. However I have encountered a problem, before I was sending too many AJAX requests which was causing my page to take way too long to load. Therefore I thought I could improve the situation by sending the arrays from the database to the view and then put them into my jquery function inline.
So here is how it looks I have my simple model:
public class NewBooking
{
public IEnumerable<dynamic> parks { get; set; }
}
Then in my controller I set the parks with information from the database as you can see here:
public ActionResult Index()
{
var model = new NewBooking();
var parks = Database.Open("SQLServerConnectionString").Query("SELECT * FROM Park");
var output = from o in parks
select new { parkID = o.parkID, parkName = o.parkName };
model.parks = output.ToList();
return View(model);
}
Now, this returns to the view all the information I am expecting, as you can see below if I simply called the model parks in the view:
#model build_01.Models.Timetabler.NewBooking
#{
#Model.parks
}
I know this method wouldn't however with a for loop it works fine, now to my issue; I'm trying to call a JavaScript function and pass this array to it.
$(document.ready(function () {
slotAvailability(#Model.parks);
}));
Is there something I can do to this #Model.parks to be able to send it to the function? Kind of like how I would do JSON if I was using AJAX.
As it stands trying to call it like this gives me this error in my console:
Uncaught SyntaxError: Unexpected number
I can see why, if I was to inspect element I can see that the function parse looks like this:
slotAvailability(System.Collections.Generic.List`1[<>f__AnonymousType3`2[System.Object,System.Object]]);
Thanks

You should use the Json.Encode function. Also make sure tha you close your parenthesis at the proper place, after document:
$(document).ready(function () {
var parks = #Html.Raw(Json.Encode(Model.parks));
slotAvailability(parks);
});
Also using dynamic seems like a bad design here. You don't get any Intellisense. You'd rather have a view model:
public class ParkViewModel
{
public int ParkId { get; set; }
public int ParkName { get; set; }
}
and then your NewBooking model:
public class NewBooking
{
public IEnumerable<ParkViewModel> Parks { get; set; }
}

Related

How to properly parse C# List of objects to Javascript. Only shows type like " System.Collections.Generic.List`1"

I really cant wrap my head around this i have a List of this class
public class StandardText
{
public string Id { get; set; }
public string Value { get; set; }
}
I then want to use it in javascript where i pass down a model to a partialView. The problem is that i dont seem to be able to use it. i tried to JSON.parse() the list in the javascript but it will then try to JSON.parse() something like " System.Collections.Generic.List`1" so it is not trying to actually parse the values of the object. i also tried to JsonConvert before i send it down but i am failing on how to porperly convert it.
this is where i create the model and then send down the partialView
public async Task<ActionResult> _confirmText(TextViewModel model)
{
model.StandardText = await GetStandardText();
return PartialView(model);
}
Then in that partialView i simply want to pass it to my frontend via a global scope(i know bad)
var text = '#Model.StandardText';
window.addElementToModal(element, text);
And then the addElementToModal
(window as any).addElementToModel = ((root: HTMLElement, standardText: {[key: string]: string}) =>
{
init(root, standardText);
});
so i want to recieve it like {[key: string]: string} where am i going wrong?
Try this code:
const list = JSON.parse("#JsonConvert.SerializeObject(ViewBag.List)");
As a result you will get a plain JS array in list variable.
var text = '#Model.StandardText';
This is just going to ToString() the object. You could use JSON.NET For example to JSON Stringify it if that's your objective. e.g.
var text = '#Json.SerializeObject(Model.StandardText)';

Pass collection of objects inside an object from js to C#

This question can be very easy for you but I cannot find the solution anywhere, I've searched on SO as well. How can I send a collection of objects inside an object to a C# API method, here is my code that I try to send
{
"Question":"sdvsdv",
"PollQuestions":
[
{
"QuestionText":"Question Text"
}
]
}
I've tried with Advanced REST client as well (not only from JS), I can see value of parent object's parameters but PollQuestions objects parameters are all empty.
Please suggest a work around. Its been couple of days and I cannot get through it. Thanks in advance.
EDIT:
Here is how API method looks like:
Advanced Rest client request:
JS request:
Poll is a simple class like this:
[Serializable]
[DataContract(Namespace = "")]
public class Poll
{
[DataMember]
public string Question
{
get;
set;
}
[DataMember]
public Collection<PollQuestion> PollQuestions { get; set; }
}
PollQuestion object:
[Serializable]
public class PollQuestion : AnotherClass
{
public string QuestionText
{
get;
set;
}
}
In your case if the problem is to Map the request JSON in C# then try below code:
Class structure:
public class PollQuestion
{
public string QuestionText { get; set; }
}
public class RootObject
{
public string Question { get; set; }
public List<PollQuestion> PollQuestions { get; set; }
}
In Post use [FromBody] attribute to map JSON to C# class:
public void YourMethod([FromBody] RootObject data)
{
// your code to use request data
}
If you are using WebAPI version="5.2.3" (Or might be supported in the lower version also) no need to serialize requested JSON to C# class. Use this to generate C# classes for JSON.
For JSON structure C# treats,
this:
{
}
as Object and
this:
[]
to List<> OR Array.
I set up a simple sample project in .NET Core and it seems to be working fine for me with your JSON data.
These are the classes I used:
public class PollQuestion
{
public string QuestionText { get; set; }
}
public class Poll
{
public string Question { get; set; }
public List<PollQuestion> PollQuestions { get; set; }
}
And here is the API call function:
[HttpPost]
public void Post([FromBody]Poll value)
{
}
When I make a postman request the Poll class is filled as expected.
Here is also a link to my sample project: https://bitbucket.org/alleskapaul/ld42/downloads/JsonExample.zip
Could you change your models in your project to match mine and see if that works? My guess would be that your model is incorrect as the JSON request works for me as well. If it is not working could you upload a sample project so I can see if I can modify it to work?
I was inheriting a class that was using [DataContract] and [DataMember] attributes, so I had to use DataMember for all parameters of the child class as well.
Thanks everyone for your answers but [FromBody] is not required in an API method when parameter is of complex type.
It works without DataContract and DataMember as well if you have not used DataMember anywhere in the class and also not inheriting any class that uses it.
You can get more info here: When to use DataContract and DataMember attributes?

SignalR: exclude non serializable types

I have a class like this:
public class MyData
{
public int Id { get; set; }
public String Name { get; set; }
public ThirdPartyClass { get; set; } // non serializable
}
I said "non-serializable" because when I pass my class to a SignalR client function in this way:
var hub = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
var myData = new MyData();
// fill fields
hub.Clients.All.data(myData);
the call return error 500.
Removing the offending field it work as expected.
Please, note I'm not interested to pass to the client that field.
Right now I know two ways to solve this:
write a custom json serializer
create a shadow class with only the relevant fields, copy the values, and send this class to the clients
Both are uncomfortable when you have dozen of fields.
I'm wondering if there's some DataAnnotation I might use to exclude a field from serialization.
You can use IgnoreDataMemberAttribute() but I'm not sure if that would work with SignalR.
Your alternative if that doesn't work is the JsonIgnore annotation.
Lastly, there is also ScriptIgnore.
IgnoreDataMember Class Reference

JQuery Javascript function to return highchart graph data source in JSON and formatted correctly through Selenium and C#

I am trying to figure out how to get the JSON equivalent of a highchart graph returned to me using Selenium and C#. I got pretty far, but I am hitting a couple issues. For the specific highchart, perform the following steps:
Go here https://rcpsc.releasecandidate-community360qa.net/login.aspx?action=enablelogin
Login with: uw_lr1/test
The chart will show on the next page once you login. The ID of the chart element is "EPAChart"
Issue #1
I can use the below function in the Console tab of DEV tools to retrieve the data in JSON format, but it does not organize it correctly (it lists all EPA's first, then all values of those EPAs second) JSON.stringify(angular.element($('#EPAChart')).scope().$parent.vm['epaGraphData']);
When I plug this into Visual Studio with C# and Selenium and then try to convert this to a DataTable, it does not allow me because the data is not organized correctly. For a similar issue, see : Newtonsoft.Json JsonConvert To Datatable
using Newtonsoft.Json;
using OpenQA.Selenium;
string jsText = string.Format("return JSON.stringify(angular.element($('#EPAChart')).scope().$parent.vm['epaGraphData']);")
var jsResult = driver.ExecuteScript(jsText) as string;
JsonConvert.DeserializeObject<DataTable>(jsResult);
Issue #2
I have a Javascript/Jquery function which produces the JSON organized correctly, but I dont know how to call it using Selenium/C#. The code, driver.ExecuteScript, does not like this function, I guess because it is too complicated and uses variables, so driver.ExecuteScript (IJavaScriptExecutor->ExecuteScript) throws an exception. Here is the function:
var epadatasource = []; for(var i=0;i<angular.element($('#EPAChart')).scope().$parent.vm['epaGraphData'].Categories.length;i++){epadatasource.push({category: angular.element($('#EPAChart')).scope().$parent.vm['epaGraphData'].Categories[i], data: angular.element($('#EPAChart')).scope().$parent.vm['epaGraphData'].Data[i]}); }; JSON.stringify(epadatasource);
For Issue #2, how do I call the above function in C#/Selenium so that it doesnt throw an exception and instead returns my JSON? Or for issue #1, is there a workaround to organize that JSON correctly?
I figured out a workaround for issue #1 and #jeffC provdided the solution to issue #2
Issue 1 resolution is to add JSON to C# object, then convert it to a new object, and deserialize it for a fixed JSON:
public static string TransformJSON(string json, IWebElement chartElem)
{
string fixedJson = "";
if (chartElem.GetAttribute("id") == "EPAChart")
{
dynamic obj = JsonConvert.DeserializeObject<EPAObservationCountOriginal>(json);
List<EPAObservationCountFixed> fixedObject = new List<EPAObservationCountFixed>();
for (int i = 0; i < obj.Categories.Length; i++)
{
fixedObject.Add(new EPAObservationCountFixed() { category = obj.Categories[i], data = obj.Data[i] });
}
fixedJson = JsonConvert.SerializeObject(fixedObject);
}
return fixedJson;
}
#endregion methods
#region Class objects representing graphs
public class EPAObservationCountFixed
{
public string category { get; set; }
public string data { get; set; }
}
public class EPAObservationCountOriginal
{
public string[] Categories { get; set; }
public string[] Data { get; set; }
}
Issue 2 resolution is to add the word "return" in the function:
var epadatasource = []; for(var i=0;i<angular.element($('#EPAChart')).scope().$parent.vm['epaGraphData'].Categories.length;i++){epadatasource.push({category: angular.element($('#EPAChart')).scope().$parent.vm['epaGraphData'].Categories[i], data: angular.element($('#EPAChart')).scope().$parent.vm['epaGraphData'].Data[i]}); }; return JSON.stringify(epadatasource);

How to preserve a C# list in my view page, to manipulate that in client side

I m using ASP.Net MVC 3.0. My model has a list of telephone. I want to preserve that in some way, so that I can manipulate & display later using Jquery in my script.
I tried saving the list in a hidden field, but I am not able to retrieve that in my JavaScript.
Please help me finding a way out. Thx in advance.
You could create a property on your viewmodel which holds a json serialized version of the phonenumbers like this:
public class Person
{
public string Firstname { get; set; }
public string Lastname { get; set; }
public IList<string> PhoneNumbers { get; set; }
public IHtmlString SerializedPhoneNumbers
{
get { return MvcHtmlString.Create(new JavaScriptSerializer().Serialize(PhoneNumbers)); }
}
}
You can use that in the view like:
<script type="text/javascript">
var phoneNumbers = #Model.SerializedPhoneNumbers
</script>
You now can manipulate the collection in your clientside script.

Categories

Resources