Set Tuple of List to ViewData Mvc C# - javascript

I am adding some data in List of Tuple type like this in Razor view
List<Tuple<int, int, string>> Downloadlist = new List<Tuple<int, int, string>>();
And adding items to this list
Downloadlist.Add(new Tuple<int, int, string>(11, 7, "somedata"));
Now I would like to access the array of data in javascript
<script>
var listofdownloadpages = '#ViewData["DownloadPages"]';
if (listofdownloadpages != null) {
alert(listofdownloadpages.length);
for (var i = 0; i < listofdownloadpages.length; i++) {
alert(listofdownloadpages[i].wishid + ' ' + listofdownloadpages[i].remain);
}
}
else {
alert("not found anything");
}
But this not giving me the items in correct way please help.

This will work
Controller
public ActionResult Test()
{
List<Tuple<int, int, string>> Downloadlist = new List<Tuple<int, int, string>>();
Downloadlist.Add(new Tuple<int, int, string>(11, 7, "somedata"));
ViewData["DownloadPages"] = Downloadlist;
return View();
}
View & JS
<script>
var listofdownloadpages = #Html.Raw(Json.Encode(#ViewBag.DownloadPages));
if (listofdownloadpages != null) {
alert(listofdownloadpages.length);
for (var i = 0; i < listofdownloadpages.length; i++) {
alert(listofdownloadpages[i].Item1 + ' ' + listofdownloadpages[i].Item2);
}
}
else {
alert("not found anything");
}
</script>

Related

How to send an object array from c# to javascript?

Im trying to send an array that contains some objects via connection made in SignalR, the connection is not a problem, everything works fine. When the data arrives to the view it is no longer the array i need to use.
This is the class:
public class Empresa
{
public string nombre { get; set; }
public int vidID { get; set; }
public string img64 { get; set; }
public string color { get; set; }
}
At the end the object will be something like this:
The object is send to the view and this is the output:
I have already tried with JsonConvert.SerializeObjectas i found on other threads, yet it doesnt seems to work. I tried to convert the data send with this jQuery.parseJSON(data) (Left) and with this JSON.parse(data)(Right); it throws an error on both cases as seen in the picture below.
I'm not sure if it is that way because the object sended is made this way:
private readonly ConcurrentDictionary<int, Empresa> _ar1 = new ConcurrentDictionary<int, Empresa>();
var data = new List<Empresa>
{
new Empresa{nombre ="Globex Corp",color="red",vidId=1, img="data:image/jpeg;base64,blabla" },
new Empresa{nombre ="AM",color="blue",vidId=2, img="data:image/jpeg;base64,blabla" }
}
for(int i = 0; i<=6; i++)
{
_ar1.TryAdd(data[i].vidID, data[i]);
}
This is inside other function but it is the next one that involves the data send.
public IEnumerable<Empresa> GetArreglo()
{
return _ar1;
}
So far im not sure what could be wrong or if i need to aproach a different solution.
If any more info is needed ill post it. And even it is obvious im a newby still learning on this.
EDIT:
This is all the code involved:
// This is the JS
<script>
var ubi = '#ViewBag.ubicacion';
console.log("UbicaciĆ³n: " + ubi);
var conex = $.connection.channel;
var $marco = $('#marco');
var $imagen = $('#imagen');
var $empresa = $('#empresa');
function empezar() {
var min;
var max;
var pos;
var arreglo = new Array;
function init() {
conex.server.createGroup(ubi);
console.log("Entro al canal");
arreglo = conex.server.getArreglo(ubi);
//pos = arreglo.split('|');
//a.split is not a function
console.log(arreglo);
//console.log(pos);
setInterval(update, 6000);
}
function update() {
}
$.connection.hub.start().done(init);
}
window.onload = function() { empezar(); }
</script>
//It gets the conection to the HUB:
[HubName("channel")]
public class CanalHub : Hub
{
private readonly Canal _canal;
public CanalHub() : this(Canal.Instance) { }
public CanalHub(Canal canal)
{
_canal = canal;
}
public string[] GetArreglo(string ubi)
{
string[] array = _canal.GetArreglo(ubi);
return array;
//it is now a string[] because i wanted to
//try creating the obj with .split('|')
}
// And finally this is the last part involved:
public class Canal
{
private static Random random = new Random();
private volatile List<Canales> listaCan = new List<Canales>();
private readonly static Lazy<Canal> _instance = new Lazy<Canal>(() => new Canal(GlobalHost.ConnectionManager.GetHubContext<CanalHub>().Clients));
private readonly ConcurrentDictionary<int, Empresa> _datos = new ConcurrentDictionary<int, Empresa>();
private readonly ConcurrentDictionary<int, Empresa> _ar1 = new ConcurrentDictionary<int, Empresa>();
private Canal(IHubConnectionContext<dynamic> clients)
{
Clients = clients;
//Create the sample objects for the class
var datos = new List<Empresa>
{
new Empresa{nombre="Globex Corp", color="#A87F3D", vidID=1, img="balbal" },
new Empresa{nombre="AM", color="#535E89", vidID=2, img="balba" },
new Empresa{nombre="Frutijugos", color="#92191A", vidID=3, img="askldj" }
};
for (int i = 0; i <=6 ; i++)
{
_ar1.TryAdd(datos[i].vidID, datos[i]);
}
for (int i = 7; i <= 13; i++)
{
_ar2.TryAdd(datos[i].vidID, datos[i]);
}
for (int i = 14; i <= 20; i++)
{
_ar3.TryAdd(datos[i].vidID, datos[i]);
}
//sort them on 3 different arrays
}
private IHubConnectionContext<dynamic> Clients { get; set; }
public static Canal Instance
{
get { return _instance.Value; }
}
public string[] GetArreglo(string ubi)
{
string[] array = new string[7];
int i = 0;
if (ubi == "Campanario")
{
foreach (var item in _ar1)
{
array[i] += item.Value.nombre + "|";
array[i] += item.Value.color + "|";
array[i] += item.Value.img + "|";
array[i] += item.Value.vidID + "|";
i++;
}
return array;
}
//sort the array values and add them to the array
else return null;
}
It appears that your javascript promise is not set up correctly. The object in the view is the promise object and not the object returned. You are going to need to set up the promise correctly. deferred promise

What is the best and most efficient way to get data by JavaScript from EntityFramework database in my case?

Right now in my ASP.NET MVC Core2 project I have a model in EF database, that contains several properties:
public class SchoolEvents
{
public long ID { get; set; }
[Required]
[StringLength(40, ErrorMessage = "Max 40 characters")]
public string Title { get; set; }
[Required]
public string Description { get; set; }
[Required]
public DateTime WhenHappens { get; set; }
}
I have no problem to get data from the EF database by MVC Razor Views. But I am using JavaScript Calendar plugin in one of my Views, that will mark events from db on it. To do it, the script is taking data in format:
{ title: 'EventTitle', description: 'Few words about the event', datetime: new Date(2018, 8, 14, 16) }
It seems to be obvious, that I supposed to use a for loop in the script, iterating on db objects.
As I am still noob about JS, right now the only way I know to do it is:
-to create JSON file in the controller:
[Route("events")]
[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
public ActionResult Comments()
{
var _events= _context.Events.OrderBy(c => c.ProductID).ToList(); //yes, I know, I should use repository in the best practice
return Json(_events);
}
-in JS file I can use kinf of loadEventsFromServer() function, that uses XMLHttpRequest or Fetch and parsing it (I do not know yet how to do the parsing, I will be happy to get some suggestions),
And that it is it. Do you have some other ideas how to do it?
EDIT:
Update with part of plugins code, for console error d is undefined:
for (var i = 0; i < 42; i++) {
var cDay = $('<div/>');
if (i < dWeekDayOfMonthStart) {
cDay.addClass('c-day-previous-month c-pad-top');
cDay.html(dLastDayOfPreviousMonth++);
} else if (day <= dLastDayOfMonth) {
cDay.addClass('c-day c-pad-top');
if (day == dDay && adMonth == dMonth && adYear == dYear) {
cDay.addClass('c-today');
}
for (var j = 0; j < settings.events.length; j++) {
var d = settings.events[j].datetime;
if (d.getDate() == day && d.getMonth() == dMonth && d.getFullYear() == dYear) {
cDay.addClass('c-event').attr('data-event-day', d.getDate());
cDay.on('mouseover', mouseOverEvent).on('mouseleave', mouseLeaveEvent);
}
}
cDay.html(day++);
} else {
cDay.addClass('c-day-next-month c-pad-top');
cDay.html(dayOfNextMonth++);
}
cBody.append(cDay);
}
I will suggest you to use ajax request.
Javascript : Ajax
$.ajax({
type: 'POST',
url: '#URL.Action("Comments","Controller")',
contentType: 'application/json;charset=utf-8',
dataType: 'json',
data: {},
success: function (data) {
var events = new Object();
events = $.map(data.d, function (item, i) {
for (var j = 0; j < data.d.length; j++) {
var event = new Object();
var startDate = Date.parse(item.WhenHappens )
event.start = startDate;
event.title = item.Title;
event.backgroundColor = "#c6458c";
event.description = item.Description;
return event;
}
})
callCalender(events);
},
error:function(e){
}
});
Controller
[Route("events")]
[HttpPost]
[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
public ActionResult Comments()
{
var _events= _context.Events.OrderBy(c => c.ProductID).ToList(); //yes, I know, I should use repository in the best practice
return Json(_events);
}

create array in javascript with Html.action

I'm trying to create an array of strings in javascript by calling a function in my MVC controller and passing back an array of strings. This pretty simply just isn't working and I'm not sure what i need to do to amend this. below you can see both my javascript and controller code. Any help is greatly appreciated
javascript:
var optionString = #Html.Action("PopulateDashboardDropdown", "Embed", new { Dashboards = Model[0][0].Dashboards });
Controller:
public string[] PopulateDashboardDropdown(ODataResponseListDashboard[] dashboards)
{
string email = "";
//loop that finds the groupID assigned to the currently logged in user
foreach (Claim claim in ClaimsPrincipal.Current.Claims)
{
if (claim.Type == "emails")
{
email = claim.Value;
email = email.ToLower();
}
}
string[] orgs = GetOrgs(email);
string[] retVal = new string[orgs.Length];
bool[] admin = new bool[orgs.Length];
for (int i = 0; i < orgs.Length; i++)
{
admin[i] = isAdmin(orgs[i], email);
retVal[i] = "";
}
//loop that creates a string to emulate the innerHtml of a dropdown selector based on the names of all dashboards in the workspace
for (int i = 0; i < orgs.Length; i++)
{
for (int j = 0; j < dashboards[i].Value.Count; j++)
{
if (dashboards[i].Value.ElementAtOrDefault(j).DisplayName.Contains("Admin"))
{
if (admin[i])
{
retVal[i] += "<option>" + dashboards[i].Value.ElementAtOrDefault(j).DisplayName + "</option>";
}
}
else
{
retVal[i] += "<option>" + dashboards[i].Value.ElementAtOrDefault(j).DisplayName + "</option>";
}
}
}
return retVal;
}
Well, from isn't clear what is the error or what happens exactly but I see a couple of problems. I suggest the following in order to fix the code:
1) Change the result of your controller method to JsonResult:
public JsonResult PopulateDashboardDropdown(ODataResponseListDashboard[] dashboards)
{
...
return this.Json(retVal);
}
2) Get your data via an ajax call (note: you need to insert the proper url in http format. The Http.Action/Razor will not work in javascript):
$.getJSON(myUrl, function (data) {
var optionString = data;
...
});

Passing model data to nvd3 chart in javascript

I'm trying to replace default chart data with real data in the form of a Model element of type string . Can anyone please demonstrate the correct syntax to accomplish this? Many thanks in advance.
The script function for .datum that displays using the default data:
function cumulativeTestData() {
return [
{
key: "Closing Prices",
mean: 60,
values: [[1083297600000, 0.77078283705125], [1085976000000, 1.8356366650335], [1088568000000, 5.3121322073127], [1091246400000, 4.9320975829662], [1093924800000, 3.9835408823225], [1096516800000, 6.8694685316805], [1099195200000, 8.4854877428545], [1101790800000, 15.933627197384], [1104469200000, 15.920980069544], [1107147600000, 12.478685045651]]
},
];
}
Samples of what I've tried:
values: #Model.ClosesJson //didn't work
values: <text> #Model.ClosesJson </text> //didn't work
values: $("#ClosesJson").val() //Model entity as hidden - didn't work
Controller and Model string entity to clone the default data Unix syntax:
public ActionResult Dashboard()
{
ProjectEntities projectDb = new ProjectEntities();
var model = new DashboardViewModel();
model.Closes = new List<ClosesModel>();
var prices = projectDb.uspGetCloses().ToList();
foreach (var result in prices)
{
var close = new ClosesModel
{
Close = result.Close,
CloseCreatedDate = result.CloseCreatedDate
};
model.Closes.Add(close);
}
model.ClosesJson = "[[" + System.Convert.ToString(model.Closes[0]. CloseCreatedDate.Subtract(new DateTime(1970,1,1)).TotalMilliseconds) + ", " +
System.Convert.ToString(model.Closes[0]. Close) + "]";
for (int i = 1; i < model.Closes.Count; i ++)
{
model.ClosesJson = model.ClosesJson + ", [" + System.Convert.ToString(model.Closes[i].CloseCreatedDate.Subtract(new DateTime(1970,1,1)).TotalMilliseconds) +
", " + System.Convert.ToString(model.Closes[i].Close) + "]";
}
model.ClosesJson = model.ClosesJson + "]";
return View(model);
}
You currently just passing a string, not an object that can be represented as JSON.
Because you need to pass an array containing an array of 2 values (representing the charts x and y values, you will need to create an anonymous object
and in your main model, add a property
public object Coordinates { get; set; }
Then in the controller
model.Coordinates = new[]
{
new []{1083297600000, 0.77078283705125F},
new []{1085976000000, 1.8356366650335F}
};
And then in your script
var values = JSON.parse('#Html.Raw(Json.Encode(Model.Coordinates))');
To construct the required array format from your model, you can use
DateTime baseDate = new DateTime(1970, 1, 1);
object[] array = new object[prices.Count];
for(int i = 0; i < prices.Count; i++)
{
array[i] = new[]
{
prices[i].CloseCreatedDate.Subtract(baseDate).TotalMilliseconds,
prices[i].Close
};
}
model.Coordinates = array;

MVC4 Client Site Split Dropdowns Date Validation

I've been trying to get some custom client site date validation working and so far I cannot seem to get it to work properly.
I have a custom date editor defined like this:
#model DateTime?
#{
if (Model.HasValue)
{
int day = Model.Value.Day;
int month = Model.Value.Month;
int year = Model.Value.Year;
}
List<SelectListItem> days = new List<SelectListItem>();
for (int i = 1; i <= 31; i++)
{
days.Add(new SelectListItem { Text = i.ToString(), Value = i.ToString(), Selected = Model.HasValue && Model.Value.Day == i});
}
List<SelectListItem> months = new List<SelectListItem>();
for (int i = 1; i <= 12; i++)
{
months.Add(new SelectListItem { Text = i.ToString(), Value = i.ToString(), Selected = Model.HasValue && Model.Value.Month == i});
}
List<SelectListItem> years = new List<SelectListItem>();
var minYear = DateTime.Now.Year - 100;
var maxYear = DateTime.Now.Year - 18;
for (int i = maxYear; i >= minYear; i--)
{
years.Add(new SelectListItem { Text = i.ToString(), Value = i.ToString(), Selected = Model.HasValue && Model.Value.Year == i });
}
}
#Html.DropDownList("days", days, "Day", new { #class="form__select" } )
#Html.DropDownList("months", months, "Month", new { #class="form__select" } )
#Html.DropDownList("years", years, "Year", new { #class="form__select" } )
And I have a custom validation attribute defined like this:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class DoBValidatorAttribute : ValidationAttribute, IClientValidatable
{
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
List<ModelClientValidationRule> clientRules = new List<ModelClientValidationRule>();
ModelClientValidationRule validDateRule = new ModelClientValidationRule
{
ErrorMessage = "Please enter a valid date.",
ValidationType = "validdate"
};
validDateRule.ValidationParameters.Add("dayelement", metadata.PropertyName + ".days");
validDateRule.ValidationParameters.Add("monthelement", metadata.PropertyName + ".months");
validDateRule.ValidationParameters.Add("yearelement", metadata.PropertyName + ".years");
clientRules.Add(validDateRule);
return clientRules;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
DateTime dateResult;
int day = Convert.ToInt32(validationContext.Items["days"]);
int month = Convert.ToInt32(validationContext.Items["months"]);
int year = Convert.ToInt32(validationContext.Items["years"]);
// Put date parts together and check is valid...
if (DateTime.TryParse(year + "/" + month + "/" + day, out dateResult))
{
return ValidationResult.Success;
}
// Not valid
return new ValidationResult(string.Format(ErrorMessageString, validationContext.DisplayName));
}
}
In order to (try) and wire all this together I also have this in my JavaScript:
jQuery.validator.unobtrusive.adapters.add(
'validdate', // notice this is coming from how you named your validation rule
['dayelement'],
['monthelement'],
['yearelement'],
function (options) {
options.rules['datepartcheck'] = options.params;
options.messages['datepartcheck'] = options.message;
}
);
jQuery.validator.addMethod('datepartcheck', function (value, element, params) {
var year = params[2];
var month = params[1];
var day = params[0];
var birthDate = year + '/' + month-1 + '/' + day;
var isValid = true;
try {
// datepicker is a part of jqueryUI.
// include it and you can take advantage of .parseDate:
$.datepicker.parseDate('yy/mm/dd', birthDate);
}
catch (error) {
isValid = false;
}
return isValid;
}, '');
I've put a breakpoint on all these methods but the GetClientValidationRules method is never called which I think means that the rules are never going to be applied to the HTML for one thing.
What am I doing wrong here? I just cannot figure it out. If I could I would ditch all of it and use a plain datepicker but the client is insistent on this format.
UPDATE
Just to be clear in the generated HTML the controls generated are three <select> inputs.
I'm wondering if it might be better to split this into three separate int properties on my model and use a range validator instead.

Categories