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();
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 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 am using javascript with knockout.js and I have 2 arrays:
self.timesheets = ko.observableArray();
self.selectedTimesheets = ko.observableArray();
I load the timesheet data like so:
$.ajax({
url: '/api/Invoice/GetPendingTimesheets',
type: 'GET',
success: function (timesheetData) {
self.timesheets(timesheetData);
}
});
Where the timesheets are defined like so:
public class Timesheet
{
public int Id { get; set; }
public DateTime WeekStart { get; set; }
}
The selectedTimesheets array keeps track of which checkboxes have been selected
What I would like to do is remove the elements in self.timesheets that are also in self.selectedtimesheets, and I am having a mental block figuring out how to do this:
I know there should be something like
self.timesheets.remove(function (el) {
// ????
});
But I just can't think of how to do it exactly.
Programmatically, you want to iterate through your self.timesheets array and compare each item's id to the ids in self.selectedtimesheets. If the ids match, you want to remove that item from self.timesheets.
Or push all items from both arrays into one new array and remove duplicates.
But since you're using Knockout, if you run the compareArrays utility function:
var differences = ko.utils.compareArrays(self.timesheets, self.selectedtimesheets);
differences will now be an array of only the different values.
Here webdriver should click on each element, but the action is same, can you anyone help me
I am new to JavaScript
public void clickOnAllFiters(){
driver.findElement(By.cssSelector("div.scroll-item.all")).click();
driver.findElement(By.cssSelector("div.scroll-item.news")).click();
driver.findElement(By.cssSelector("div.scroll-item.results")).click();
driver.findElement(By.cssSelector("div.scroll-item.schedules")).click();
driver.findElement(By.cssSelector("div.scroll-item.images")).click();
driver.findElement(By.cssSelector("div.scroll-item.video")).click();
driver.findElement(By.cssSelector("div.scroll-item.comment")).click();
driver.findElement(By.cssSelector("div.scroll-item.activity")).click();
}
clickOnAllFilters("div.scroll-item.activity", "div.scroll-item.activity"); // You can add more, or simply send an array of strings.
public void clickOnAllFilters(String... filters)
{
for(String filter : filters)
{
driver.findElement(By.cssSelector(filter)).click();
}
}
Put the strings into an array and loop through the array.
String[] strings = new String[] {"div.scroll-item.all", ...};
for (String string : strings) {
driver.findElement(By.cssSelector(string)).click();
}
The model:
public class oPage
{
public int PageId { get; set; }
public List<oContent> Contents { get; set; }
}
The oContent object have properties: Id and Text.
The view: (Razor)
#for (int i = 0; i <= Model.Agrees.Count; i++)
{
#Html.TextAreaFor(m => Model.Agrees[i].Text)
}
I want to let to user to add another content from the client.
I found some solutions that I don't like:
Write the html markup manually. I don't like it because maybe in one day the rendering's structure will change and my code will not word.
(Like here: http://www.techiesweb.net/asp-net-mvc3-dynamically-added-form-fields-model-binding/)
Get the structure from the server. I don't like this because.. well I'm always prefer not use the server unless I have to.
(Like here: How to add items to MVC model in javascript?)
I'm looking for a better and smarter solution.
The solution a little beat complex but I think that it cover all my points.
The logic is:
Get the html from the razor engine
#Html.TextAreaFor(m => Model.Agrees[i].Text).ToHtmlString()
Than replace the index number with the attributes name and id (It makes more sense than relying on all attribute value)
public static string CreateHelperTemplate(string PlaceholderPerfix, MvcHtmlString mvcHtmlString)
{
string Result = "";
XElement TempNode = XDocument.Parse(mvcHtmlString.ToHtmlString()).Root;
XAttribute AttrId = TempNode.Attribute("id");
AttrId.Value = AttrId.Value.Replace("0", PlaceholderPerfix);
XAttribute AttrName = TempNode.Attribute("name");
AttrName.Value = AttrName.Value.Replace("0", PlaceholderPerfix);
// Clear the content if exist
TempNode.SetValue(string.Empty);
Result = TempNode.ToString();
return Result;
}
The result it something like this:
<textarea class="form-control" cols="20" id="Perfix_$__Text" name="Agrees[$].Text" rows="2"></textarea>
Then, in javascript, when the user click on "Add item" button you can get the "template" and the index and replace the '$' with the index.
So, I not need to call the server and if the structure of the helper will change my code will still work.
It's working.