I have an ASP.NET Core 3.1 Web App that has functionality where a user can input a stock ticker and a chart is created for them using a query to retrieve data (Price & Date) for that ticker. I've followed basic Google Chart API walkthroughs to implement in my app. It works if the data is hardcoded in the JSON method, but if I want to dynamically view a chart based on whatever ticker I enter, the chart doesn't receive the JSON data needed.
What I tried was having a Ticker Entry page (Action method) with a Form that returns the user inputted ticker to the Chart action method. What I wanted was for the Chart method to handle all the LINQ Querying and transforming the list into a JSONList, so that it can be passed into it's View method. I'll post the code in order.
TickerEntry.cshtml
@using (Html.BeginForm("Chart", "Stocks", FormMethod.Get))
{
<table>
<tr>
<td>Enter a Ticker to pull up its chart: </td>
<td>@Html.TextBox("stockTicker")</td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Submit"></td>
</tr>
</table>
}
StocksController.cs
public List<StockLineChart> GetStockData(string stockTicker)
{
var list = new List<StockLineChart>();
var result = (from s in _context.HistoricalDatas
where s.Ticker == stockTicker
select new { s.Price, s.DateOfClose });
list = result.AsEnumerable()
.Select(sl => new StockLineChart
{
Price = sl.Price,
DateOfClose = Convert.ToDateTime(sl.DateOfClose)
}).ToList();
return list;
}
public IActionResult TickerEntry()
{
return View();
}
public IActionResult Chart(string stockTicker)
{
//Returns the Chart View, but passes in the list of stock price&date transformed into JSON
return View(GetLineChartJSON(GetStockData(stockTicker)));
}
public JsonResult GetLineChartJSON(List<StockLineChart> stockList)
{
return Json(new { JSONList = stockList });
}
Chart.cshtml
@{
ViewData["Title"] = "Chart";
}
<div >
<div >
<div id="chartdiv" style="width:1000px;height:350px;">
</div>
</div>
</div>
@section Scripts
{
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
// Load the Visualization API and the corechart package.
google.charts.load('current', { 'packages': ['corechart'] });
// Set a callback to run when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(DrawChart);
// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
function DrawChart() {
$(function () {
$.ajax({
type: 'GET',
url: '/Stocks/GetLineChartJSON',
success: function (chartsdata) {
// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
//get jsonList from Object
var Data = chartsdata.jsonList;
var data = new google.visualization.DataTable();
data.addColumn('string', 'DateOfClose');
data.addColumn('number', 'Price');
//Loop through each list data
for (var i = 0; i < Data.length; i ) {
data.addRow([Data[i].dateOfClose, Data[i].price]);
}
// Instantiate and draw our chart, passing in some options
var chart = new google.visualization.LineChart(document.getElementById('chartdiv'));
//Draw line chart command with data and chart options
chart.draw(data,
{
title: "Stock Chart",
position: "top",
fontsize: "14px",
});
},
error: function () {
alert("Error loading data! Please try again.");
}
});
})
}
</script>
}
What I believe is that the GetLineChartJSON shouldn't take any parameters, but it's hard to do this because it needs some type of data(Either a ticker to query the list, or the list itself so it can transform into JSON)
For example, this would work:
StockController.cs
public JsonResult GetLineChartJSON()
{
var list = new List<StockLineChart>();
var result = (from s in _context.HistoricalDatas
where s.Ticker == "AC"
select new { s.Price, s.DateOfClose });
list = result.AsEnumerable()
.Select(sl => new StockLineChart
{
Price = sl.Price,
DateOfClose = Convert.ToDateTime(sl.DateOfClose)
}).ToList();
return Json(new { JSONList = list });
}
Note that there's nothing passed into this method, and stockTicker has now been hardcoded in as "AC", which I don't want, because the user chooses what stock they want to see.
I hope I'm not confusing with the explanation of my problem, I'm willing to clarify any misunderstanding.
CodePudding user response:
A whole working demo here you could follow:
Chart.cshtml
@{
ViewData["Title"] = "Chart";
}
<div >
<div >
<div id="chartdiv" style="width:1000px;height:350px;">
</div>
</div>
</div>
@section Scripts
{
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', { 'packages': ['corechart'] });
google.charts.setOnLoadCallback(DrawChart);
function DrawChart() {
$(function () {
var Data = @Html.Raw(ViewBag.StockTicker); //get the ViewBag object
var data = new google.visualization.DataTable();
data.addColumn('string', 'DateOfClose');
data.addColumn('number', 'Price');
for (var i = 0; i < Data.length; i ) {
//change uppercase here....
data.addRow([Data[i].DateOfClose, Data[i].Price]);
}
var chart = new google.visualization.LineChart(document.getElementById('chartdiv'));
chart.draw(data,
{
title: "Stock Chart",
position: "top",
fontsize: "14px",
});
})
}
</script>
}
Controller
public IActionResult TickerEntry()
{
return View();
}
public List<StockLineChart> GetStockData(string stockTicker)
{
var list = new List<StockLineChart>();
var result = (from s in _context.HistoricalDatas
where s.Ticker == stockTicker
select new { s.Price, s.DateOfClose });
list = result.AsEnumerable()
.Select(sl => new StockLineChart
{
Price = sl.Price,
DateOfClose = Convert.ToDateTime(sl.DateOfClose)
}).ToList();
return list;
}
public IActionResult Chart(string stockTicker)
{
//Use ViewBag instead....
ViewBag.StockTicker =JsonConvert.SerializeObject(GetStockData(stockTicker));
return View();
}
//no need GetLineChartJSON method any more....