Using Google charts API with MVC 3 Razor and jquery ajax - asp.net-mvc-3

I'm trying to display a pie chart in my website using Google charts API so far i cant get it to work and I couldn't find any examples that use MVC 3 Razor.
here is my code im using json to get the data
// Load the Visualization API and the piechart package.
google.load('visualization', '1.0', { 'packages': ['corechart'] });
// Set a callback to run when the Google Visualization API is loaded.
google.setOnLoadCallback(drawChart);
JSON.stringify = JSON.stringify || function (obj) {
var t = typeof (obj);
if (t != "object" || obj === null) {
// simple data type
if (t == "string") obj = '"' + obj + '"';
return String(obj);
}
else {
// recurse array or object
var n, v, json = [], arr = (obj && obj.constructor == Array);
for (n in obj) {
v = obj[n]; t = typeof (v);
if (t == "string") v = '"' + v + '"';
else if (t == "object" && v !== null) v = JSON.stringify(v);
json.push((arr ? "" : '"' + n + '":') + String(v));
}
return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}");
}
};
// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
function drawChart() {
// Create the data table.
var data = new google.visualization.DataTable();
data.addColumn('string', 'Topping');
data.addColumn('number', 'Slices');
$.post('#Url.Content("~/Home/GetMyChart1")',
function (items) {
// Successful requests get here
alert(JSON.stringify(items) + " - " + items.rows.length);
data.addRows(items.rows.length);
$.each(items.rows, function (i, item) {
alert(i);
data.setCell(i, 0, item.Name);
data.setCell(i, 1, item.ID);
});
alert("finished");
alert(data.length);
});
// Set chart options
var options = { 'title': 'How Much Pizza I Ate Last Night',
'width': 400,
'height': 300
};
// Instantiate and draw our chart, passing in some options.
var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
The controller Code
public ActionResult GetMyChart1(string CurrentClass)
{
var tests = from t in db.Tests
group t by new { t.StudentID, t.Student.CurrentSchoolGrade } into tl
select new { StudentID = tl.Key.StudentID, Class = tl.Key.CurrentSchoolGrade, Score = (tl.Sum(k => k.Score)/tl.Sum(l => l.Part.Score))* 100, Count = tl.Count() };
var results = from t in tests
where t.Class == CurrentClass
select t;
List<DataItem> dt = new List<DataItem>();
dt.Add(new DataItem(results.Count(x => x.Score <= 40), "0% - 40%"));
dt.Add(new DataItem(results.Count(x => x.Score <= 60 && x.Score > 40), "40% - 60%"));
dt.Add(new DataItem(results.Count(x => x.Score <= 80 && x.Score > 60), "60% - 80%"));
dt.Add(new DataItem(results.Count(x => x.Score <= 100 && x.Score > 60), "80% - 100%"));
chartJson cj = new chartJson();
cj.rows = dt;
return Json(cj);
}
public class chartJson
{
public List<DataItem> rows { get; set; }
}
public class DataItem
{
public DataItem(int id, string name)
{
ID = id;
Name = name;
}
public int ID { get; set; }
public string Name { get; set; }
}
all the alerts returns correct values except alert(data.length); it returns undefined
and the drawing div appears with a label written in it No data

I am thinking that you need to move the chart drawing lines inside of the POST callback:
$.post('#Url.Content("~/Home/GetMyChart1")', function (items) {
// Successful requests get here
alert(JSON.stringify(items) + " - " + items.rows.length);
data.addRows(items.rows.length);
$.each(items.rows, function (i, item) {
alert(i);
data.setCell(i, 0, item.Name);
data.setCell(i, 1, item.ID);
});
alert("finished");
alert(data.length);
// Set chart options
var options = {
'title': 'How Much Pizza I Ate Last Night',
'width': 400,
'height': 300
// Instantiate and draw our chart, passing in some options.
var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
chart.draw(data, options);
});
};

Google charts API is written in JavaScript so it can be used with any web framework, including ASP.NET MVC. All that you need to do is to include it in your views. It shouldn't be limited or not work because you are using ASP.NET MVC.

After reviewing the full sample of code it looks like the google.setOnLoadCallback(drawChart); is most likely executing the drawChart method before the data is ready. Thus no chart.
Instead of making an Ajax .Post to the server to retrieve data, just build your data on the initial request.

Related

Trouble accessing the property of a class in Ajax

In index.cshtml I am using Ajax. In click event of .removelink to get changes from action controller as follows:
$(".RemoveLink").click(function () {
// Get the id from the link
var recordToDelete = $(this).attr("data-id");
if (recordToDelete != '' || recordToDelete != null) {
// Perform the ajax post
$.ajax({
//contentType: 'application/json',
//dataType: 'text',
type: 'post',
dataType: 'JSON',
url: '/ShoppingCart/RemoveFromCart/',
data: { id: recordToDelete },
success: function (data) {
if (data.ItemCount == 0) {
$('#row-' + data.DeleteId).fadeOut('slow');
}
else {
$('#item-count-' + data.DeleteId).text(data.ItemCount);
}
$('#cart-total').text(data.CartTotal);
$('#update-message').text(data.Message);
$('#cart-status').text('Cart (' + data.CartCount + ')');
}
});
}
});
And in controller:
//AJAX: /ShoppingCart/RemoveFromCart/5
[HttpPost]
public IActionResult RemoveFromCart(int id)
{
//Remove the item from the cart
var cart = ShoppingCart.GetCart(this.HttpContext);
// Get the name of the album to display confirmation
//string albumName = _context.Carts
//.Single(item => item.RecordId == id).Album.Title;
Cart cartt = ShoppingCart.getCartForGetalbumName(id);
// Remove from cart
int itemCount = cart.RemoveFromCart(id);
// Display the confirmation message
var results = new ShoppingCartRemoveViewModel
{
Message = HtmlEncoder.Default.Encode(cartt.Album.Title) +
" has been removed from your shopping cart.",
CartTotal = cart.GetTotal(),
//CartCount = cart.GetCount(),
ItemCount = itemCount,
DeleteId = id
};
return Json(results);
}
However, it does not work. Additionally, the text of the tags does not change and fadeOut() does not work.
When I send a unit field (eg, a string or an integer) Jason reads it well.
However, when I send a class containing some properties (like the example above), its value in the data parameter is problematic.
Please modify your property to lowercase , try to use :
success: function (data)
{
if (data.itemCount == 0) {
$('#row-' + data.deleteId).fadeOut('slow');
}
else {
$('#item-count-' + data.deleteId).text(data.itemCount);
}
$('#cart-total').text(data.cartTotal);
$('#update-message').text(data.message);
$('#cart-status').text('Cart (' + data.cartCount + ')');
}
i add The following code to convert data to json in RemoveFromCart controller action:
var resulTtoJson = Newtonsoft.Json.JsonConvert.SerializeObject(results);
and return json type :
[HttpPost]
public IActionResult RemoveFromCart(int id)
{
//Remove the item from the cart
var cart = ShoppingCart.GetCart(this.HttpContext);
// Get the name of the album to display confirmation
//string albumName = _context.Carts
//.Single(item => item.RecordId == id).Album.Title;
Cart cartt = ShoppingCart.getCartForGetalbumName(id);
// Remove from cart
int itemCount = cart.RemoveFromCart(id);
// Display the confirmation message
var results = new ShoppingCartRemoveViewModel
{
Message ="محصول"+ cartt.Album.Title +
"از سبد خریدتان حذف گردید.",
CartTotal = cart.GetTotal(),
//CartCount = cart.GetCount(),
ItemCount = itemCount,
DeleteId = id
};
var resulTtoJson = Newtonsoft.Json.JsonConvert.SerializeObject(results);
return Json(resulTtoJson);
also add the following code in view to convert data to javascript type:
var data =JSON.parse(dataa);
and use it:
$(".RemoveLink").click(function () {
// Get the id from the link
var recordToDelete = $(this).attr("data-id");
// alert(recordToDelete);
if (recordToDelete != '' || recordToDelete != null) {
// Perform the ajax post
$.post("/ShoppingCart/RemoveFromCart/", { id: recordToDelete},
function (dataa) {
// Successful requests get here
// Update the page elements
var data =JSON.parse(dataa);
if (data.ItemCount == 0) {
$('#row-' + data.DeleteId).fadeOut('slow');
} else {
$('#item-count-' + data.DeleteId).text(data.ItemCount);
}
$('#cart-total').text(data.CartTotal);
$('#update-message').text(data.Message);
$('#cart-status').text('Cart (' + data.CartCount + ')');
}
});
}
});

In my mvc full calendar, events are not getting displayed

I am facing a problem in rendering events from a SQL Server database. All events are getting fetched using this code but not getting displayed in my calendar, so can anyone please help me?
.cshtml code:
events: function(start, end, callback) {
debugger;
var startdate=start.format('DD-MM-YYYY HH:mm'),
enddate=end.format('DD-MM-YYYY HH:mm'),
params={'start_time':startdate,'end_time':enddate};
$.ajax({
type: 'GET',
url: '#Url.Action("GetAllEvents","Base")',
success: function (data) {
alert("hello");
}
});
}
,
my controller code:
public static List<Task_has_UsersModel> LoadAllTasks(double start, double end)
{
var fromDate = ConvertFromUnixTimestamp(start);
var toDate = ConvertFromUnixTimestamp(end);
var sql = "SELECT * from task_has_users";
var data = Database.Open("DefaultConnection").Query(sql);
List<Task_has_UsersModel> result = new List<Task_has_UsersModel>();
foreach (var item in data)
{
Task_has_UsersModel model = new Task_has_UsersModel();
model.Task_Id = Convert.ToInt32(item.Task_Id);
model.Project_Id = Convert.ToInt32(item.Project_Id);
model.start_time = item.start_time;
model.end_time = item.end_time;
result.Add(model);
}
return result;
}
[HttpPost]
public JsonResult GetAllEvents(double start, double end)
{
var ApptListForDate = LoadAllTasks(start,end);
var eventList = from e in ApptListForDate
select new
{
id=e.Task_Id,
name=e.Project_Id,
start=e.start_time.ToString(),
end=e.end_time.ToString(),
allDay=false,
color = "#008000",
//allDay=false,
className= "label-important" ,
};
var rows = eventList.ToArray();
return Json(rows, JsonRequestBehavior.AllowGet);
}
private static DateTime ConvertFromUnixTimestamp(double timestamp)
{
var origin = new DateTime(1970, 1, 1, 0, 0, 0, 0);
return origin.AddSeconds(timestamp);
}
}
I have tried with (double start,double end ) still my events are not getting displayed in calendar
Finally after 3 days of hard work , i have done this.... No need to write anything in events , just call a function , it will automatically appends the date range and all you are done................... thanks
.cshtml code:
events:'GetAllEvents',
eventLimit: 50,
editable: true,
droppable: true,
// timeFormat: 'hh:mm-h:mma ',
timeFormat: 'hh:mma ',
displayEventEnd : true,
my controller code:
public static List<Task_has_UsersModel> LoadAllTasks(string start, string end,string uname)
{
UsersContext db = new UsersContext();
var uid = (from i in db.UserProfiles
where i.UserName == uname
select i.UserId).FirstOrDefault();
int userId = Convert.ToInt32(uid);
// var culture = System.Globalization.CultureInfo.CurrentCulture;
var sql = "SELECT * from task_has_users where UserId = " + userId;
var data = Database.Open("DefaultConnection").Query(sql);
List<Task_has_UsersModel> result = new List<Task_has_UsersModel>();
foreach (var item in data)
{
Task_has_UsersModel model = new Task_has_UsersModel();
model.Task_Id = Convert.ToInt32(item.Task_Id);
model.Project_Id = Convert.ToInt32(item.ProjectId);
// model.start_time = Convert.ToDateTime(item.start_time);
model.start_time = (item.start_time).ToString("yyyy-MM-dd HH-mm-ss");
model.end_time = (item.end_time).ToString("yyyy-MM-dd HH-mm-ss");
model.title = item.title;
result.Add(model);
}
return result;
}
[HttpGet]
public JsonResult GetAllEvents(string start, string end)
{
string uname = (Session["UserName"]).ToString();
var ApptListForDate = LoadAllTasks(start,end,uname);
var eventList = from e in ApptListForDate
select new
{
id=e.Task_Id,
title=e.title,
start=e.start_time,
end=e.end_time,
allDay=false,
color = "#008000",
//allDay=false,
className= "label-important" ,
};
var rows = eventList.ToArray();
return Json(rows, JsonRequestBehavior.AllowGet);
}
finally done

Handsontable - Unable to keep html element created by a custom renderer visible

I am using the open source version of handsontable (version 0.29.2). I created a custom renderer that creates a hidden SPAN element/icon on every row. When input fails validation, I use jQuery to programmatically unhide/show the SPAN tag/icon so that it appears in the right-hand side of the cell. It works great, but unfortunately when I enter an invalid value into another cell, the icon from the first cell disappears. The preferred behavior is to have all of the icons visible in cells where a validation issue exists.
Question: Is there a way to keep all of the icons visible?
If this is not possible, is there a different way in handsontable to display an image after validation? As you can see from the code below (and my jsfiddle example), I am not using the built-in handsontable validation hooks. With the built-in validation, I can't add an icon like I want - I can only override the default style of an invalid cell by using invalidCellClassName.
I have created a simple example with instructions demonstrating my issue:
http://jsfiddle.net/4g3a5kqc/15/
var data = [
["1", "abc"],
["2", "def"],
["3", "ghi"],
["4", "jkl"]
],
container = document.getElementById("example"),
hot1;
// This function is a custom renderer that creates a hidden SPAN element/
// icon. In this example, when a user changes the value, the SPAN element
// icon will appear.
function customRenderer(instance, td, row, col, prop, value, cellProperties) {
td.innerHTML = value +
'<span id="account-code-error-' + row + '-' + col + '" class="account-code-error ' +
'glyphicon glyphicon-exclamation-sign text-warning jzb-icon-md pull-right" ' +
'style="font-size: large; cursor: pointer; display: none;"></span>';
}
var hot1 = new Handsontable(container, {
data: data,
rowHeaders: true,
colHeaders: true,
stretchH: 'all',
cells:
function (row, col, prop) {
var cellProperties = {};
if (col == 0) {
cellProperties.renderer = customRenderer;
}
return cellProperties;
}
});
hot1.addHook('afterChange', afterChange);
// Show the SPAN tag with the icon
// in the right-hand side of the cell.
function afterChange(changes, source) {
console.log(changes, source);
if (source == 'edit' || source == 'autofill') {
$.each(changes,
function (index, element) {
var change = element;
var rowIndex = change[0];
var columnIndex = change[1];
var oldValue = change[2];
var newValue = change[3];
console.log(oldValue, newValue, rowIndex, columnIndex, change);
if (columnIndex != 0) {
return;
}
if (newValue >= 0) {
return;
}
var cellProperties = hot1.getCellMeta(rowIndex, hot1.propToCol(columnIndex));
var td = hot1.getCell(rowIndex, columnIndex, true);
var span = td.getElementsByTagName("span");
$("#" + span[0].id).show();
});
}
}
Due to customRenderer() being called after every change we have to store somewhere cells with spans visible and check for it at the rendering. On the other hand if the span should not be visible (input is valid) we need to remove it from the array of cells wit visible spans. Working fiddle:
http://jsfiddle.net/8vdwznLs/
var data = [
["1", "abc"],
["2", "def"],
["3", "ghi"],
["4", "jkl"]
],
container = document.getElementById("example"),
hot1,
visibleSpans = [];
// This function is a custom renderer that creates a hidden SPAN element/
// icon. In this example, when a user changes the value, the SPAN element
// icon will appear.
function customRenderer(instance, td, row, col, prop, value, cellProperties) {
if (visibleSpans.indexOf(td) > -1) {
td.innerHTML = value +
'<span id="account-code-error-' + row + '-' + col + '" class="account-code-error ' +
'glyphicon glyphicon-exclamation-sign text-warning jzb-icon-md pull-right" ' +
'style="font-size: large; cursor: pointer;"></span>';
} else {
td.innerHTML = value +
'<span id="account-code-error-' + row + '-' + col + '" class="account-code-error ' +
'glyphicon glyphicon-exclamation-sign text-warning jzb-icon-md pull-right" ' +
'style="font-size: large; cursor: pointer; display: none;"></span>';
}
}
var hot1 = new Handsontable(container, {
data: data,
rowHeaders: true,
colHeaders: true,
stretchH: 'all',
cells:
function (row, col, prop) {
var cellProperties = {};
if (col == 0) {
cellProperties.renderer = customRenderer;
}
return cellProperties;
}
});
hot1.addHook('afterChange', afterChange);
// Show the SPAN tag with the icon
// in the right-hand side of the cell.
function afterChange(changes, source) {
console.log(changes, source);
if (source == 'edit' || source == 'autofill') {
$.each(changes,
function (index, element) {
var change = element;
var rowIndex = change[0];
var columnIndex = change[1];
var oldValue = change[2];
var newValue = change[3];
var td = hot1.getCell(rowIndex, columnIndex, true);
console.log(oldValue, newValue, rowIndex, columnIndex, change);
if (columnIndex != 0) {
return;
}
if (newValue >= 0) {
var indexOfSpan = visibleSpans.indexOf(td);
if (indexOfSpan > -1) {
visibleSpans.splice(indexOfSpan, 1);
hot1.render();
return;
}
return;
}
var cellProperties = hot1.getCellMeta(rowIndex, hot1.propToCol(columnIndex));
visibleSpans.push(td);
var span = td.getElementsByTagName("span");
span[0].setAttribute('style', '');
});
}
}

context: contextMenu.SelectionContext() not working for selected text in input fields

My little project - extension for Firefox that translate text. User select text on page, make right click and see translation right in the context-menu or in popup. In my contextMenu.Item I am using context: contextMenu.SelectionContext() for determin context (for example, user click on image or on selected text).
But this not working if text selected in input field, documentation page not mentioned it. What I need to do for handling selection context for input fields, not only for regular text on page? In this situation I see my context-menu, but in debug I see that selected text was not send to the code of my extension.
I tried this code - nothing.
My current code is:
const { getMostRecentBrowserWindow } = require('sdk/window/utils');
var uuid = require('sdk/util/uuid').uuid();
var uuidstr = uuid.number.substring(1, 37);
var notifications = require("sdk/notifications");
var contextMenu = require("sdk/context-menu");
var Request = require("sdk/request").Request;
var self = require('sdk/self');
var tabs = require('sdk/tabs');
var prefs = require('sdk/simple-prefs').prefs;
var cmitems = null;
var wasTranslatedSecondTime = false;
var inProgress = '...';
var translated = '';
var menuItem = contextMenu.Item({
data: uuidstr, // for 'binding' tooltop's 'id' + text
label: inProgress, // ...
image: self.data.url('ico.png'),
context: contextMenu.SelectionContext(),
contentScript: 'self.on("context", function() {' +
'var selectionText = window.getSelection().toString();' +
'self.postMessage({name:"context", data:selectionText});' +
'return true;' +
'});' +
'self.on("click", function() {' +
'var selectionText = window.getSelection().toString();' +
'self.postMessage({name:"click", data:"https://translate.yandex.ru?text=" + selectionText.replace("&", "%26")});' +
'})',
onMessage: function(message) {
if (message.name == 'context') {
menuItem.label = inProgress; // ...
if (cmitems != undefined) cmitems[0].tooltipText = '';
var input = message.data.replace('&', '%26');
translate('ru', input); // default direction - from EN to RU
} else { // if (message.name == 'click')
tabs.open(message.data);
}
}
});
function translate(lang, input) {
Request({ // key is not referral but API-key: https://api.yandex.com/translate/doc/dg/concepts/api-overview.xml
url: 'https://translate.yandex.net/api/v1.5/tr.json/translate?key=trnsl.1.1.20150627T071448Z.117dacaac1e63b79.6b1b4bb84635161fcd400dace9fb2220d6f344ef&lang=' +
lang + '&text=' + input,
onComplete: function (response) {
translated = response.json.text[0];
if (input == translated && wasTranslatedSecondTime == false) { // if input on Russian and we receive the same text -
translate('en', input); // translate again selected text into English
wasTranslatedSecondTime = true;
} else { // show results
if (prefs.popup) popup(translated);
menuItem.label = translated;
wasTranslatedSecondTime = false;
if (prefs.tooltip) tooltip(translated);
}
}
}).get();
}
function popup(text) {
if (text.length > 0)
notifications.notify({
title: 'translate.yandex.ru',
text: text,
time: 5000
})
}
function tooltip(translated) {
menuItem.data = uuidstr + translated;
cmitems = getMostRecentBrowserWindow().document.querySelectorAll(".addon-context-menu-item[value^='"+uuidstr+"']");
cmitems[0].tooltipText = cmitems[0].value.substring(36);
}
It appears that your question boils down to: How do I get the selected text, even when it is in an input field?
You are currently using var selectionText = window.getSelection().toString(); which is failing when the selected text is in an input field.
In one of my extensions, I use the following to obtain the selected text. It works even when the selected text is in an input field:
/**
* Fix an issue with Firefox that it does not return the text from a selection if
* the selected text is in an INPUT/textbox.
*/
function getSelectedText(win,doc) {
//Adapted from a post by jscher2000 at:
// http://forums.mozillazine.org/viewtopic.php?f=25&t=2268557
//Is supposed to solve the issue of Firefox not getting the text of a selection when
// it is in a textarea/input/textbox.
var ta;
if (win.getSelection && doc.activeElement){
if (doc.activeElement.nodeName == "TEXTAREA" ||
(doc.activeElement.nodeName == "INPUT" &&
doc.activeElement.getAttribute("type").toLowerCase() == "text")
){
ta = doc.activeElement;
return ta.value.substring(ta.selectionStart, ta.selectionEnd);
} else {
//As of Firefox 31.0 this appears to have changed, again.
//Try multiple methods to cover bases with different versions of Firefox.
let returnValue = "";
if (typeof win.getSelection === "function"){
returnValue = win.getSelection().toString();
if(typeof returnValue === "string" && returnValue.length >0) {
return returnValue
}
} //else
if (typeof doc.getSelection === "function"){
returnValue = doc.getSelection().toString();
if(typeof returnValue === "string" && returnValue.length >0) {
return returnValue
}
} //else
if (typeof win.content.getSelection === "function"){
returnValue = win.content.getSelection().toString();
if(typeof returnValue === "string" && returnValue.length >0) {
return returnValue
}
} //else
//It appears we did not find any selected text.
return "";
}
} else {
return doc.getSelection().toString();
}
}

Filter plugin without data-attribute

How to filter or sort info without data-attribute by plugin of MixItUp/Isototpe?
Maybe filter will be an #url and sort will be class.
Assuming you have a JSON set, you can filter against the values like so (I'm also assuming you have taken the filter/sort value from the DOM already):
Haven't run this so apologies if not exact - and I'm not used to stack overflow formatting yet but any issues and I'll edit. I think the logic should be OK
var dataset = [
{url: '/test'},
{url: '/test2'}
];
var filterValue = '/test2'; // pass this to function or get from DOM
var sortBy = 'url'; // again, pass in somewhere or get from DOM
var sortType = 'asc';
function filter(data, filter) {
var filteredResults = data.filter(function (el) {
return (filter !== '' && el.url.toLowerCase().indexOf(filter.toLowerCase())) !== -1;
})
return filteredResults;
}
function sort(data, sortBy, sortType) {
var sortIndex = sortType === "asc" ? 1 : -1;
data.sort(function (a, b) {
if (a[sortBy] < b[sortBy]) {
return -1 * sortIndex;
} else if (a[sortBy] > b[sortBy]) {
return 1 * sortIndex;
}
return 0;
})
}
var filteredResults = filter(dataset, filterValue);
sort(dataset, sortBy, sortType); //dataset will be sorted

Resources