This i code from js. I want to set up the same thing i C#, but don't know how. I have tried using arrays, but the information is supposed to be easy to update without changing the rest of the code.
For example, i can get the summer price from: hotell[0].list[0].price_s.text
Is there a way to do this in C#(visual studio), where you can put information like this in an array?
var hotell = [];
hotell[0] = {
city: "New York",
liste: [
{name: "Aurora", price_s: 590, price_v: 690},
{name: "Downtown", price_s: 660, price_v: 750},
{name: "City Hall", price_s: 450, price_v: 530},
]
};
Create a Model class named as Hotel which is having two properties named as "city" and "liste". "liste" is nothing but a List<HotelDetails> class
public class HotelDetails
{
public string name { get; set; }
public int price_s { get; set; }
public int price_v { get; set; }
}
public class Hotel
{
public string city { get; set; }
public List<HotelDetails> liste { get; set; }
}
Next you need to convert your array to an json object and make an ajax call to your webmethod(if asp.net web form application) or make a call to your controller action (if asp.net MVC application) and pass your json object as a parameter.
After that you can play with your Hotel class
Classes for both Hotel and items within Liste would be the better implementation, like #degant mentioned.
However, you could have a list of tuple<string, int, int>.
var hotel1 = new List<Tuple<string, int, int>>
{
new Tuple<string, int, int>("Aurora", 590, 690),
new Tuple<string, int, int>("Downtown", 660, 750),
new Tuple<string, int, int>("City Hall", 450, 530)
};
You could then store all the Hotels in a dictionary:
var allhotels = new Dictionary<string, List<Tuple<string, int, int>>>
{
{"Hotel1", storage}
};
Or:
var allhotels = new Dictionary<string, List<Tuple<string, int, int>>>();
allhotels.Add("Hotel1", storage);
But as you can see it get complicated rather quickly.
The cleanest would probably be to create a class which represents your data.
class Hotel { string name; int price_s; price_v;}
Then you could either create a dictionary where the key is the citys name and the value is a list of hotels:
Dictionary<string, List<Hotel>> hotels;
Or you could create another class for this:
class HotelsPerCity{ string city; List<Hotel> hotels; }
And just keep the HotelsPerCity in a list:
List<HotelsPerCity> hotels;
Technically speaking you could use anonymous classes for this, doing something like below
var hotell = new []{
new {city = "New York",
liste= new[]{
new{name= "Aurora", price_s = 590, price_v = 690},
new {name= "Downtown", price_s = 660, price_v = 750},
new {name= "City Hall", price_s= 450, price_v= 530},
}
}};
Console.WriteLine(hotell[0].liste[1]);
The problem here is that the var keyword is inferred to a specific class by the compiler. That is, anonymous classes are contructed for a type containing fields string name, int price_s and int price_v, as well an anonymous class for the actual Hotels.
Anonymous classes are meant to be shortlived and the only way you would be able to return you hotell object from a method would be as an object causing you to have to cast it to your anonymous type later on. As it is anonymous this is hard :). You could probably also go with dynamics, but these are slow and afaik reflection base.
IE: You are in a strongly typed language and is better of declaring your classes.
Having Hotel and Suite classes
class Room {
public string name {get;set;}
public int price_s {get;set;}
public int price_v {get;set;}
}
class Hotel {
public string city {get;set;}
public List<Room> liste {get;set;}
}
you could get reasonably simple initialization not unlike (but also not identical to js):
var hotel = new Hotel[]{
new Hotel{city = "New York",
liste= new List<Room>{
new Room{name= "Aurora", price_s = 590, price_v = 690},
new Room{name= "Downtown", price_s = 660, price_v = 750},
new Room{name= "City Hall", price_s= 450, price_v= 530},
}
}};
which could be passed around with the corresponding types. Please note that the properties are usually capitalized i C#.
Related
i have setup a jquery bootgrid on a .net mvc web page, it shows me a grid with a few commands,like sorting,search autocomplete,scroll pages. Library is here: http://www.jquery-bootgrid.com/documentation
The grid works well, and i decided to send the commands through ajax to a function behind. The library then sends a list of strings to the function, used to handle the grid:
current 1
rowCount 10
sort[filename] asc
where filename is one of the columns for which i wanna sort. it could be sort[id], sort[name] or whatever i set my column to be.
the values are pretty clear, the ajax sends to the function the current grid page,the number of rows and the sorting direction.
but when i get in the function i can read only the first 2 values:
public ActionResult AjaxRequestData(string current,string rowCount,string sort)
this definition reads the first 2 values from the web page,but cannot read the sort ,because the actual name of the var is sort[filename], it's not an array of strings.if i either declare sort as string or string[],the result is always null.
How should i declare the variables in the action? So far i could read the sort by using formcollection["sort[filename]"],formcollection["sort[id]"] etc but i have a lot of columns and i really dont want to write out a condition for each one of them,is there any other solution to this?
Approch1.
consider you have table with columns "col1, col2, col3, ...".
you can use:
public ActionResult AjaxRequestData(string current,string rowCount,Sort sort){
//sort.col1 == 'asc' (consider sorted by col1 in ascending order)
}
public class Sort
{
public string col1 { get; set; }
public string col2 { get; set; }
public string col3 { get; set; }
//... other columns
}
Approach 2.
You can remove you parameters and parse data manually. (notice i used post here instead of get)
[HttpPost]
public object AjaxRequestData(){
string jsonContent = Request.Content.ReadAsStringAsync().Result;
Dictionary<string, string> keyvalues = new Dictionary<string, string>();
string[] keyvalue_strings = jsonContent.Split('&');
string sort_column = "";
string sort_direction = "";
for (var i = 0; i< keyvalue_strings.Length; i++)
{
var a = keyvalue_strings[i].Split('=');
a[0] = a[0].Replace("%5B", "[").Replace("%5D", "]");
keyvalues.Add(a[0], (a[1]));
if (a[0].Contains("sort"))
{
sort_column = a[0].Replace("sort[", "").Replace("]", "");
sort_direction = a[1];
}
}
//now you have keyvalues, sort_column, sort_direction.
//...
}
I'm getting an error when I'm trying to use the following code:
filters.Filters = JsonConvert.DeserializeObject<List<SearchFilterItem>>(customFilterString);
The SearchFilterItem is the following class:
public Guid Id { get; set; }
public string ColumnName { get; set; }
public string ColumnDisplayName { get; set; }
public SearchColumnTypes ColumnType { get; set; } //Character, Numeric, Boolean, Date, DateTime.
public SearchOperators Operator { get; set; }
public string Value { get; set; }
public string DisplayValue { get; set; }
public string Logic { get; set; } //And / Or
From JavaScript I'm trying to send the following:
if ($.isNumeric($scope.type)) {
filter = {
columnDisplayName: 'Type Id',
columnName: 'LTypeId',
columnType: parseInt('1'),
value: $scope.type.toString(),
displayValue: $scope.type.toString(),
strOperator: 'Equals', Logic: "AND"
};
So, my problem here is how to properly send the columnType which is C# Enum?
I'm getting this error in run-time:
"Could not cast or convert from System.Int64 to Siriusware.Models.Messages.SearchColumnTypes."} System.Exception {System.ArgumentException
What should I do?
There is a StringEnumConverter attribute in Newtonsoft.Json which has this exact purpose.
You can check the associated documentation here :
https://www.newtonsoft.com/json/help/html/t_newtonsoft_json_converters_stringenumconverter.htm
Here is a blog article giving interesting inputs on the subject, like custom converter for instance :
https://bytefish.de/blog/enums_json_net/
Turned out it was my own stupid mistake. In the filterItem class the column type is another class. In that class we have yet one more ColumnType property which is an enum. So, as soon as I changed my JavaScript to use columnType: {ColumnType: 'Numeric'} it did work by itself - no extra changes were needed. I did ask my colleague to help me as well and we spent about an hour or more chasing this down until it finally dawned on me.
I am using an API that returns an array of data, which I JSON.Parse in order to use the data. I am able to gather the proper data details, however I want to be able to link those details to the object which they are contained in.
I use the following code to gather my array and JSON parse:
var venue = JSON.parse(this.responseText);
console.log(venue);
which returns: Object {4293315: Array[108]}
I then parse through the array contained in '4293315' by running the following code:
for(var person in venue) {
var personDetail = venue[person];
for(detail in personDetail) {
if(personDetail[detail].max_rssi > maxRssi) {
venueDetails.push(personDetail[detail]);
}
}
}
var capacity = venueDetails.length;
capacity --;
console.log("capacity: " + capacity);
var temp = JSON.stringify(venueDetails);
console.log(venue +": " + temp);
which returns:
capacity: 6
[object Object]: [{"mac_id":12960837,"wifi_uid":null,"first_seen":"2016-06-14T00:13:23.000Z","last_seen":"2016-06-14T00:13:23.000Z","max_rssi":-55,"latest_rssi":-55,"frames":1},...
The issue is that the object name is an id number, for example 4293315, so I receive an error when I try to run venue.4293315.name.
Can someone please help me figure out how to store the object name so that I can associate the values contained inside with the object? For example, I want to be able to store the object name in a key and value map, so that I can later ask for the capacity information of each object or ID.
You can programmatically get the value of the name by doing:
var objectNames = Object.keys(venue); // gives an array of the keys
Assuming you know there is only one:
var id = objectNames[0];
Then you can access the properties using id as others have shown.
in my case i use the PropertyName with json Property, maybe help someone
{
"1": "English LL",
"2": "Individuals and Societies",
"3": "Sciences",
"4": "Visual Arts # Music",
"5": "Arabic LL",
"Day": "Su"
}
//Change the number to
[JsonProperty(PropertyName = "1")]
public string Day1{ get; set; }
[JsonProperty(PropertyName = "2")]
public string Day2{ get; set; }
[JsonProperty(PropertyName = "3")]
public string Day3{ get; set; }
[JsonProperty(PropertyName = "4")]
public string Day4{ get; set; }
[JsonProperty(PropertyName = "5")]
public string Day5{ get; set; }
[JsonProperty(PropertyName = "6")]
public string Day6{ get; set; }
You can use venue[4293315].name to access the name of the venue.
If you really want to access the values using the format in the question, you can append a string "id" (or whatever you prefer) to the beginning of each id number. Then you can use venue.id4293315.name.
When accessing numbers in objects, or if you need to get an item in an object based off of a variable, use bracket notation.
object.property is called Dot Notation and can be used, for the most part, if the property does not start with a number.
object[property] is called Bracket Notation and can be used to access a property that does not qualify as a regular variable name.
myObj = {
'hello': 'world',
'17921': 'foo'
}
In this example, you can access myObj.hello as normal, but you MUST use myObj[17921] to access the numbered name, which does not normally count as a valid JS variable name.
In the same right, if you have a variable called numberId that equals 17921, you can get the same number by using myObj[numberId].
I have the following classes defined
public ReportsViewmodel
{
public GeographicData GeographicData { get; set; }
...
}
public class GeographicData
{
public List<ZipcodeData> Regions { get; set; }
...
}
public class ZipcodeData
{
//TupleList is defined as public class TupleList<T1, T2> : List<Tuple<T1, T2>>
public TupleList<double, double> Boundries { get; set; }//Contains list of Lat/Long values for plotting on a map.
}
inside my view, I need to do something like this:
foreach (region in GeographicData.Regions)
foreach (boundry in region.Boundries)
add item1 & item2 to a 2 dimensional Javascript array
In the end, I want my javascript array to look like:
var vmBoundries= [[34.1, -85.4], [34.8, -85.234], [34.347, -85.345], [34.541, -85.434], [34.2341, -85.4]];
I can't figure out how to access the data from my view. I keep running into scope issue. For example, if I try to use a javascript for loop I can't index into my ViewModel lists because the loop variable is undefined when I call #Model.GeographicData.Regions[i]...
So how do I pull the data from my ViewModel into the Javascript array?
Typically you'd:
Transform the data into the format you want
Serialize the transformed data into JSON
Assign a JavaScript variable to the serialized value.
So, something like this:
#{
IEnumerable<double[]> flattened = vm.GeographicData.Regions
.SelectMany(region => region.Boundries
.Select(tpl => new double[] { tpl.Item1, tpl.Item2 }));
string json = new JavaScriptSerializer().Serialize(flattened);
}
<script type="text/javascript">
var arr = #json;
// do something with arr.
</script>
Something like:
var array = (from region in GeographicData.Regions
select from boundry in region.Boundries
select new object[] { boundry.Item1, boundry.Item2 }).ToArray();
This will give you a 2D array that you can then just serialize.
Example: https://dotnetfiddle.net/Y9KOaq
I would use a javascript serializer to make it easier:
using System.Web.Script.Serialization;
And add a helper method to ReportsViewmodel:
public string GetBoundriesJs()
{
var pairs =
from r in GeographicData.Regions
from b in r.Boundries
select new[] { b.Item1, b.Item2 };
return new JavaScriptSerializer().Serialize(pairs);
}
Then you can just call it where you need it in your view:
var vmBoundries = #Model.GetBoundriesJs();
The company recently came upon the need to create a side by side record comparison in Visualforce / Apex. We routinely have the need to merge leads into contacts. Previously this was handled in S-Controls; however, recent initiatives and desire to have support for our code on into the future has pushed us to move many of our S-Controls into Visualforce pages and Apex code.
We are looking to achieve something like this:
I have experimented somewhat (with little luck) doing this using the apex:pageBlockTable tag; however, I am not sure how to get two sets of data to render through when it is expecting a single SObject.
All of the prior code I have to work with was done in S-Controls using JavaScript; and while this code does work now - we need to port this to a VisualForce page. Obviously I can manually write this using HTML tables...etc but I believe that defeats the purpose of using the stock Salesforce functionality.
I'm definitely open to alternative methods - as the one i have outlined works, but requires an almost painful amount of coding to make it viable (especially as fields are updated/removed/added in the future).
The answer ended up being very straight forward!
First - As it turns out, the apex:pageBlockTable can handle pretty much any kind of object passed into the value parameter, be it an array of SObjects or an array of MyFooBar objects.
Second - we needed a wrapper class to encapsulate two records at the same time:
public with sharing class LeadContactCompareWrapper {
public static final String SALUTATION = 'Salutation';
public static final String FIRST_NAME = 'First Name';
public static final String LAST_NAME = 'Last Name';
public static final String EMAIL = 'Email';
public static final String PHONE = 'Phone';
public static final String STREET = 'Street';
public static final String CITY = 'City';
public static final String STATE = 'State';
public static final String COUNTRY = 'Country';
public static final String ZIP_POSTAL = 'Zip / Postal Code';
public static final String TITLE = 'Title';
public static final String PRIMARY_FUNCTIONAL_ROLE = 'Primary Functional Role';
public static final String SECONDARY_FUNCTIONAL_ROLE = 'Secondary Functional Role';
public static final String BULLETIN = 'Bulletin';
public static final String CREDIT_MEMO = 'Credit Memo';
public static final String FS_INSIGHTS = 'FS Insights';
public static final String MANUFAC_IND_INSIGHTS = 'Manufact. Ind Insights';
public static final String LIT_AND_FRAUD = 'Lit. & Fraud News';
public static final String REGULATORY_INSIGHTS = 'Regulatory Insights';
private Lead lead;
private Contact contact;
public List<Compare> information { get; set; }
public List<Compare> marketing { get; set; }
public List<Compare> furtherDetails { get; set; }
public List<SelectOption> names { get;set; }
public String newName { get;set; }
public Id getContactId() {
return this.contact.Id;
}
public Id getAccountId() {
return this.contact.Account.Id;
}
public Id getLeadId() {
return this.lead.Id;
}
public Lead getLead() {
return this.lead;
}
public Contact getContact() {
return this.contact;
}
public LeadContactCompareWrapper(Lead lead, Contact contact) {
this.lead = [Select Id, DeliveryPreference__c, ACE__c,AML__c,BusContinuity__c,CorpGovSOX__c,ERM__c,FinancialRisk__c,InternalAudit__c,ITAsset__c,ITAudit__c,ITSecurity__c,LitSupport__c,ORM__c,SelfAssessment__c,SpendRisk__c, Owner.Name, Company, Bulletin__c,Credit_Memo__c,FSInsights__c,Manufact_Ind_Insights__c,LitFraudNews__c,RegulatoryInsights__c, LastModifiedDate, Salutation, FirstName, LastName, Email, Phone, Street, City, State, Country, PostalCode, Title, Primary_Functional_Role__c, SecondaryFunctionalRole__c From Lead Where Id = :lead.Id];
this.contact = [Select Id, Owner.Name, Account.Id, Account.Name, Bulletin__c,Credit_Memo__c,FSInsights__c,Manufact_Ind_Insights__c,LitFraudNews__c,RegulatoryInsights__c, LastModifiedDate, Salutation, FirstName, LastName, Email, Phone, MailingStreet, MailingCity, MailingState, MailingCountry, MailingPostalCode, Title, Primary_Functional_Role__c, SecondaryFunctionalRole__c From Contact Where Id = :contact.Id];
this.init();
}
private void init() {
this.information = new List<Compare>();
this.marketing = new List<Compare>();
this.furtherDetails = new List<Compare>();
// this part will suck but it has to be done
information.add(this.createCompare(SALUTATION,
(this.lead.Salutation != null) ? this.lead.Salutation : '',
(this.contact.Salutation != null) ? this.contact.Salutation : ''
));
/* Continue adding as many compare fields for the 'information' section as needed... */
// Marking Subscriptions
marketing.add(this.createCompare(BULLETIN,
(this.lead.Bulletin__c != null) ? this.lead.Bulletin__c : '',
(this.contact.Bulletin__c != null) ? this.contact.Bulletin__c : ''
));
/* Continue adding as many compare fields for the 'marketing' section as needed... */
// Further information - just for display purposes
furtherDetails.add(this.createCompare('Owner',
(this.lead.Owner.Name != null) ? this.lead.Owner.Name : '',
(this.contact.Owner.Name != null) ? this.contact.Owner.Name : '',
false,
true
));
/* Continue adding as many compare fields for the 'further information' section as needed... */
}
/*
* Creates a comparison object
*/
private Compare createCompare(string label, String val1, String val2, Boolean isVal1, Boolean isVal2) {
Compare c = new Compare(label);
c.selectVal1 = isVal1;
c.selectVal2 = isVal2;
c.val1 = val1;
c.val2 = val2;
return c;
}
/*
* Defaults our comparison to value 1 as selected
*/
private Compare createCompare(String label, String val1, String val2) {
return createCompare(label, val1, val2, true, false);
}
}
Third - We need to create a 'compare' class that holds two values and two booleans based on which value is selected (and a row label to display on the table):
public class Compare {
public Compare (String label) {
this.label = label;
}
public String label { get; set; }
public Boolean selectVal1 { get; set; }
public Boolean selectVal2 { get; set; }
public String val1 { get; set; }
public String val2 { get; set; }
}
Then it is as simple as putting it all on a VF page with the following:
<apex:pageblocktable value="{!leadToContact.information}" var="compare">
<apex:column>
<apex:facet name="header">Information</apex:facet>
{!compare.label}
</apex:column>
<apex:column>
<apex:facet name="header">Lead</apex:facet>
<apex:inputcheckbox id="val1" label="{!compare.val1}" onclick="uncheckOtherCompare(this);" title="{!compare.val1}" value="{!compare.selectVal1}" />
<apex:outputlabel value="{!compare.val1}" />
</apex:column>
<apex:column>
<apex:facet name="header">Contact</apex:facet>
<apex:inputcheckbox id="val2" label="{!compare.val2}" onclick="uncheckOtherCompare(this);" value="{!compare.selectVal2}" />
<apex:outputlabel value="{!compare.val2}" />
</apex:column>
</apex:pageblocktable>
Finally we just need a little javascript to make the radio buttons behave properly :)
function uncheckOtherCompare(obj) {
// Get the id of the object being checked
var objId = obj.id;
if (objId.indexOf('val1') >= 0) {
objId = objId.replace('val1', 'val2');
} else {
objId = objId.replace('val2', 'val1');
}
if (obj.checked) {
document.getElementById(objId).checked = false;
} else if (!document.getElementById(objId).checked) {
// If the user is trying to uncheck both boxes, recheck the box that is being passed in.
// We can't have 'no' boxes checked on a given row
obj.checked = true;
}
}
The javascript can be placed pretty much anywhere on the page, but it's best to either link it or place it at the top of the document just after the opening tag.
Once this has been done you can (from the code) access your LeadContactCompareWrapper.[information|marking|furtherDetails] array and step through each one to determine the selected values, or write additional helper classes to expedite the process.
With this in place we were able to create a side-by-side record comparison that allowed us to merge our leads directly into our contacts!