JSON data and getting/changing a property in it using a variable - javascript

To begin, I am not sure if this question will make much sense. I will do my best to explain.
I am working on a project looking at U.S. Census bureau information. The part of the object that I am looking at looks like this: (Please note that this is only part of the object.)
Object {MTFCC: "G5020", OID: 207903717468543, GEOID: "13135050431", STATE:
"13", COUNTY: "135"…}
AREALAND: 5416158
AREAWATER: 34463
B19013_001E: "45543"
The part that I am interested in is: B19013_001E which happens to be the code for Median Household Income. In order to get specifically the Median household income I would do:
response.features[1].properties.B19013_001E
Everything works find up to this point. However, my problem is the following: I want to change that code to have other values. So, if the individual wants to look for median_male_age, whose code is B01002_002E I do not want to hard code in B01002_002E as the following:
response.features[1].properties.B01002_002E
The above line would work. But again I want something that can be determined by a variable so that I will not have to hard code in the special code. So, I want a code that is like this: (just an example!)
var value = prompt("What do you want to look at: ")
//In this case value would be the special code like B01002_002E which the user enters.
console.log(response.features[1].properties.value)
Whenever I do this, I get no information back. At first I thought I had the wrong type but I do not believe that is the issue. (I tried converting to a number and back to a string etc.) Any help on this will be great!

Expanding on my comment.
First, MDN has a great doc on Working with objects. It is worth the read.
Second, for your own edification, JSON is a string and not an object hence it's abbreviation of JavaScript Object Notation. What you have is colloquially referred to as a POJO or Plain Old Javascript Object. They are different. :)
Third, for your question in particular, you want to use bracket notation when accessing an object property via a variable. So in this case it would be:
console.log(response.features[1].properties[value])
Hope this helps!

Related

TypeError: Cannot call method "indexOf" of null

I'm triying to find the records that includes "SO -" or "NS - SO" or "SO –" or "SWAT" on THE "RESUMEN" field from a CSV file to asigne a new category (in this cases would be "Call Center"). So, I used "indexOf" funtion witch worked so well.
The problem comes when I change the data source (It is a CSV too), this gave me next error on that step:
"Caused by: org.mozilla.javascript.EcmaError: TypeError: Cannot call method "indexOf" of null (script#2)"
The objective is to assign a category by identifying the words on the source file
My code
if (RESUMEN.indexOf("SO -")!=-1 || RESUMEN.indexOf("NS - SO")!=-1 || RESUMEN.indexOf("SO –" )!=-1 || RESUMEN.indexOf("SWAT")!=-1)
{
var RESULTADO = "Call Center"
}
else RESULTADO = ""
I expect to assigne call center category like I got with the first file (I did not change nothing)
regards!
You're overcomplicating the issue.
Before the answer, remember something, there are several steps, and combinations of steps, that achieve an incredible number of transformations to make usable patterns, the last resort IS User defined Java Expression.
Seems like what you want to achieve is a Value Mapping, thou the difference from a direct value map in your case, is that the row you're testing must contain "SO -", and the other cases, somewhere in the text.
With this simple filter, you can transform your data that contains those informations as you desire, and on the "FALSE" side, treat it for errors.
This will expand your transformation a bit, but when you need to change something it will be easier than with a single step with a lot of code.
As another answer pointed out, you can achieve the same result with different steps, you don't need the javascript step.
But, if you want to go that route, you should first convert null values into, e.g., empty strings.
Simply add this to the beginning of your javascript code:
if (!RESUMEN){ RESUMEN = ''}
That'll convert nulls to empty strings and then indexOf returns correctly.

Array object gets removed from list before splice() statement (JS)

DISCLAIMER: This is part of a lab assignment for school
Update: I want to keep this for reference in the future, so I will just delete the code portion. Thanks to everyone who helped! You were a big help
Assignment (Sum of it): Create a celebrity photo guessing game in HTML/JS using an array of 30 celebrity objects.
Current State: I'm at the part where the users guess gets checked. The users guess is called in function checkUserGuess(). If it matches, then I call displayOutPut("correct") or ("incorrect") as a parameter for the next function, function displayOutput(result). It takes the result parameter and checks it in the switch statement. For the sake of argument, the code I'm concerned about is in the "incorrect" case rather than "correct" since I don't know majority of these celebrities faces. I purposely get it incorrect for testing purposes.
(Celebrity randomly chosen: Charlie Chaplin)
Observation: (Per my screenshot) It seems that the celebrity array already has Charlie removed, although its reading in console that the Array has a size of 30. This is before I splice Charlie out of the array. The washedupCelebs array did receive Charlie. And, the third array shows the celebrity array with Charlie removed and the size changed to 29.
Screenshot: https://i.stack.imgur.com/prtHk.png
Whats being console.log in order:
randomCelebrity object
celebrities array before removing the used celebrity
the index of the current celebrity
washedupCelebs array to store the used celebrities
celebrities array after removing the current celebrity
Questions: Is there a reason that Charlie is removed before the splice takes place? Should I be concerned about this? I feel like its not a big deal, but I would rather get some opinions about it so I can move on. The functionality seems to work properly, but it looks like its bugged in some way.
Notes:
- The off-chance a fellow classmate sees this post, I don't want
them stealing my code. I will delete this post after a few hours as
well for that same reason.
- One more thing, I know my professor is a moderator on here so if you're seeing this, I'd be more than happy to delete it and email you personally about it. Not sure if you'd mind me doing this, seeing I'm not asking anybody to actually do the assignment for me.
Code:
REMOVED FOR POTENTIAL COPYING
TLDR: Don't trust the console.
If you log an object / array, it gets serialized (gets turned into a string) and that serialized version gets printed into the console:
console.log([1, 2]); // [1, 2]
Now for longer arrays / nester objects, a full serialization might result in a very long string being printed and that would take time. Also that long string might not really be helpful (you can't see the tree in the forest). Therefore the console only serializes a small part of the array, e.g.
Array(30) [...]
It just gives you the basic info, just the datatype (Array) the length (30) and the content gets omitted ([...]).
So actually there is no magic, before the splice the arrays length is 30 afterwards it is 29.
Now there is the helpful but confusing >. Because sometimes the abbreviated serialization is not enough for debugging, you need the full version. The thing is, by the time you click the >, the console doesn't know anymore how the object / array looked by the time you logged it.Therefore it serializes the current state of the object / array. Therefore in the unfolded part you see the spliced out version two times, as it was already spliced out by the time you clicked on >.
Now to get the serialized version at that time, either serialize it yourself:
console.log( JSON.stringify(array) );
or clone the array to store its state:
console.log( array.slice() );
Looks like you are just starting with JS.
Well, everything looks fine to me.
The reason is that console.log is using REFERENCE to the array when logging in the console.
The celebrity is not removed from the code before splice.
When you are calling splice the celebrity is removed and all the console.log with the reference of that array shows the latest values.
console.log(celebrities.length) --> 30
.
console.log(celebrities.length) --> 29
celebrities.splice(index, 1);
I'll suggest you to run the code in the debugger to better understand what is happening.

Why and when do we need to flatten JSON objects?

I am surprised that no one on StackOverflow asked this question before.
Looking through the JSON object documentation and a quick google search did not yield satisfactory results.
What's the advantage of it? How does it work?
Edit: To make it clear, take a look at this flatten/un-flatten example.
Fastest way to flatten / un-flatten nested JSON objects
Thank you.
There are many situations where you get JSON text that was automatically built by some library. Throughout the programming languages, there are many libraries that build JSON text (one example is here).
Whenever libraries add some additional object or array wrappings, you might want to get rid of them maybe because you send the JSON to the server and your code there crashes because it expects a primitive value instead of an object (or an array). Or, if your JSON is a server response, you don't want the resulting Javascript code having to differ between object/array or not object/array. In all these cases, flattening is helpful as it will save you time. You will have to implement lesser if/elses, and you can reliably expect your data structure to be as flat as possible.
The other approach to improve code for the scenario mentioned is to write the code in a maximal robust way so there is no way for it to crash by superfluous wrappings ever. So always expect some wrappers and get it's contents. Then, flattening is not needed.
You see, it depends on what is building the JSON and what is parsing it. The building may be out of your scope.
This leads also to data model questions. I've worked with XML code that needed to be parsed quiet a different way if there where 0 entries of some XY, or if there were >0 entries of some XY. Having a wrapper that is allowed to have 0 or more entries of some XY will make live easier. These are data model desicions.
In all cases where the JSON represents an object structure that I've combined manually, I expect it not to change. So flattening something I've designed in detail would be disturbing. Standard operations as far I've seen them do not need flattening (e.g. JSON.stringify(), json_encode() etc.)
Here's a simple scenario: In a web app you have an HTTP POST that is updating a complex relational object.
POST
update=1
&user.id=12345
&user.email=testmail#domain.tld
&user.profile.name=Mr. Test
&user.profile.age=42
&user.profile.friend.0.email=tom#domain.tld
&user.profile.friend.1.email=sally#domain.tld
&user.profile.friend.2.email=bob#domain.tld
&user.profile.skill.0.id=100
&user.profile.skill.0.name=javascript
&user.profile.skill.1.id=200
&user.profile.skill.1.name=piano
Everything is already in a flat structure, so why not have a simple one-to-one binding? If you had a list of constraints or security requirements that you needed to enforce you could validate them by searching directly on the sorted key list.
Flat structures are easier for people to understand and work with there's even some cross-over with database de-normalisation. It also allows for context specific security and constraints to be implemented in a readable, but more verbose way.
When showing a user's view in full you may want to hide the display of the primary key ID for the user's list of skills.
"user.profile.skill.#.id": { hidden: true, readonly: true }
But when looking directly at a skill (to possibly edit it as an administrator) you may want to see the ID.
"skill.id": { readonly: true }
If you were writing a user-centric/self-service type CMS application you'd get more users on board and able to contribute using a straightforward flat model (flat abstraction of the underlying nested relational model) than you would with just the nested model.
TLDR: Flat is easier to read than nested. While programmers can handle nested schemas, recursive parsing and processing; end-users and admins usually prefer that part abstracted away.
I realize this is a 5 year old question at this point, but I figured, I'd add my thoughts to it, in case someone runs into a similar use case and finds this useful.
One of the use cases why you would want to flatten a JSON object, is for dynamic template binding via Regular Expression (RegEx) string interpolation. Well wasn't that a mouthful 👀😅? It simply translates to "template filling a string without hardcoding".
Ok Imagine a scenario, you have a template string like this for an email:
Hello {{firstName}},
It is amazing you chose to join our site. We are happy to have you on board.
To get started, we would really love it if you can confirm your email address
by clicking on the link: {{confirm_url}}.
Welcome aboard
The Team!
Given the following JSON object in memory:
{
"user" : {
"prefix" : "Dr.",
"firstName" : "Awah",
"lastName" : "Teh",
"email" : "awah#superduperubercoolsite.com",
"address" : {
"street": "100 Main St",
"city" : "PleasantVille",
"state" : "NY",
"phone" : "+1-212-555-1212"
}
},
"meta" : {
"confirm_url" : "http://superduperubercoolsite.com/confirm/ABC123"
}
}
it seems super simple to do a Regular Expression replace like so (assuming our email template string was stored in a variable named template and the json object was stored in a variable called templateData:
template = template.replace(new RegExp('{{firstName}}', 'g'), templateData.user.firstName);
template = template.replace(new RegExp('{{confirm_url}}', 'g'), templateData.meta.confirm_url);
Easy right? --> Actually yes! How about this email had 10 templated fields, or you wanted to decouple the template from the code, by storing it in a separate system like SendGrid, where your cool head of marketing can access the template and make changes to the copy-language, without having to call someone from engineering to make changes to the code, test the code and redeploy to production (what a hassle).
This is exactly where flattening of the JSON comes save the day!
Now there are many ways to flatten JSON, I have attached a link to a codepen I wrote that has logic to flatten JSON (actually, I demonstrate two similar but different approaches in the methods flattenJSONIntoKVP and flattenJSONIntoRAW check 'em out!).
That said, there are other implementations out there, and it is worth remembering that the focus on this post is to discuss the WHY JSON flattening could be useful, not the HOW.
Moving on! Assume you flattened the JSON from above (using my implementation that results in key value pairs) to something like this:
[
{ "key": "user.prefix", "value": "Dr."},
{ "key": "user.firstName", "value": "Awah"},
{ "key": "user.lastName", "value": "Teh"},
{ "key": "user.email", "value": "awah#superduperubercoolsite.com"},
{ "key": "user.address.street", "value": "100 Main St"},
{ "key": "user.address.city", "value": "{PleasantVille"},
{ "key": "user.address.state", "value": "NY"},
{ "key": "user.address.phone", "value": "+1-212-555-1212"},
{ "key": "meta.confirm_url", "value": "http://superduperubercoolsite.com/confirm/ABC123"},
]
Now, my friend, you are cooking with GAS!
Why, cause now you can dynamically interpolate the template string with values from the JSON object without giving too much worry to the structure of the JSON (if it changes due to the application evolving, you don't have to also remember to come down here and change this interpolation code -- you simply just have to update the email template itself, which mind you, is on SendGrid [per this example]).
So how to do it you say?: Simple, iteratively. Let's assume that flattened from above was stored in a variable called flatJSON:
///Notice how I use Javascripts native string interpolation to create my RegExp
///Also note that I am replacing the dot (.) in my flattened JSON variable names with a double underscore (__), I only do this because my intended target is SendGrid, and I don't believe it likes dots in its template placeholders.
flatJSON.forEach(kvp=>template = template.replace(new RegExp(`{{${kvp.key.replace(/\./g, '__'}}}`, 'g'), kvp.value));
That's it, one line of code to replace possibly 10 or even hundreds or even thousands (ok.. maybe not thousands, but you get the point).
Ohh! almost forgot, we need to update our template string.
Notice how now, in our new templated string we can use a somewhat FQDN style variable to map back to our original JSON (Ideally if SendGrid supported dots in their template placeholders, this would look super sweet but alas, can't always win everything!😭.
Hello {{user__firstName}},
It is amazing you chose to join our site. We are happy to have you on board.
To get started, we would really love it if you can confirm your email address
by clicking on the link: {{meta__confirm_url}}.
Welcome aboard {{user__prefix}} {{user__lastName}}!
The Team!
Et Voila!
Just like that, we have accomplished some good here today; we have:
Answered the WHY of flattening JSON objects
We dibble-dabbled into the how, with the codepen example
And we even overviewed a use case where taking advantage of JSON flattening can help you write durable dynamic code, that evolves as your underlying object structures change -- and that doesn't require you to leverage the big bad ugly eval method (we can talk about big bad ugly eval on another post).

Better design for data stored using HTML5 localStorage

I have a scenario on my web application and I would like suggestions on how I could better design it.
I have to steps on my application: Collection and Analysis.
When there is a collection happening, the user needs to keep informed that this collection is going on, and the same with the analysis. The system also shows the 10 last collection and analysis performed by the user.
When the user is interacting with the system, the collections and analysis in progress (and, therefore, the last collections/analysis) keep changing very frequently. So, after considering different ways of storing these informations in order to display them properly, as they are so dynamic, I chose to use HTML5's localStorage, and I am doing everything with JavaScript.
Here is how they are stored:
Collection in Progress: (set by a function called addItem that receives ITEMNAME)
Key: c_ITEMNAME_Storage
Value: c_ITEMNAME
Collection Finished or Error: (set by a function called editItem that also receives ITEMNAME and changes the value of the corresponding key)
Key: c_ITEMNAME_Storage
Value: c_Finished_ITEMNAME or c_Error_ITEMNAME
Collection in the 10 last Collections (set by a function called addItemLastCollections that receives ITEMNAME and prepares the key with the current date and time)
Key: ORDERNUMBER_c_ITEMNAME_DATE_TIME
Value: c_ITEMNAME
Note: The order number is from 0 to 9, and when each collection finishes, it receives the number 0. At the same time, the number 9 is deleted when the addItemLastCollections function is called.
For the analysis is pretty much the same, the only thing that changes is that the "c" becomes an "a".
Anyway, I guess you understood the idea, but if anything is unclear, let me know.
What I want is opinions and suggestions of other approaches, as I am considering this inefficient and impractical, even though it is working fine. I want something easily maintained. I think that sticking with localStorage is probably the best, but not this way. I am not very familiar with the use of Design Patterns in JavaScript, although I use some of them very frequently in Java. If anyone can give me a hand with that, it would be good.
EDIT:
It is a bit hard even for me to explain exactly why I feel it is inefficient. I guess the main reason is because for each case (Progress, Finished, Error, Last Collections) I have to call a method and modify the String (adding underline and more information), and for me to access any data (let's say, the name or the date) of each one of them I need to test to see which case is it and then keep using split( _ ). I know this is not very straightforward but I guess that this whole approach could be better designed. As I am working alone on this part of the software, I don't have anyone that I can discuss things with, so I thought here would be a good place to exchange ideas :)
Thanks in advance!
Not exactly sure what you are looking for. Generally I use localStorage just to store stringified versions of objects that fit my application. Rather than setting up all sorts of different keys for each variable within localStore, I just dump stringified versions of my object into one key in localStorage. That way the data is the same structure whether it comes from server as JSON or I pull it from local.
You can quickly save or retrieve deeply nested objects/arrays using JSON.stringify( object) and JSON.parse( 'string from store');
Example:
My App Object as sent from server as JSON( I realize this isn't proper quoted JSON)
var data={ foo: {bar:[1,2,3], baz:[4,5,6,7]},
foo2: {bar:[1,2,3], baz:[4,5,6,7]}
}
saveObjLocal( 'app_analysis', data);
function saveObjLocal( key, obj){
localStorage.set( key, JSON.stringify(obj)
}
function getlocalObj( key){
return JSON.parse( localStorage.get(key) );
}
var analysisObj= =getlocalObj('app_analysis');
alert( analysisObj.foo.bar[2])

A good way to implement a string tokenizer ( or use one that's already established )

Found myself in a situation where I was making one of two rookie mistakes:
Writing code that I should get out of a library
Writing super complex code that could be greatly simplified using better patterning
What I'm trying to do is pretty simple, I need to send instructions to some JavaScript code that prints fields from an object to the page. Things started out fine, the following string:
message, tags, date
Easily instructed the code to get these elements from the object using
field_array = instruction_string.split(',')
obj['message'], obj['tags'], obj['date']
Then I realized that I wanted to modify that date field to reflect the time zone I was in. Enabling the string to carry special instructions for a field added a little complexity with regex, but still wasn't too complicated:
message, tags, date(GMT-5)
Using the code:
var special_instruction = /\(.*\)/ig.exec('date(GMT-5)')[2]
RESULT: special_instruction = 'GMT-5'
I realized that I was getting in over my head when I realized that I also wanted to tell the output to adjust the date so that it reflects the time delta since right now instead of printing the actual date:
message, tags, date(GMT-5_)(SINCE_NOW)
The regex that I wrote didn't work:
var special_instruction = /\((.*)\)/ig.exec('last_updated(GMT-5)(since_now)')
RESULT: special_instruction = 'GMT-5)(since_now'
Although there is probably a way to fix the regex, this indicates that I should be using a tool or established pattern to do this instead of writing custom code off the cusp and screwing around with it for way too long.
Are you sure you want to use strings and regular expressions for this?
An alternative would be to use an array and objects for defining the fields that should be printed.
Something like this:
var fields = [{
name: 'message'
}, {
name: 'tags'
}, {
name: 'date',
timezone: 'GMT-5',
since: new Date() // now
}];
For getting the values from that sure be printed you can iterate over the array and look for the name field. If you found an object with name date you can look for additional properties. You could also add new properties very easily.

Categories