assigning variables only if undefined in javascript - javascript

I'm trying to extract two keywords from a url in this format
localhost:3000/"charactername"/"realmname"
where I want to exctract "charactername" and "realmname" and assign them to variables.
I use:
var charactername = req.url.split("/")[1];
console.log(charactername);
var realmname = req.url.split("/")[2];
console.log(realmname);
Everything works fine and dandy at first, but then it seems a request is made for a "favicon.ico", and my variables become undefined since there is a new request url. I tried solving this by encapsulating the code snippet in an if statement like this:
if(req.url !== '/favicon.ico'){
var charactername = req.url.split("/")[1];
console.log(charactername);
var realmname = req.url.split("/")[2];
console.log(realmname);
}
The console.log outputs tells me the variables are set to their correct values, it never says it is undefined so it seems to work.. However, when the next part of the code is executed:
if(charactername.length > 0){
res.writeHead(200, {'Content-Type': 'text/html'});
renderer.view("header", {}, res);
//get json from battle.net
var characterProfile = new Profile(charactername, realmname);
//on "end"
characterProfile.on("end", function(profileJSON){
//Show profile
//Store values we need
var values = {
avatarURL: profileJSON.thumbnail,
charactername: profileJSON.name,
realmname: profileJSON.realm,
level: profileJSON.level
}
//Simple response
renderer.view("profile", values, res);
renderer.view("footer", {}, res);
res.end();
});
I get an error saying cannot read property length of undefined. So it seems the variables become undefined somehow anyway. Anyone got a clue on how to solve this?

if(x === undefined){
//do something
}
This checks if the variable is undefined, however I suggest you check what is causing the error in the first place.

if(charactername && charactername.length > 0){
...

Related

Why is this code not working in NodeJS after exporting it to a separate module?

I am on my way to separate the code for my API in different modules using the exports object, as it is the most similar way to the ES6 standard (not yet supported by Node).
Here is my code currently (it can be run as shown), the problem is that, after separating, the function "cleanFormData" gets called fine, but stops without returning anything (observe the comments starting with "STACK OVERFLOW"):
File: main.js
// Dependencies:
const express = require('express');
const bodyParser = require('body-parser');
// Define app:
const app = express();
// API v0 code:
const apiV0 = require('./api0_sources/api');
// Configuration variables:
const consoleLogActions = true;
// Server start:
app.listen(8888, function () {
console.log('Server running on port ' + this.address().port + ' - ' + new Date());
});
// For parsing every application/json request:
app.use(bodyParser.json());
// Submit data to register an user:
app.post('/registration', function (req, res) {
res.set({'Content-Type': 'application/json'});
// Clean the required data after obtaining it from the parsed JSON:
let cleanedFormData = apiV0.cleanFormData({ // STACK OVERFLOW: The code stops working here.
username: req.body.formdata.username,
email: req.body.formdata.email,
phone: req.body.formdata.phone,
password: req.body.formdata.password
});
// The "required or not" policy is enforced here (after the strings have been cleaned to prevent blank fields to pass):
errors = [];
if (cleanedFormData.username === undefined) errors.push('username_required');
if (cleanedFormData.email === undefined) errors.push('email_required');
if (cleanedFormData.phone === undefined) errors.push('phone_required');
if (cleanedFormData.password === undefined) errors.push('password_required');
if (errors.length > 0) {
let result = {
success: false,
errors: errors
};
res.jsonp(result);
}
})
// [More things happen after]
File: ./api0_sources/api.js
// Fix and delete object's strings (for data coming from user's inputs):
exports.cleanFormData = function(object) {
for (let i in object) {
object[i] = String(object[i]); // Convert all the object properties to strings (to prevent problems with true, false and null).
if ((object[i] === 'undefined') || (!object[i].replace(/\s/g, '').length)) { // Deletes 'undefined' strings, empty strings and the ones containing only spaces.
delete object[i];
continue; // Skip to the next loop after the property is removed.
}
// Do not try to fix the "password" or "newPassword" property:
if ((i === 'password') || (i === 'newPassword')) continue;
// Replace multiple spaces with a single one:
object[i] = object[i].replace(/\s\s+/g, ' ');
// Check if it is "trimmable" and if so, trim the string:
if (object[i].trim()) object[i] = object[i].trim();
console.log(object[i]) // Observing iterations.
}
if (consoleLogActions) console.log('▼ Cleaned object keys:\n', object);
return object;
};
Before, everything was in the same file and worked perfectly fine! Can someone help me to identify what has triggered this unexpected behaviour?
UPDATED 1: Apparently, I identified the problem: I had a variable not shown in the example before: "consoleLogActions", that was only defined in the main file and apparently this stopped the function in the child module from finishing. However, absolutely no error was being thrown by Node. In the updated example it does, in my actual file it doesn't (still, no idea why).
UPDATE 2: Thanks, Marcos Casagrande. It seems like this Express middleware is catching the wrong exceptions. I had literally no idea that this could affect the rest of the code nor I have idea how to fix it. Any suggestions?:
// Detecting syntax errors (depending on the "application/type"):
app.use(function(err, req, res, next) {
if (err instanceof SyntaxError) { // If "SyntaxError" is part of the error object:
res
.status(400)
.jsonp({
success: false,
errors: ['bad_syntax']
});
}
});
Apparently, I identified the problem: I had a variable not shown in
the example before: "consoleLogActions", that was only defined in the
main file and apparently this stopped the function in the child module
from finishing. However, absolutely no error was being thrown by Node.
In the updated example it does, in my actual file it doesn't (still,
no idea why).
If you're not getting any error, you probably have an express error-handling middleware, that it's not logging the error.
app.use((err, req, res, next) => {
// console.error(err); // I'm not doing this.
res.status(500).end();
});
Or you have an uncaughtException listener somewhere in your code.
process.on('uncaughtException', () => {});
The code above, will prevent uncaught errors from being logged, and the process from crashing. This is a really bad practice, and you should avoid it.
Check the following question:
Node.js Best Practice Exception Handling

getting sessionid with javascript

Under the headline:
Finding the session id with javascript in the browser
from this link:
Link to Autopilot
it says that I with the line of code can capture the Autopilot session id.
var sessionId = AutopilotAnywhere.sessionId;
I tried to set the line of code in the console, but I get undefined:
I am not quite sure how to use this line of code. Can anybody see how I use the line of code?
Try it:
function getJSessionId(){
var jsId = document.cookie.match(/JSESSIONID=[^;]+/);
if(jsId != null) {
if (jsId instanceof Array)
jsId = jsId[0].substring(11);
else
jsId = jsId.substring(11);
}
return jsId;
}

Not able to get nested objects from JSON

I have tried to get some help on this matter previously, but nothing seems to work. I want to retrieve some nested objects from a REST API.
This is the code that I am using and that should work:
var url = 'XXXXX';
$(function(){
$.getJSON(url, function(data){
$.each(data.paths,function(i,emp){
var b = this.places[0].place_radius;
console.log(b);
});
});
});
However, I get this error message when I try to execute it in a web browser:
25
25
apirest.html:14 Uncaught TypeError: Cannot read property 'place_radius' of undefined
I really appreciate any help!
Here's one way to quickly check a bunch of child elements, and assign the correct value to "b", or false if something didn't exist. Note that if place_radius is falsy (evaluates to bool false, so zero for example) you'll have to use a more careful technique.
$.getJSON(url, function(data){
$.each(data.paths,function(i,emp){
var b = this.places && this.places[0] && this.places[0].place_radius || false;
if (b === false) {
console.log("that thing did not exist");
} else {
console.log(b);
}
});
});

Javascript Variable Sometimes Undefined

I know this question has been asked several times, but I couldn't seem to find a solution that worked for me in any of the previous questions. I have a variable that gets set when my HTML page is done loading, but sometimes when my code tries to access that variable, it says that it is undefined. I'm not sure why, since I believe I am waiting for everything to load properly. This exception seems to happen randomly, as most of the time all the code runs fine. Here's a simplified version of my code:
var globalVar;
function initStuff(filePath) {
// I wait till the HTML page is fully loaded before doing anything
$(document).ready(function(){
var video = document.getElementById("videoElementID");
// My parseFile() function seems to run smoothly
var arrayOfStuff = parseFile(filePath);
if (arrayOfStuff == null) {
console.error("Unable to properly parse the file.");
} else {
setGlobalVariable(arrayOfStuff);
video.addEventListener("play", updateVideoFrame, false);
}
});
}
function setGlobalVariable(arrayOfStuff) {
window.globalVar = arrayOfStuff;
}
function updateVideoFrame() {
// A bunch of other code happens first
// This is the line that fails occasionally, saying
// "window.globalVar[0].aProperty.anArray[0] is undefined"
var test = window.globalVar[0].aProperty.anArray[0].aProperty;
}
The only thing that I can think of that might be causing this problem is some sort of synchronicity issue. I don't see why that would be the case, though. Help please!
Edit:
In case the asynchronicity issue is coming from my parseFile(xmlFile) method, here is what I'm doing there. I thought it couldn't possibly be causing the issue, since I force the method to happen synchronously, but in case I'm wrong, here it is:
function parseKML(xmlFile) {
var arrayOfStuff = new Array();
// Turn the AJAX asynchronicity off for the following GET command
$.ajaxSetup( { async : false } );
// Open the XML file
$.get(xmlFile, {}, function(xml) {
var doc = $("Document", xml);
// Code for parsing the XML file is here
// arrayOfStuff() gets populated here
});
// Once I'm done processing the XML file, I turn asynchronicity back on, since that is AJAX's default state
$.ajaxSetup( { async : true } );
return arrayOfStuff;
}
The first thing you should do in your code is figure out which part of:
window.globalVar[0].aProperty.anArray[0]
is undefined.
Since you have multiple chained property references and array references, it could be many different places in the chain. I'd suggest either set a breakpoint right before your reference it examine what's in it or use several console.log() statement sto output each nested piece of the structure in order to find out where your problem is.
console.log("globalVar = " + globalVar);
console.log("globalVar[0] = " + globalVar[0]);
console.log("globalVar[0].aProperty = " + globalVar[0].aProperty);
console.log("globalVar[0].aProperty.anArray = " + globalVar[0].aProperty.anArray);
console.log("globalVar[0].aProperty.anArray[0] = " + globalVar[0].aProperty.anArray[0]);
If the problem is that globalVar isn't yet set, then you have a timing problem or an initialization problem.
If the problem is that one of the other properties isn't set, then you aren't initializing globalVar with what you think you are.
You may also want to write your code more defensibly so it fails gracefully if some of your data isn't set properly.
You need to use defensive programming.
http://www.javascriptref.com/pdf/ch23_ed2.pdf
Example:
var video = document.getElementById("videoElementID") || 0;
-
if( video && video.addEventListener ){
video.addEventListener("play", updateVideoFrame, false);
}
Here's another version of your code.
window.globalVar = globalVar || [];
function setGlobalVariable(arrayOfStuff) {
window.globalVar = arrayOfStuff;
}
function updateVideoFrame() {
// A bunch of other code happens first
// This is the line that fails occasionally, saying
// "window.globalVar[0].aProperty.anArray[0] is undefined"
if( window.globalVar ){
var g = window.globalVar || [];
var d = (g[0] || {})["aProperty"];
// etc...
}else{
console.error( "test error." );
}
}
function initStuff(filePath) {
// I wait till the HTML page is fully loaded before doing anything
$(document).ready(function () {
var video = $("#videoElementID");
// My parseFile() function seems to run smoothly
var arrayOfStuff = parseFile(filePath) || [];
if (arrayOfStuff == null || video == null ) {
console.error("Unable to properly parse the file.");
} else {
setGlobalVariable(arrayOfStuff);
video.bind("play", updateVideoFrame);
}
});
}

I'm having a lot of trouble trying to modify a "this" object from within a pseudo javascript class when it's already been initialized

Scroll down to the bottom of this post to see a work around / possible solution.
This is probably easier just to explain in the source code with comments. The issue at hand is I cannot figure out how pseudo classes work together to perform the task I'm trying to do (explained in the code below).
The code is broken down into 3 files: lead.js, router.js, and db.js.
There are a decent amount of lines of code but most of it is comments.
[lead.js]
var bcrypt = require('bcrypt'),
validators = require('../lib/validators'),
utility = require('../lib/utility'),
document = {};
var Lead = module.exports = function (db) {
// Save a reference to the database.
this.db = db;
// Reference initial document.
// This is totally wrong, not sure how to 'send' a variable to the constructor of a class
// when I cannot add another param. Due to how I'm importing the db model, I won't know what
// the document is until I fill out the form. I've also tried 'document' instead of 'Lead.document'.
this.document = Lead.document;
// Setup the document if it exists.
// This also doesn't work.
// Basically I want to be able to set up a document variable outside of this module (line #100),
// Then pass it to this module after filling it up with values from a form.
// Then based on what's been filled in, it would fix up (trim, convert to lower case)
// some of the values automatically and default a few values that I'm not always going to pass.
if (!document) {
var salt = bcrypt.genSaltSync(10),
hash = bcrypt.hashSync(utility.generatePassword(), salt);
// Default values.
if (!document.meta.createdAt) { this.document.meta.createdAt = Date.now(); }
if (!document.login.password) { this.document.login.password = hash; }
if (!document.login.role) { this.document.login.role = 'User'; }
// Normalize a few values.
this.document.login.email = document.login.email.toLowerCase().trim();
this.document.contact.name.first = document.contact.name.first.trim();
this.document.contact.name.last = document.contact.name.last.trim();
this.document.contact.address.street = document.contact.address.street.trim();
this.document.contact.address.city = document.contact.address.city.trim();
this.document.contact.address.state = document.contact.address.state.trim();
this.document.contact.address.zip = document.contact.address.zip.trim();
this.document.contact.phone.home = document.contact.phone.home.trim();
}
// So in regards to the above code, the end result I'm looking for is...
// I want to append some properties to the this.document reference when the document is empty (when I'm updating it, I won't set the document),
// and on new documents it will append a few default values/normalize all the fields.
};
Lead.prototype.validate = function(fn) {
var errors = [];
// Some validation rules I cut out to make this shorter.
if (errors.length) return fn(errors);
fn();
};
Lead.prototype.save = function(fn) {
this.db.collection('leads', function(err, collection) {
if (err) { fn(new Error({message: err})); }
collection.insert(this.document, function(err, result) {
return fn(err, result);
});
});
};
---
[route.js file]
var db = require('../models/db');
app.post('/register', function(req, res) {
var data = req.body.lead || {};
// Fill the document.
var document = {
meta: {
host: req.headers.host,
referer: req.headers.referer,
createdIPAddress: req.connection.remoteAddress
},
login: {
email: data.email
},
contact: {
name: {
first: data.first,
last: data.last
},
address: {
street: data.street,
city: data.city,
state: data.state,
zip: data.zip
},
phone: {
home: data.phone
}
}
};
// Write the document.
db.lead.document = document;
db.lead.validate(function(err) {
if (err) {
req.session.error = err;
return res.redirect('back');
}
db.lead.save(function(err) {
res.redirect('/register/success');
});
});
});
---
[db.js]
var mongodb = require('mongodb'),
server = new mongodb.Server('localhost', 27017),
connection = new mongodb.Db('test', server);
connection.open(function(err, db) {});
module.exports = {
lead: new (require('./lead'))(connection)
};
When I run this, my validator always reports that the password is empty which makes sense. I'm sending the document initially to the class with an empty password (the password is randomly generated, not a form field) -- the problem is I have no idea what to do with the if (!document) ... code block to actually set the this.document properly.
I hope between the comments and code you can get an idea of what I'm trying to do. I've been stuck on this for a while.
EDIT
I changed the flow of it a bit to get a solution.
In the db.js, I exported the connection rather than instantiating the lead (and future models) directly.
In the router.js file, I require the db and lead file, then pass both the db connection and the document in the constructor of the Lead. Ex.
var lead = new Lead(db, document);
In the lead.js file, it becomes as simple as doing this.document = document (same as the db). When I submit a new lead, the values I don't send over from router.js get appended to the document (the created date, a random password, etc.) and everything is good.
Is this a decent way of handling this, or is there a better way to refactor this?
This is completely wrong way even if make this code work as you want. In this example you have singleton lead. By requesting /register url you want to set 'document' field to this singleton . (IMPORTANT) But requests work asynchronously. Absolutely no guarantee that you save the document, which has just validate. Because new request may overwrite it in lead object. You need to do this logic in request scope. One scope for one request. Not one for all.
You need to read up on object-oriented programming in Javascript.
The anonymous function you're defining near the top of your code is the constructor function, so with respect to the document property you want that is currently uninitialized, just type something like:
this.document = null;
Then some time later when you create a new object using this constructor, like so:
var myLead = new Lead(dbConnection);
You'll have the myLead.document property.
There are many other things wrong with your code, though. Why are you assuming that there is a global document variable with relevant data visible in your library when it's defined as {}? The code in that if statement at the end of your constructor should be run when the document property is set in your other file below, and should only expect this.document to exist.
You set var document = {} initially, and {} is not falsy. Better would be to set as a starting value document = null and then after checking for !document set document = {} before assigning whatever properties you need.

Categories

Resources