JSON attribute unreachable - "Cannot read property of undefined" - javascript

I am attempting to use the Wikipedia API to retrieve article titles and snippets of the article's text. But when I try to access those properties, I am getting the error "Cannot read property of undefined."
Here is my JSON response:
{
"batchcomplete": "",
"continue": {
"gsroffset": 10,
"continue": "gsroffset||"
},
"query": {
"pages": {
"13834": {
"pageid": 13834,
"ns": 0,
"title": "\"Hello, World!\" program",
"index": 6,
"extract": "<p>A <b>\"Hello, World!\" program</b> is a computer program that outputs or displays \"Hello, World!\" to a user. Being a very simple program in most programming languages, it is often used to illustrate the</p>..."
},
"6710844": {
"pageid": 6710844,
"ns": 0,
"title": "Hello",
"index": 1,
"extract": "<p><i><b>Hello</b></i> is a salutation or greeting in the English language. It is first attested in writing from 1826.</p>..."
},
"1122016": {
"pageid": 1122016,
"ns": 0,
"title": "Hello! (magazine)",
"index": 7,
"extract": "<p><i><b>Hello</b></i> (stylised as <i><b>HELLO!</b></i>) is a weekly magazine specialising in celebrity news and human-interest stories, published in the United Kingdom since 1988. It is the United Kingdom</p>..."
}
}
}
}
I have tried a couple different ways of writing the code. For example, this works (logs the pages as an object in the console):
console.log(response.query.pages);
But this returns the error I wrote above ("Cannot read property of undefined"):
console.log(response.query.pages[0].title);
Any suggestions on how to access the attributes "title" and "extract" would be appreciated. Thanks.

That's because pages is not an array; it's an object where the keys are the ids. So you need to do:
console.log(response.query.pages[1122016].title);
This will work. If you want the "first" page, for instance, then
let pages = response.query.pages;
console.log(pages[Object.keys(pages)[0]].title);
Note that I'm not sure if the order of the keys in JS objects is guaranteed.
If you want to iterate over the pages, do
let pages = response.query.pages;
Object.keys(pages).forEach(id => {
let page = pages[id];
console.log(page.title, page.foo);
});

Special Case: Working with Asynchronous Calls
Howdy fellow devs,
If you're checking out this thread because you're working with a framework like React, or some other framework that has you using a development server (e.g. using npm start or something similar), your dev server may be crashing when you try to do something like console.log(response.foo.bar) before it refreshes on data reload.
Specifically, my dev server was crashing with the Cannot read property 'bar' of undefined type message, and I was like, "what the heck is going on here!?". Solution: put that baby in a try/catch block:
try {
console.log(rate['bar'].rate)
} catch (error) {
console.log(error)
}
Why? If your App has a default state (even an empty array, for example), then it tries to console.log the response before the data has been received from the remote source, it will successfully log your empty state, but if you try to reference parts of the object you're expecting to receive from the remote source in your console.log or whatever else, the dev server will be trying to reference something not there on initial load and crash before it has a chance to reference it when it's actually received from the remote source via API or whatever.
Hope this helps someone!

I'm not sure which language you're using to parse the JSON (looks like Javascript from console.log?) but the issue is that query.pages is a dictionary, not an array, so it can't be iterated by index, only by key.
So you want something like (pseudocode):
for (key in response.query.keys)
{
console.log(response.query[key].title);
}

Related

Google Fit get heart rate data

I would like to get my heart rate data stored on Google Fit. Through this page I can try the API: https://developers.google.com/fit/rest/v1/reference/users/dataSources/datasets/get?apix=true
and work because the json result is:
{
"minStartTimeNs": "1607036400000000000",
"maxEndTimeNs": "1607122800000000000",
"dataSourceId": "raw:com.google.heart_rate.bpm:AA:62:2a5297f4:Notify for Amazfit - heart rate",
"point": [
{
"startTimeNanos": "1607036509703000000",
"endTimeNanos": "1607036509703000000",
"dataTypeName": "com.google.heart_rate.bpm",
"value": [
{
"fpVal": 46,
"mapVal": []
}
],
"modifiedTimeMillis": "1607076710847"
},
...
...
...
If I click on the javascript tab it generates the code that must only be modified with API_KEY and CLIENT_ID but if I run it the result is:
minStartTimeNs "1607036400000000000"
maxEndTimeNs "1607122800000000000"
dataSourceId "raw:com.google.heart_rate.bpm:com.mc.amazfit1:Amazfit:Amazfit Bip Watch:97f19a4a:Notify for Amazfit - heart rate"
point []
The "point" array is empty. Without any errors, it doesn't tell me, that I don't have access, or the scope is wrong, it's just empty. Even looking with the firefox debugger the ajax calls are identical, only the access token changes. how can I do? thanks.
I see you are using the device's datasource directly (Amazfit Bip watch), not the derived Google Fit datasource. When I tried accessing the device's datasources, I also saw no data returned. After much trial and error, I had better luck fetching it from the derived sources, examples below.
DATA_SOURCE = {
"steps": "derived:com.google.step_count.delta:com.google.android.gms:merge_step_deltas",
"dist": "derived:com.google.distance.delta:com.google.android.gms:from_steps<-merge_step_deltas",
"bpm": "derived:com.google.heart_rate.bpm:com.google.android.gms:merge_heart_rate_bpm",
"rhr": "derived:com.google.heart_rate.bpm:com.google.android.gms:resting_heart_rate<-merge_heart_rate_bpm",
"sleep" : "derived:com.google.sleep.segment:com.google.android.gms:sleep_from_activity<-raw:com.google.activity.segment:com.heytap.wearable.health:stream_sleep",
"cal" : "derived:com.google.calories.expended:com.google.android.gms:from_activities",
"move": "derived:com.google.active_minutes:com.google.android.gms:from_steps<-estimated_steps",
"points" : "derived:com.google.heart_minutes:com.google.android.gms:merge_heart_minutes",
"weight" : "derived:com.google.weight:com.google.android.gms:merge_weight"
}
Obviously, the only other time I have seen this happen (point []) is when there is no data for that timeframe, i.e. the datasetId (start-end). It is common with 'Heart Points' and 'Active Minutes'. But I wouldn't think that would be the case for heart rate data (unless you weren't wearing the watch).

chrome.storage.managed doesn't seem to work in my kiosk app

I've written a fairly simple kiosk app for a enterprise-enrolled/managed chromebox. I want to provide a default URL through a policy with chrome.storage.managed.
According to the documentation available a schema could look something like this:
{
"type": "object",
"properties": {
"DefaultUrl": {
"title": "Default URL",
"description": "The Default URL that will be loaded",
"type": "string"
}
}
}
And then the configuration text file you upload on the admin.google page would look like this (but this is kind of a guess):
{
"DefaultUrl": {
"Value": "http://example.com"
}
}
Next I try to use this URL using the following code:
chrome.storage.managed.get('DefaultUrl', function (data) {
var url = data.DefaultUrl;
/*if(url == undefined)
url = "undefined url";*/
//further code to proces the url
});
As far as I understand from the documentation a dict object with key/value pairs is returned containing the specified keys (1 in my case). When I uncomment the ifstatement in the above code the variable url always ends up being "undefined url", and otherwise it doesn't show any text (since it seems to be undefined)..
Debugging this isn't easy, because as far as I know you can't use console.log in kiosk mode, the policies can't be set through the admin panel when running it locally and since it's a managed device I can't run it from dev mode..
Can anyone tell me what's wrong here? If this is insufficient info I'd be glad to supply more, but my guess is the error is somewhere in the code above.
Update
I got this working locally when adding policies for chrome in my windows register, as described by the 'windows' part on: this site..
Allthough I am now using more than 1 policy, so maybe the error was that the schema expects atleast 2 policies? I have yet to test this on the kiosk app.

"Assertion Failed: The response from a findAll must be an Array, not undefined"

I am trying to make Emberjs work with the fortunejs backend. So far I made a very simple page in Ember that should show all the 'customer' entities, which works fine with the LSadapter.
When my app loads the overview page, its does a GET request to http://localhost:1337/customers and fortune responds with:
{
"customers": [
{
"id": "YIR17juOFkaWBFhl",
"name": "PIm",
"phone": 132,
"fax": 123,
"chamberOfCommerceNumber": 123,
"website": "123.nl"
},
{
"id": "gUGIoHvwI8mwVTgE",
"name": "Marco",
"phone": 123,
"fax": 123,
"chamberOfCommerceNumber": 123,
"website": "it.nl"
}]}
However, ember does not seem to like it and gives me:
"Assertion Failed: The response from a findAll must be an Array, not
undefined"
I thought that this is the right json format ember expects from a get request to get all customers, what is going wrong?
FYI, I made a create page that works fine with fortunejs. For that I had to modify the RESTSerializer like so:
App.ApplicationSerializer = DS.RESTSerializer.extend({
serialize: (record, options) ->
[this._super record, options] #Turn into array
serializeIntoHash: (hash, type, record, options) ->
console.log type.typeKey
type.typeKey = Ember.Inflector.inflector.pluralize type.typeKey #pluralize root key
console.log type.typeKey
console.log record
result = this._super hash, type, record, options
});
But this should have nothing to do with the incoming JSON form the api.
Any ideas what goes wrong?
I know this is old, and I'm not sure Stack Overflow's policy on that but I was trolling through unanswered questions to see if I knew any off the top of my head...
I think the problem here is that findAll (which doesn't exist in the current version of Ember Data) is a method that only does a store lookup. The equivalent of store.all in the current version (http://emberjs.com/api/data/classes/DS.Store.html#method_all).
You would want store.find, which makes a backend server request for the data (http://emberjs.com/api/data/classes/DS.Store.html#method_find).
Hope this helps anyone who stumbles across this problem...

Formatting JSON using the RESTSerializer in the latest Ember Data version

I'm struggling to 'munge' my JSON into the correct format.
To illustrate i've made a quick, JSfiddle.
http://jsfiddle.net/chrismasters/NQKvy/638/
The format the server returns the data has a couple of differences to the preferred format recommended by Ember Data now.
Here is the raw JSON output
{
"video": {
"uuid": "8a660002-03c6-4b8e-bd8b-4ce28fa0dacd",
"state": "pending",
"theme": "basic",
"resolution": "nHD",
"title": "Test title",
"track": {
"uuid": "376fc3bb-d703-49e7-9d92-bce7f6bf8b56",
"state": "complete",
"source": "upload"
}
}
}
The first is that rather than use IDs it uses a UUID that is a string.
I seem to have managed to fix that using the normalizeHash, for video at least - but i'm not sure whether the same approach will fix the track model too - especially if I use embedding as I need to.
This is where the big problems start to appear, if I comment out the belongsTo relationship from the video model then it works OK, so I think... it is clearly a problem with the JSON formatting for the embedded track data.
Here are the model definitions and the serialization
App.Video = DS.Model.extend({
title: DS.attr('string'),
//track: DS.belongsTo('track', { embedded: true })
});
App.VideoSerializer = DS.RESTSerializer.extend({
normalizeHash: {
video: function(hash) {
hash.id = hash.uuid;
delete hash.uuid;
return hash;
}
}
});
I'd really appreciate some advice on how to format this response into a format that Ember Data recognises.
Also - does anyone know of a tool or good way of debugging these serialization transformations because at the moment the error message from Ember is not very helpful in terms of debugging or seeing what the serialization output is.
Many thanks for any help you can suggest.
Chris
In case anyone else has the same confusion over serializations I thought i'd include an explanation how to solve this problem.
Here is the working jsbin:
http://jsbin.com/fuzu/4
The main points are:
Primary Keys
primaryKey: 'uuid'
Is useful to convert the id into the correct naming & needs to be applied explicitly to any serializers (using globally on a ApplicationSerializer didn't seem to work).
Model Relationships
track: DS.belongsTo('track', {embedded: true} )
Ensure the definition of the relationship includes embedding & only on one side.
Extract Single
extractSingle: function(store, type, payload, id, requestType) {
var tracks = [];
var track = payload.video.track;
var video = payload.video;
tracks.push(track);
video.track = payload.video.track.uuid;
payload = { video: video, track: tracks };
return this._super(store, type, payload, id, requestType);
}
Pluralization is really important for Ember Data to understand the relationships, even though the model relationship is a belongsTo.
You can see this clearly in the desired (working) JSON
{
"video": {
"id": "8a660002-03c6-4b8e-bd8b-4ce28fa0dacd",
"state": "pending",
"theme": "basic",
"resolution": "nHD",
"title": "Test title",
"track": "2"
},
"track": [{
"id": "2",
"state": "complete",
"source": "upload"
}]
}
The track value in video isn't wrapped in an array, yet the root track value is an array.
For this reason I found it very useful first define the desired JSON and test it working first, then try to munge the real JSON into that format.
I think a tool to help with this process (visualising real-time JSON output from seraliziation) could be a great addition to Ember Data & something I'm going to look into creating.

Facebook Like Button - Is It Checked?

I'm having trouble finding good documentation about how to use javascript in order to find out if a like button is clicked or not. I can't use an on-click event because the button might already be checked when a user comes onto my page but that seems to be all I can find regarding tracking likes externally (not counting other methods that are no longer supported). Anyone have any experience with such issues? Thanks.
It depends on the Like button. If it's for a Facebook object that has an ID, you can query the like table (but you'll need user_likes permission)
If it's for a URL, it's not really possible: facebook graph api determine if user likes url [stackoverflow]
It it's for a built-in like you could use a cookie to remember the click, or save the click in your own database.
Just to expand on Gil's answer. For built-in likes you can use a batch request consisting of two request:
1) Try to like the object in question
2) If there was no error, delete the like connection
Example batch:
[{"method":"POST", "relative_url":"me/og.likes", "body":"object=<SOME_URL>", "name":"like-attempt", "omit_response_on_success": false},
{"method":"DELETE", "relative_url":"{result=like-attempt:$.id}"}]
If an object was already liked, batch response would be:
[
{
"code": 400,
"headers": [
...
{
"name": "WWW-Authenticate",
"value": "OAuth \"Facebook Platform\" \"invalid_request\" \"(#3501) User is already associated to the object object on a unique action type Like. Original Action ID: 143539809123515\""
}
],
"body": "{\n \"error\": {\n \"message\": \"(#3501) User is already associated to the object object on a unique action type Like. Original Action ID: 143539809123515\",\n \"type\": \"OAuthException\",\n \"code\": 3501\n }\n}"
},
null
]
So to check if object was liked, JSON.parse the first response body and look for an error with error code 3501. Keep in mind that the actual error code is not documented anywhere so it could change, although I don't think it is likely.

Categories