JavaScript cannot read property of undefined on variable declared earlier - javascript

I get TypeError: Cannot read property 'enabled' of undefined both in the anonymous function (on column 21) and the while loop (on column 15):
var enabled = "unknown";
chrome.runtime.sendMessage({request: "Am I enabled?"},
function(response)
{
enabled = response.enabled;
});
while(enabled == "unknown")
{
// wait
}
I don't typically write Javascript, so I'm not sure what I could be doing wrong here. Searching gives me results like var y = null; log(y.property); which are not this issue at all.

The error comes from this line:
enabled = response.enabled;
because response is undefined.
According to the documentation:
If an error occurs while connecting to the extension, the callback will be called with no arguments and runtime.lastError will be set to the error message.
So, modify your code:
var enabled = "unknown";
chrome.runtime.sendMessage({request: "Am I enabled?"},
function(response)
{
if (!response) {
// TODO: Check runtime.lastError and take an appropriate action
} else {
enabled = response.enabled;
if (enabled) {
// TODO: Do the stuff you were planning to do after the while() loop, call a function, etc.
}
}
});

Related

accessing object values that are inside an array

I'm hoping someone can help with what is likely a simple answer - but I'm ready to bash my head against the wall....again.
I have a function which makes a JSON call to an API, and then pushes the results into an array. The function appears to work just fine as my console.log is showing that the array is populated correctly.
I'm struggling with how to access the values of the modified twichResult object (after the function has run), so that I can do 'stuff' with it. e.g. display the value of the 'status' property onscreen etc... I give some examples of what I've tried in the in the large commented out section.
I'd really appreciate some intelligence weighing in on this as I've exhausted my resources. Thanks in advance.
<script type="text/javascript">
$(document).ready(function() {
var twitchResult = {results:[]};
var channel = { logo:"", display_name:"", status:"", url:"" };
var finalUrl = "https://api.twitch.tv/kraken/streams/freecodecamp?callback=?"
getTwitchers (finalUrl, "freecodecamp");
console.log(twitchResult);
// How do I access the individual values in the object TwitchResult?
// I get "undefined" in the console if I try to access the object's property values
// I've tried every way I can think of to get 'into' the returned object :
// console.log(twitchResult.results);
// console.log(twitchResult["results"])
// console.log(twitchResult.results.status)
// console.log(twitchResult[0])
// console.log(twitchResult[0][0])
// etc etc
function getTwitchers (url, item) {
$.getJSON(url, function(data) {
var obj = data.stream;
// Check if the object is not valid using (obj == null) which is shorthand for both null and undefined
if (obj == null) {
if (obj === undefined) {
channel.display_name = item;
channel.status = "closed";
console.log ("this is undefined");
}
else {
channel.display_name = item;
channel.status = "offline";
console.log("this is null");
}
}
else {
channel.logo = obj.channel.logo;
channel.display_name = obj.channel.display_name;
channel.status = obj.channel.status;
channel.url = obj.channel.url;
console.log("valid entry");
}
twitchResult["results"].push(channel);
// twitchResult.results.push(channel);
// console.log(twitchResult);
});
}
});
</script>
$.getJSON is making an ajax-request. You must handle this request from within the request handler. When getTwichers returns, twichResults is not yet set.
There are methods to delay Program execution, until twichResults is done, but You should not think of using them, since they would delay program execution. The idea of ajax is to execute things asynchronously, without disturbing the rest of the execution flow. If the code You want to execute depends on the json, then You should add it to the handle in $.getJSON. Just write a new function (e.g. continue_execution(twichResult)) and invoke it right after twitchResult["results"].push(channel);. Just don't do anything after getTwitchers(...).
By the way: It is a good habit to define functions, before they are used, because it follows the flow the human eye reads the code and there are programming languages, which depend on this style of declaring function.
If this is unclear to You, then add a comment.

chrome.hid.send fails on second use

Something about my use of chrome.hid.send seems to be leaving the bus in a bad state. I consistently can NOT get my second usage of the API call to work. Sometimes, it will also fail on the first usage. WITH THE EXACT SAME CODE, I can come back and try a while later (maybe 10min) and the first send will work.
The device I'm working with does not return a response to all messages sent to it. The test message for example, is just a dummy message that is ignored by the device. I've tested this both on a mac and a PC. My call stack depth is 2 at this point in my application (literally first one is kicked off by a button click and then a setTimeout calls the same method 5s later).
I've testing sending buffers of length 64Bytes as well as 58Bytes. The properties from the HidDeviceInfo object read "maxInputReportSize":64,"maxOutputReportSize":64
Params on first usage:
Params on second usage:
I really can't identify how I'm using the API incorrectly. When messages do succeed, I can see them on the device side.
// Transmits the given data
//
// #param[in] outData, The data to send as an ArrayBuffer
// #param[in] onTxCompleted, The method called on completion of the outgoing transfer. The return
// code is passed as a string.
// #param[in] onRxCompleted, The method called on completion of the incoming transfer. The return
// code is passed as a string along with the response as an ArrayBuffer.
send: function(outData, onTxCompleted, onRxCompleted) {
if (-1 === connection_) {
console.log("Attempted to send data with no device connected.");
return;
}
if (0 == outData.byteLength) {
console.log("Attempted to send nothing.");
return;
}
if (COMMS.receiving) {
console.log("Waiting for a response to a previous message. Aborting.");
return;
}
if (COMMS.transmitting) {
console.log("Waiting for a previous message to finish sending. Aborting.");
return;
}
COMMS.transmitting = true;
var dummyUint8Array = new Uint8Array(outData);
chrome.hid.send(connection_, REPORT_ID, outData, function() {
COMMS.transmitting = false;
if (onTxCompleted) {
onTxCompleted(chrome.runtime.lastError ? chrome.runtime.lastError.message : '');
}
if (chrome.runtime.lastError) {
console.log('Error in COMMS.send: ' + chrome.runtime.lastError.message);
return;
}
// Register a response handler if one is expected
if (onRxCompleted) {
COMMS.receiving = true;
chrome.hid.receive(connection_, function(reportId, inData) {
COMMS.receiving = false;
onRxCompleted(chrome.runtime.lastError ? chrome.runtime.lastError.message : '', inData);
});
}
});
}
// Example usage
var testMessage = new Uint8Array(58);
var testTransmission = function() {
message[0] = 123;
COMMS.send(message.buffer, null, null);
setTimeout(testTransmission, 5000);
};
testTranmission();
The issue is that Windows requires buffers to be the full report size expected by the device. I have filed a bug against Chromium to track adding a workaround or at least a better error message to pinpoint the problem.
In general you can get more detailed error messages from the chrome.hid API by enabling verbose logging with the --enable-logging --v=1 command line options. Full documentation of Chrome logging is here.

Meteor Session.set() from mongodb property in helper function not working after deploy

I am trying to set the session from a property in the mongodb. I have this working locally, but after deploy I get this error in the console, and a white screen of death.
Exception from Deps recompute: TypeError: Cannot read property
'siteTheme' of undefined
// helper
Handlebars.registerHelper("site", function(){
host = headers.get('host');
theSite = Site.findOne({'domain': host});
theme = theSite.siteTheme;
// Problem - Works locally, not deployed with mup.
// Exception from Deps recompute: TypeError: Cannot read property 'siteTheme' of undefined
Session.set("theme", theme);
return theSite;
});
// Add theme class to html
siteTheme0 = function(){
$('html').addClass('theme0');
};
siteTheme1 = function(){
$('html').addClass('theme1');
};
siteTheme2 = function(){
$('html').addClass('theme2');
};
siteTheme3 = function(){
$('html').addClass('theme3');
};
// Change theme on change to db
Deps.autorun(function (c) {
if (Session.equals("theme", "1")){
siteTheme1();
}
else if (Session.equals("theme", "2")){
siteTheme2();
}
else if (Session.equals("theme", "3")){
siteTheme3();
}
else {
Session.set("theme", "0");
siteTheme0();
}
});
This is one of the most commonly encountered problems with meteor. Your collection data isn't ready when your helper is called (or it doesn't exist), so Site.findOne returns undefined and you can't access siteTheme of undefined. See my answer to this question. Basically you just need to add some kind of guard or return statement and assume the data may not be ready. For example:
Handlebars.registerHelper("site", function(){
var host = headers.get('host');
var theSite = Site.findOne({'domain': host});
if (theSite) {
var theme = theSite.siteTheme;
Session.set("theme", theme);
return theSite;
}
});
If the rest of your code is written properly, your template should render again as soon as the data is ready.

Check for duplicate record in Chrome Storage extension before saving

I'm developing a small Chrome extension that would allow me to save some records to chrome.storage and then display them.
I've managed to make the set and get process work as I wanted (kinda), but now I'd like to add a duplicate check before saving any record, and I'm quite stuck trying to find a nice and clean solution.
That's what I came up for now:
var storage = chrome.storage.sync;
function saveRecord(record) {
var duplicate = false;
var recordName = record.name;
storage.get('records', function(data) {
var records = data.records;
console.log('im here');
for (var i = 0; i < records.length; i++) {
var Record = records[i];
if (Record.name === recordName) {
duplicate = true;
break;
} else {
console.log(record);
}
}
if (duplicate) {
console.log('this record is already there!');
} else {
arrayWithRecords.push(record);
storage.set({ bands: arrayWithRecords }, function() {
console.log('saved ' + record.name);
});
}
});
}
I'm basically iterating on the array containing the records and checking if the name property already exists. The problem is it breaks basic set and get functionality -- in fact, when saving it correctly logs 'im here' and the relative record object, but it doesn't set the value. Plus, after a while (generally after trying to list the bands with a basic storage.get function) it returns this error:
Error in response to storage.get: TypeError: Cannot read property
'name' of null
I'm guessing this is due to the async nature of the set and get and my incompetence working with it, but I can't get my head around it in order to find a better alternative. Ideas?
Thanks in advance.

Correctly Suppressing Warnings in DataTables?

I'm trying to correctly suppress warnings (alerts) in DataTables. The standard behavior of DataTables is to throw a javascript alert when an error occurs; however, this is currently inconvenient for me. I have been trying to convert the warning to a javascript error by
$.fn.dataTableExt.sErrMode = 'throw';
Which works correctly, but this stops the current javascript execution, which is not what I want. So, I wrapped the DataTables operations (init and changes) in a try-catch with no error handling; however, this also halts the javascript execution. (Tested on Chrome and Firefox)
My question is how do I go about getting rid of these errors/alerts for the purposes of debugging? I'm trying to debug other parts of my script, but these alerts keep on getting in the way.
I modified the native alert using this closure function to redirect DataTables warnings to the console.
window.alert = (function() {
var nativeAlert = window.alert;
return function(message) {
window.alert = nativeAlert;
message.indexOf("DataTables warning") === 0 ?
console.warn(message) :
nativeAlert(message);
}
})();
It restores the window.alert to its native function on first trigger. If you don't want it to restore to the original alert, just comment out the window.alert = nativeAlert; line.
NB: This answer applies to dataTables 1.9.x!
For $.fn.dataTableExt.sErrMode the only value there has any importance is "alert". It is "alert" or anything else. sErrMode is handled by the internal dispatcher function _fnLog, in v1.9.2 about line 4575 in media/js/jquery.dataTables.js :
function _fnLog( oSettings, iLevel, sMesg )
{
var sAlert = (oSettings===null) ?
"DataTables warning: "+sMesg :
"DataTables warning (table id = '"+oSettings.sTableId+"'): "+sMesg;
if ( iLevel === 0 )
{
if ( DataTable.ext.sErrMode == 'alert' )
{
alert( sAlert );
}
else
{
throw new Error(sAlert);
}
return;
}
else if ( window.console && console.log )
{
console.log( sAlert );
}
}
Unfortunelaty, there is no way to override dataTables internal functions, believe me - I have tried, not possible with prototyping or anything else. You can read the author Allan Jardines own comment to that here :
I'm sorry to say that due to how DataTables is constructed at the
moment, it's not possible to override an internal function using
Javascript outside of DataTables scope. This is something that will be
addressed whenever I get around to doing the 2.x series (which might
be a while off!) - but at present you would need to alter the core.
One could think that : Hey, perhaps the iLevel-flag can be changed somewhere in the settings? Again, unfortunately no. iLevel is hardcoded in each internal call to _fnLog.
It is somehow disappointing we have to choose between ugly alerts and completely halt of execution, because an error is thrown. A simply override of window.onerror does not work either. The solution is to modify _fnLog, simply comment out the line where the custom error is thrown :
else
{
// throw new Error(sAlert); <-- comment this line
}
And the execution continues if you have $.fn.dataTableExt.sErrMode = 'throw' (anything else but "alert") and if errors occurs. Even better, one could need those thrown errors in other situations, set a flag outside, like
window.isDebugging = true;
and
else
{
if (!window.isDebugging) throw new Error(sAlert);
}
This is not a "hack" in my opinion, but overruling of a general not avoidable jQuery dataTables behaviour that sometimes is not satisfying. As Allan Jardine himself write in the above link :
Why can't you just modify the source? That's the whole point of open
source :-)
Here's a solution proposed here that's slightly modified and works in v1.10.2 without having to change any vendor files:
$.fn.dataTableExt.sErrMode = "console";
$.fn.dataTableExt.oApi._fnLog = function (oSettings, iLevel, sMesg, tn) {
var sAlert = (oSettings === null)
? "DataTables warning: "+sMesg
: "DataTables warning (table id = '"+oSettings.sTableId+"'): "+sMesg
;
if (tn) {
sAlert += ". For more information about this error, please see "+
"http://datatables.net/tn/"+tn
;
}
if (iLevel === 0) {
if ($.fn.dataTableExt.sErrMode == "alert") {
alert(sAlert);
} else if ($.fn.dataTableExt.sErrMode == "thow") {
throw sAlert;
} else if ($.fn.dataTableExt.sErrMode == "console") {
console.log(sAlert);
} else if ($.fn.dataTableExt.sErrMode == "mute") {}
return;
} else if (console !== undefined && console.log) {
console.log(sAlert);
}
}
try this:
$.fn.DataTable.ext.oApi._fnLog = function (settings, level, msg, tn) {
msg = 'DataTables warning: ' +
(settings !== null ? 'table id=' + settings.sTableId + ' - ' : '') + msg;
if (tn) {
msg += '. For more information about this error, please see ' +
'http://datatables.net/tn/' + tn;
}
console.log( msg );
};
As of DataTables version 1.10.15, you can set $.fn.dataTableExt.errMode to 'ignore' and it will silently ignore the error messages:
$(document).ready(function () {
$.fn.dataTableExt.errMode = 'ignore';
});
_fnLog DataTables function has the following code :
if ( type == 'alert' ) {
alert( msg );
}
else if ( type == 'throw' ) {
throw new Error(msg);
}
else if ( typeof type == 'function' ) {
type( settings, tn, msg );
}
The default value is 'alert' which is problematic.
You can also set to 'throw'. It will create javascript error, but will not do disturb the user.
'ignore' or any other values will just sliently skip the error.
Let me add my 2 cents to davidkonrad's answer above.
One way of modifying _fnLog function without changing the file is to get reference to that method from Api instance in datatables settings:
$.fn.dataTableSettings[0].oApi._fnLog = function(settings, level, msg, tn) {
// Modified version of _fnLog
}
Hope that this will be helpful for someone.

Categories