Flattening a complex json object for mvc binding - javascript

My controller is returning an object graph to the view in json format like this
return Json(customer);
On the view my json object looks like this
{
Name: 'Joe',
Budget: { Amount: 500, Spend: 100 }
}
Which maps correctly to my customer object:
public class Customer
{
public string Name {get;set;}
public Budget Budget{get;set;}
}
public class Budget
{
public decimal Amount{get;set;}
public decimal Spend{get;set;}
}
I want to pass that same json object back to another method on the controller with this signature:
public ActionResult Method(Customer customer)
When I do this customer's name get populated but not the Budget class, which I understand why because the modelbinder is expecting this: {Name:'Joe','Budget.Amount':500,'Budget.Spend': 100}
So I have to options:
1. I can return the json object in the format it wants, but I don't know how because you can't do this:
return Json(new { Budget.Amount= 500})
I can flatten the json object on the client side. Is there plugins or methods to do this?

Here's a function that convert an object to a flat hash
function flatten(json){
var nj = {},
walk = function(j){
var jp;
for(var prop in j){
jp = j[prop];
if(jp.toString() === "[object Object]"){
walk(jp);
}else{
nj[prop] = jp;
}
}
};
walk(json);
return nj;
}

Protovis has a JavaScript flattener, available under the BSD License.

In my case we have solved it by passing additional object to the action url.
public ActionResult Method(Customer customer, [Bind(Prefix="Budget")]Budget budget)
to make this happen you have to flatten the json data (before you sent it to controller) in following way:
How to pass complex type using json to ASP.NET MVC controller

Related

How to send pure JSON object (which resided inside model object) to view in spring boot?

I'm new to spring boot development. I have to put my json object inside my model object and send it to view. I've used jackson library's ObjectMapper class to convert the object into String.
My controller snippet is
#GetMapping("/show-employee")
public String showEmployee(Model model) {
ObjectMapper objectMapper = new ObjectMapper();
String empString = objectMapper.writeValueAsString(new Employee("santhosh", "kumar", "example#gmail.com"))
model.addAttribute("employee", empString);
return "employees/employee-display";
}
And my model class is
#Entity
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#NotBlank
#Size(min = 3, max = 20)
private String firstName;
#NotBlank
#Size(min = 3, max = 20)
private String lastName;
#Email(message = "Please enter a valid email id")
private String email;
// constructors, getters and setters
On the view side, I have thymeleaf code as below to access the JSON object
<script>
var employeesJsonStr = "[[${employee}]]";
console.log(employeesJsonStr);
</script>
But on the console window, I end up with this...
{"id":0,"firstName":"santhosh","lastName":"kumar","email":"example#gmail.com","projects":null}
How can pass the JSON String to front end so that I can access that using Javascript without having to do html decoding.
I understand you are converting JSON object as string and setting it up inside a model. This is obviously produce String in the front end instead what you could directly send the model object in the response. It will produce JSON data at the end anyway.
#GetMapping("/show-employee" , produces = MediaType.APPLICATION_JSON_VALUE)
public List<Employee> showEmployee(Model model) {
Employee emp = new Employee("santhosh", "kumar", "example#gmail.com"))
model.addAttribute("employee", emp);
return "employees/employee-display";
}

How do I convert a C# object into a Javascript array of arrays using JSON?

I'm trying to convert an object of the following C# class type into a Javascript array of arrays:
public class SankeyData
{
public string Source { get; set; }
public int Width { get; set; }
public string Destination { get; set; }
}
The array of arrays in Javascript needs to look like this:
[["Link1",10,"Link2"],["Link3",20,"Link4"],["Link5",30,"Link6"]]
Is there an easy way to do the conversion? I'm using a jQuery $.getJSON to get the data from a C# controller action.
My related technologies include MVC5, jQuery, and JSON. I've tried using JSON.stringify and JSON.parse, but the data won't come over correctly.
Here's what I have so far:
$.getJSON('/Application/Sankey', { id: #Model.ID }, function (data) {
$.each(data, function (i, item) {
sankey.setData(JSON.stringify(item));
});
});
Which gives a close result, but not quite what I need:
[{"Source":"Link1","Width":10,"Destination":"Link2"},{"Source":"Link3","Width":20,"Destination":"Link4"},{"Source":"Link5","Width":30,"Destination":"Link6"}]
NOTE: I'm already using an MVC #model for something else in the page so I can't just set the #model to the SankeyData class.
There is no direct way out there to serialized C# objects to JSON Array. You can achieve this either
By converting C# objects to C# Array and then serialise the array as JSON.
Use Javascript to convert serialised objects to JSON Array.
I would recommend second option as array is heterogeneous.
Something like this:
function objectsToArray(data, columns) {
var dataArray = [];
for (var i in data) {
var itemArray = [];
for (var j in columns) {
itemArray.push(data[i][columns[j]]);
}
dataArray.push(itemArray);
}
return dataArray;
}
data = [{"Source":"Link1","Width":10,"Destination":"Link2"},{"Source":"Link3","Width":20,"Destination":"Link4"},{"Source":"Link5","Width":30,"Destination":"Link6"}]
console.log(objectsToArray(data, ["Source", "Width", "Destination"]));
So, just pull data using $.getJSON and the feed to objectsToArray with key names in order. Hope that solves your problem.

How to get attributes in Json String in servlet

How can I get each attribute within a Json String?
I got the Json by converting first my array of objects in JavaScript via JSON.stringify. Afterwards I used ajax to pass the string to my servlet.
Servlet Code:
String data = request.getParameter("jsonData");
System.out.println("json data: " + data);
Result:
[{"courseID":"1","codePI":"PO-BSINSYS-02.01","curriculumID":"3"},
{"courseID":"2","codePI":"PO-BSINSYS-02.02","curriculumID":"3"}]
What I want is to get the individual values of the json so that I can assign them later to my object.
E.g.
ArrayList<Curriculum> arrCur = new ArrayList<>();
for (int x = 0; x < array.size(); x++) {
Curriculum cur = new Curriculum();
cur.setCourseID(courseID[x]);
cur.setCodePO(codePI[x]);
cur.setCurriculumID(curriculumID[x]);
arrCur.add(cur);
}
As "crowder" mentioned, you need to parse the json.
There are several ways to do it.
low-level libraries that would convert your string into a
JSONObject which is sort of a map (with keys "courseID", "codePO"
etc). At the time I used fasterxml but I see a newer approach here:
http://crunchify.com/java-how-to-parse-jsonobject-and-jsonarrays/
Higher-level libraries that would map the json directly into
Java business Objects such as "Curriculum". My own experience was
focused on replacing the simple Servlet with Spring - see for
example https://spring.io/guides/gs/rest-service/
good luck
You can use this way if you are sending arry of object from javascript and if you class -
class Curriculum{
Integer courseID;
String codePI;
Integer curriculumID;
}
Use like this -
String data = request.getParameter("jsonData");
JSONArray jsonArray = new JSONArray(data);
java.lang.reflect.Type curriculumType =new com.google.gson.reflect.TypeToken<List<Curriculum>>(){}.getType();
List<Curriculum> curriculum = new GsonBuilder().create().fromJson(jsonArray.toString(), curriculumType);
This will assign list of Curriculum. Hope this will help you.
You can also use jackson-databind API to convert your json to java object.
Create your bean for Curriculum.
class Curriculum{
Integer courseID;
String codePI;
Integer curriculumID;
public Integer getCourseID() {
return courseID;
}
public void setCourseID(Integer courseID) {
this.courseID = courseID;
}
public String getCodePI() {
return codePI;
}
public void setCodePI(String codePI) {
this.codePI = codePI;
}
public Integer getCurriculumID() {
return curriculumID;
}
public void setCurriculumID(Integer curriculumID) {
this.curriculumID = curriculumID;
}
}
Following is the code to convert your json to Curriculum object
JSONArray jsonArray = getJSONArray();
ObjectMapper objectMapper = new ObjectMapper();
for(int i =0;i<jsonArray.length();i++){
JSONObject jsonData = jsonArray.getJSONObject(i);
//convert json string to object
try {
Curriculum curr= objectMapper.readValue(jsonData.toString().getBytes(), Curriculum.class);
System.out.println(curr);
} catch (Exception e) {
e.printStackTrace();
}
}

c# equivalent for serializing json

whats the equivalent for creating json serialized data for this javascript code:
chartData.push({date: "bla",value1: "bla1",value2: "bla2"});
chartData.push({date: "blx",value2: "blax2"});
The json will look something like this:
[{
"date": bla,
"value1": bla1,
"value2": bla3,
}, {
"date": blx,
"value2": blax2
}]
I tried creating a list of class, but when i dont assign the value1 property, the value will just be zero. But i dont want the property to be displayed in the json at all, when not assigned.
List <Models.HistoClass> HistoData= new List<Models.HistoClass>();
HistoData.Add(new Models.HistoClass {date="bla",value1="bla1",value2="bla3"});
HistoData.Add(new Models.HistoClass { date= "blx", value2="blax2" });
How should i create the datamodel to have a json like that?
Thanks!
If you're creating data manually in the way you show, you could use anonymous types to construct data the looks exactly how you want:
List <object> HistoData= new List<object>();
HistoData.Add(new {date="bla",value1="bla1",value2="bla3"});
HistoData.Add(new { date= "blx", value2="blax2" });
However, if you want to use a strong type and/or your code is initializing the values in the same way every time, but sometimes values just aren't present, then you can make the values nullable and tell JSON.NET to ignore null properties when serializing:
public class HistoClass
{
public string date;
[JsonProperty(NullValueHandling=NullValueHandling.Ignore)]
public int? value1;
[JsonProperty(NullValueHandling=NullValueHandling.Ignore)]
public int? value2;
}
...
List <Models.HistoClass> HistoData= new List<Models.HistoClass>();
HistoData.Add(new Models.HistoClass {date="bla",value1="bla1",value2="bla3"});
HistoData.Add(new Models.HistoClass { date= "blx", value2="blax2" });
You can use Json.NET's ShouldSerialize:
Public class DateAndValues
{
public DateTime Date {get; set;}
public Int32 Index {get; set;}
public Int32 Value1 {get; set;}
public Int16 Value2 {get; set;}
public bool ShouldSerializeValue1 ()
{
// your condition for serialization, for example even objects:
this.Index % 2 != 0;
}
}
This description:
To conditionally serialize a property, add a method that returns boolean with the same name as the property and then prefix the method name with ShouldSerialize. The result of the method determines whether the property is serialized. If the method returns true then the property will be serialized, if it returns false then the property will be skipped.
is taken from this link.
To actually serialize, of course, use:
var firstObj = new DateAndValues { Index = 1, .. };
var secondObj = new DateAndValues { Index = 2, .. };
string json =
JsonConvert.SerializeObject(new[] {firstObj, secondObj}, Formatting.Indented);
and according to the condition above, secondObj (even Index) will not have Value1.

How to implement Dynamic data for chart in MVC?

Im new in ASP.NET MVC, im doing on my own project and i have some problems. I want to draw line chart from with data from database.
I hope you will understend me (bad english, sorry):
I have table of metals, after i click on specific one, i want to see chart that show me price of metal by date.
For example, i click on Copper;
PricePoint is my Controller, wich action shoud i call here ?
#Html.DisplayFor(modelItem => item.name)
I call DrawChart Action in PricePoint controller:
public ActionResult DrawChart()
{
return View();
}
In same controlller i create action that add data from database to json and return it.
public ActionResult Statistics(int ?id) {
// here i pull data from database to stats
return Json(stats,JsonRequestBehavior.AllowGet);
}
This is my view page where i want to show chart, DrawChart.cshtml file.
<script type="text/javascript">
$.get('#Url.Action("Statistics")', function(result){
new Morris.Line({
// ID of the element in which to draw the chart.
element: 'myfirstchart',
// Chart data records -- each entry in this array corresponds to a point on
// the chart.
data: [
result
],
// The name of the data record attribute that contains x-values.
xkey: 'year',
// A list of names of data record attributes that contain y-values.
ykeys: ['value'],
// Labels for the ykeys -- will be displayed when you hover over the
// chart.
labels: ['Value']
});
});
</script>
When i click on metal, DrawChart action return view DrawChart.cshtml, then JavaScript run Statistics function and populate data for chart, is that how this works?
I have blank page, with no result, when i type in url: http://localhost:50101/PricePoint/DrawChart
When url is next, i see json data from database:
http://localhost:50101/PricePoint/Statistics
I dont know where is problem. When i put example data in script, like this
data: [
{ year: '2008', value: 20 },
{ year: '2009', value: 10 },
{ year: '2010', value: 5 },
{ year: '2011', value: 5 },
{ year: '2012', value: 20 }
],
i see line chart as expected. Again, sorry for bad english, hope you can help me and i hope you understend my question.
I had a play with it and I managed to display the chart just fine. Here are a few things to watch out for that may be the cause of your problem:
1) your call to $.get('#Url.Action("Statistics")' is not passing in an id though you declared one on your action public ActionResult Statistics(int ?id). Considering it's nullable maybe you are prepared to serve a default set of data if no id is passed, but thought I'd mention in case that is what's affecting the logic of your database retrieval and affecting the results returned
2) I noticed that your link to the DrawChart action passed in new { id = item.ID } however this not captured on the server-side since your DrawChart action is missing the parameter, it should be something like : public ActionResult DrawChart(id). I understand this could've been for the sake of simplifying it just to post here and may not affect anything but thought I'd point it out
3) Be careful about what you are returning from the MVC action. The stats object in return Json(stats,JsonRequestBehavior.AllowGet); should be a C# array containing the properties value and year for each object in the array, so something like :
new[] {new Entry() {value = 20, year = 2008}, new Entry() {value = 10, year = 2009}};
If you just pass a string to the return Json() statement it won't work properly since it'll think it's just one long json string not a json array object.
If you want to return a string rather than an actual serialized c# collection then you can use something like : return Content(dataString, "application/json");
4) Case matters! Make sure that the json returned contains properties with names of year and value for each entry just as you declared in your morris object on the xkey and ykey values. This can be quite a subtle trap since return Json() will serialize your json objects exactly as they are declared in your classes and while the tendency in javascript code is to start variables and properties with lower-case in .Net properties are usually declared with upper-case such as public int Year { get; set; }
Conclusion:
I got it working by returning this code :
public ActionResult Statistics(int ?id) {
var data = new[] {new Entry() {value = 20, year = 2008}, new Entry() {value = 10, year = 2009}};
return Json(data,JsonRequestBehavior.AllowGet);
}
And on your Morris initialization code remove the array brackets from the data declartion so data : result and not data : [result]
Your first step to troubleshoot this is to look at what your Statistics method is returning. You can do this really easily by testing your web site in Chrome, for instance, and hitting F12 then choose the Network tab. Then Ctrl+F5 the page and find the call to the server in the results pane. Click on it and then choose Response and keep troubleshooting your method till it returns what you need.
If the data is in a wrong format and doesn't contain the keys that Morris expects Morris will throw an error saying Uncaught TypeError: Cannot read property 'match' of undefined . Keep trying till you make that go away and hopefully you should see your graph :)
PS: one last thing, I'd wrap the Morris init code in a $(document).ready() call
When i send data (values and dates) from function (manualy input), everything is ok, json file is populeted god, and i see chart, but when i send data from database, there is no chart but i see that json file is also populeted.
Here is code:
public class YearlyStat
{
public string year { get; set; }
public double value { get; set; }
}
public ActionResult Statistics(int? id)
{
//var result = db.pricepoints.Where(r => r.commodityID.Equals(id));
var items = from item in db.pricepoints
where (item.commodityID == id)
select item;
var stats = new List<YearlyStat>();
foreach (var item in items)
{
stats.Add(new YearlyStat
{
year = item.date_of_price.ToShortDateString(),
value = item.value
});
}
//but this work's
//string s = "2.2.2002";
//double v = 20.20;
//stats.Add(new YearlyStat { year = s, value = v });
//or
//stats.Add(new YearlyStat { year = "2.2.2002", value = 20.20 });
return Json(stats, JsonRequestBehavior.AllowGet);
}
Types are string and double in both cases...

Categories