Get a JSON Key based off of a user select - javascript

I am currently creating a tool that allows users to put in their state and category to see what the 3 price plans are. These 2 selections (state/category) will be picked via select field, and the data containing these numbers is in a JSON file:
[{
"Alabama/Category1/Price1":"$123,123 ",
"Alabama/Category1/Price2":"$123,123 ",
"Alabama/Category1/Price3":"$123,123 ",
"Alabama/Category2/Price1":"$345,345 ",
"Alabama/Category2/Price2":"$345,345 ",
"Alabama/Category2/Price3":"$345,345 ",
"Alabama/Category3/Price1":"$456,789 ",
"Alabama/Category3/Price2":"$456,789 ",
"Alabama/Category3/Price3":"$456,789 ",
"Alabama/Category4/Price1":"$321,321 ",
"Alabama/Category4/Price2":"$321,321 ",
"Alabama/Category4/Price3":"$321,321 ",
"Alaska/Category1/Price1":"$123,123 ",
"Alaska/Category1/Price2":"$123,123 ",
"Alaska/Category1/Price3":"$123,123 ",
"Alaska/Category2/Price1":"$345,345 ",
"Alaska/Category2/Price2":"$345,345 ",
"Alaska/Category2/Price3":"$345,345 ",
"Alaska/Category3/Price1":"$456,789 ",
"Alaska/Category3/Price2":"$456,789 ",
"Alaska/Category3/Price3":"$456,789 ",
"Alaska/Category4/Price1":"$321,321 ",
"Alaska/Category4/Price2":"$321,321 ",
"Alaska/Category4/Price3":"$321,321 ",
}]
Basically on button click, I would like to loop through the JSON file and get the State/Category based off the users selections. Being that there are some "/"'s in that key path, I tried stashing the users selection in a variable, so that I could target each price point and display them on the page. My way of trying that was stashing it in a variable like so:
var test = stateSelected + '/' + categorySelected + '/Price1';
This, however does not work, and was wondering if there was any additional insight as to how to achieve this? Reading some other material, it seems some are recommending to use $.parseJSON, but that was not working either. For that I used:
$.getJSON("json_data.json", function(obj) {
$.each($.parseJSON(data), function(key, value) {
//code here
});
});
Sorry for the longevity on this, but too many times on this site I have seen people not give enough information for people to be able to understand the real issue, and I hope I have outlined mine correctly. Any help on this would be appreciated. Thanks!
EDIT: Also, if you think there is a different way to present the JSON data other than the way I have it here, let me know. The data will be updated via spreadsheet and I used an Excel -> JSON translator tool and this was the way it spit back out the data.

I'd format the JSON in the following way:
var options = {
Alabama: {
Category1: {
Price1: "$123, 123",
Price2: "$123, 123",
}
}
}
and then:
var priceOptions = options[stateSelected][categorySelected];

If you cannot alter the JSON then you'll have to iterate through each key in the object:
function getPricePoints(state, category, onComplete)
{
$.getJSON("json_data.json", function(obj)
{
var result = {};
for(key in obj)
{
if(obj.hasOwnProperty(key) && key.indexOf(state + "/" + category + "/") == 0)
{
result[key] = obj[key];
}
}
onComplete(result);
});
}

If you can alter the way the JSON is represented then why not store the data like so:
var options = {
"Alabama/Category1" : {
"Price1":"$123,123 ",
"Price2":"$123,123 ",
"Price3":"$123,123 "
},
"Alabama/Category2" : {
"/Price1":"$345,345 ",
"Price2":"$345,345 ",
"Price3":"$345,345 "
}
...
}
Then you get slash the user's inputs and get all the prices options for that combination of state and category?
test = stateSelected + '/' + categorySelected;
var priceOptions = options[test];

Related

Deleting URL parameters using URLSearchParams

I'm utilizing the URLSearchParams API to delete keys/values from the query string in my URL.
I have the following snippet:
params = new URLSearchParams('a=x&b=y&c=z');
params.forEach(function(value, key){
console.log("Deleted: ", key, value, params.toString());
params.delete(key);
});
console.log("Left with: ", params.toString());
Invariably, the Left with: returns part of the query parameters.
Output on this JSFiddle:
☁️ "Running fiddle"
"Deleted: ", "a", "x", "a=x&b=y&c=z"
"Deleted: ", "c", "z", "b=y&c=z"
"Left with", "b=y"
My understanding of forEach() is that it'll loop over all the key/value pairs, but based on this fiddle, it looks like it exits the loop on the penultimate pair.
Edit, based on feedback in the comments below:
I'm trying to selectively retain one or two parameters (based on a list provided).
params = new URLSearchParams('a=x&b=y&c=z&d=1');
params.forEach(function(value, key){
retainList = ['d'];
if (retainList.includes(key)){
console.log("Retaining ", key);
} else {
console.log("Deleted: ", key, value, params.toString());
params.delete(key);
}
});
console.log("Left with: ", params.toString());
Seems to be some odd reference issue happening with URLSearchParams. Even when you use the .keys() method to get a list of keys it seems like it's giving a reference to it's internal list of keys.
You can work around this issue by cloning the list of keys using spread
params = new URLSearchParams('a=x&b=y&c=z');
keys = [...params.keys()]
for (key of keys) {
console.log("Deleting: ", key, params.get(key), params.toString());
params.delete(key)
};
console.log("Left with: ", params.toString());
To achieve the desired result you could do:
params = new URLSearchParams('a=x&b=y&c=z&d=1');
retainList = ['d']
for (key of [...params.keys()]) {
if (! retainList.includes(key)) {
console.log("Deleting: ", key, params.get(key), params.toString());
params.delete(key)
}
};
console.log("Left with: ", params.toString());

Twitter typeahead.js and a json object for multiple matches

I'm writing a program that should be able to find a university course based on a few of the courses parameters. I have a huge json object containing 1360 objects, and each object has around 20-30 parameters. I am only interested in about 3-5 of them however.
What I want to do is to be able to find a course based on it's number, the name, the name of the teacher or a set of keywords that each course has in it's description.
Anyway. I have tried messing around with twitters typeahead.js and as far as I can understand you need to parse it an array of strings, and it only takes 1 array as far as it seems. Isn't there an easy way (or another javascript module) that I can do this?
My current object is:
var courses = [
{ "number": "<5 digits>",
"name": "<course name>",
"teacher": "<teacher name>",
"keywords": "<string of keywords>" }
{ ... }
{ ... }
{ ... }
and so forth..
];
And it is as mentioned 1360 objects of size.
I want to get an output similar to this:
However I want to be able to search on the parameters mentioned (number, name, teacher name, keywords) and get the best possible match for whatever was input into the text field.
Does anyone have an idea of how to achieve this?
This is very easy, but not with typeahead.js. It has 231 open issues (at the time typing, some very serious) and has not been updated in a year.
Use bootstrap3-typeahead instead. It is maintained and uptodate. Take a look at the docs before reading further. You are not providing a JSON so I am using another JSON in the example below.
All you have to do is to define a matcher method, here a very simple not case sensitive that compares with all attributes in a JSON item :
matcher: function(item) {
for (var attr in item) {
if (~item[attr].toString().toLowerCase().indexOf(this.query.toLowerCase())) return true
}
return false
}
You can override which attrs / text that should be shown in the dropdown using displayText (pure example) :
displayText: function(item) {
return item.id + ' ' + item.label + ' ' + item.value
}
If you want to override the rendering of the items completely, as complex HTML, use a combination of displayText and highlighter where each display string contain the stringified JSON :
displayText: function(item) {
return JSON.stringify(item)
},
highlighter: function(item) {
item = JSON.parse(item)
return '<span><h4>'+item.value + '</h4>' + item.id + ' ' + item.label +'</span>'
}
When the display string is stringified, the <input> must be updated with the value attribute(s) that should be the selected value :
afterSelect: function(item) {
this.$element[0].value = item.value
}
Complete example :
$('#example').typeahead( {
source: json,
matcher: function(item) {
for (var attr in item) {
if (~item[attr].toString().toLowerCase().indexOf(this.query.toLowerCase())) return true
}
return false
},
displayText: function(item) {
return JSON.stringify(item)
},
highlighter: function(item) {
item = JSON.parse(item)
return '<span><h4>'+item.value + '</h4>' + item.id + ' ' + item.label +'</span>'
},
afterSelect: function(item) {
this.$element[0].value = item.value
}
})
demo -> http://jsfiddle.net/vhme3td1/

Reusing range object in Excel.run for apps for office

I am new to APPS for OFFICE
I am trying a simple code in which I Validate Excel Data.
So Rather than nesting things in ctx.sync() again and again, I am writing code like this:-
// **json** object used beneath is somewhat like:
{"Field":[
{"FieldName":"Field1", "FieldDesc":"Field 1 desc", "MappedTo":"B2", "IsMandatory":"true", "LOV":"1,2,3"}]}
// **LOV** in above json data means:- the field data can only be among the values given.
//********** MY PIECE OF CODE**************
var fieldData = "";
$.each(json, function (index, field) {
range = ctx.workbook.worksheets.getActiveWorksheet().getRange(field.MappedTo + ":" + field.MappedTo);
range.load('text');
ctx.sync();
fieldData = range.text;
if(field.IsMandatory == true && (fieldData == "" || fieldData == null))
{
headerValidation = headerValidation + "Data is required for Field : " + field.FieldDesc + "\n";
}
else if(field.LOV != "" )
{
if($.inArray(fieldData, field.LOV.split(',')) == -1)
{
headerValidation = headerValidation + "Data not among LOV for Field : " + field.FieldDesc + "\n";
}
}
range = null;
});
As can be seen, I need to read range object again and again. So I am using range object everytime with different address and calling first "load()" and then "ctx.sync()".
If i debug slowly , things do work fine but on running application i get frequent error now and then:-
The property 'text' is not available. Before reading the property's
value, call the load method on the containing object and call
"context.sync()" on the associated request context.
Please guide me how I can handle this?
Also , is my approach correct?
In terms of what's wrong, the error is next to your ctx.sync() statement.
You need it to be
ctx.sync()
.then(function() {
fieldData = range.text;
...
});
And I wouldn't forget the .catch(function(error) { ... }) at the end, either.
As far as reusing the variable or not, it really doesn't matter. By doing "range = ctx.workbook...." you're actually creating a global range variable, which is considered bad practice. Better to do "var range = ctx.workbook....". And you don't need to worry about setting it to null at the end.
One thing to note is that since you're doing this in a for-each loop, note that the number of concurrent .sync()s that can be happening is limited (somewhere around 50-60, I believe). So you may need to adjust your algorithm if you're going to have a large number of fields.
Finally, you can make this code much more efficient by simulataniously ceating all of your range objects, loading them all at once, and then doing a single ".sync".
var ranges = [];
$.each(json, function (index, field) {
var range = ctx.workbook.worksheets.getActiveWorksheet().getRange(field.MappedTo + ":" + field.MappedTo);
range.load('text');
ranges.push(range);
});
ctx.sync()
.then(function() {
// iterate through the read ranges and do something
})
Hope this helps,
~ Michael Zlatkovsky, developer on Office Extensibility team, MSFT

Iterating over JSON object

I'm having some troubles iterating in a json object.
I'm currently saving the table properties of a some web page in a cookie.
The value of the cookie is an array of objects which I serialize.
The typical value of an array with 2 entries is something like:
cookieValue=["{ "PageID": "1391", "PageSize": "100"}", "{ "PageID": "2341", "PageSize": "50"}"]
My problem is iterating in this array now. I want to be able to check if there is any duplicate entry to update its PageSize (if applicable) or to read it in order to set the page size when a user goes back to the same page.
I've tried this so far:
for (var key in cookieValue) {
if(cookieValue.hasOwnProperty(key) ){
console.log(key + " -> " + cookieValue[key]);
}
}
which give me an output like:
0 -> { "PageID": "1391_tabela", "PageSize": "100"}
1 -> { "PageID": "1391_tabela", "PageSize": "50"}
2 -> { "PageID": "1391_tabela", "PageSize": "10"}
My question is how am i able to access the value of PageID in each entry.
Thanks in advance
I am not sure if I understand you correctly but I think you should just use
cookieValue[key]["PageID"]
together:
for (var key in cookieValue) {
if(cookieValue.hasOwnProperty(key) ){
console.log(key + " -> " + cookieValue[key] + " -> " + cookieValue[key]["PageID"]);
}
}
It seems that you need to get the object by the PageId. Here is a function
function getPageById(pageId) {
for (var pageObj in cookieValue) {
if (pageObj.PageId === pageId)
return pageObj;
}
}
If you only want to access the value of PageId in each entry, you can view example here :
var cookieValue=[{ "PageID": "1391", "PageSize": "100"}, { "PageID": "2341", "PageSize": "50"}];
for (key in cookieValue) {
alert(cookieValue[key]["PageID"]);
}
JSFIDDLE
Manipulate the data using a javascript array for easier code.
One way that should work for you:
convert your JSON into a javascript array using:
var mycookieArray = JSON.parse(cookieValue);
Iterate through it with:
for(String s : myCookieArray)
{
console.log(s.PageID);
}

Get object in array with underscore.js

I have a function with a rather convoluted object in this format:
function getNBATeamsESPNByAbbrev(abbrev)
{
var json = {
"sports":[
{
"name":"basketball",
"id":40,
"uid":"s:40",
"leagues":[
{
"name":"National Basketball Assoc.",
"abbreviation":"nba",
"id":46,
"uid":"s:40~l:46",
"groupId":7,
"shortName":"NBA",
"teams":[
{
"id":1,
"uid":"s:40~l:46~t:1",
"location":"Atlanta",
"name":"Hawks",
"abbreviation":"ATL",
},
{
"id":2,
"uid":"s:40~l:46~t:2",
"location":"Boston",
"name":"Celtics",
"abbreviation":"BOS",
"color":"006532",
},
]
}
]
}
],
"resultsOffset":0,
"resultsLimit":50,
"resultsCount":30,
"timestamp":"2014-03-22T23:42:43Z",
"status":"success"
}
obj = _.find(json.sports[0].leagues[0].teams, function(obj) { return obj.abbreviation == abbrev })
if (obj !== undefined)
{
var team = new Object();
team.abbrev = abbrev;
team.location = obj.location;
team.nickname = obj.name;
return team;
}
}
It can be easier seen at this example JSFiddle. So I have the team abbreviation, and I want to pull back the team object as a whole (this is a stripped down version, leaving only the necessary details). This seems to work fine. However, another case has arisen, one in which I need to pull back the team object based on its location + " " + name. So I tried to do the same thing using underscore.js, passing in the parameter name, and changing the predicate in ._find to return obj.location + " " + obj.name == name. For example, I'd pass in Atalnta Hawks as name and expect to return the relevant team object. Here's a very similar JSFiddle demonstrating the change. But, now it can't seem to find the team object I want to pull. Is it because such a string concatenation isn't allowed in underscore.js, or is there something stupid I'm missing?
Line 50, you have:
team.abbrev = obj.abbrev;
and it should be
team.abbrev = obj.abbreviation;

Categories