Creating another instance of the javascript console - javascript

Is it possible to create another instance of the javascript console and use it at one's own discretion, such as placing content filed to console.log() in a div on your page)?

You can override it, but that's not a good practice. Like this:
console.log = function() {
for(var i = 0; i < arguments.length; i++)
document.getElementById("logs").textContent += JSON.stringify(arguments[i], null, 4) + '\n\n';
}
var object = {a: 45, b: "hh"};
console.log(object);
console.log("Hello world!");
console.log(45 + 5);
<pre id="logs"></pre>
Note 1: console.log is a great tool for debugging, it should not be overriden. I don't recommend you override it but instead, I'll recommend you make a function (called for example myConsoleLog) that does what you need.
Note 2: The example I provided is just a basic example to give you insight, you'll need a lot of other stuff (the folding of objects and arrays, the logging of functions for example...).

See this answer, which you could implement by grabbing the value of the stack and writing it to a div on your page.
<div id="log"></div>
var logBackup = console.log;
var logMessages = [];
console.log = function() {
logMessages.push.apply(logMessages, arguments);
document.getElementById('log').innerHTML = "";
for(var i = 0; i < logMessages.length; i++){
var pre = document.createElement("pre");
pre.innerHTML = logMessages[i];
document.getElementById('log').appendChild(pre);
}
logBackup.apply(console, arguments);
};
console.log("My name is joe.")
console.log("My name is tom")
https://jsfiddle.net/yak613/7g6kchox/

You can override console.log. Something like this:
console.log = function(objToLog) {
var myLog = document.getElementById('myLog');
var str = '';
if (typeof objToLog === 'string') {
str = objToLog;
} else if (typeof objToLog === 'object') { //includes array print
str = JSON.stringify(objToLog);
}
myLog.innerText = myLog.innerText + '\n> ' + str;
}
console.log('log this line');
console.log('log this other line');
console.log([1,2,3]);
console.log({ key: 'value' });
Will print to a div:
> log this line
> log this other line
> [1,2,3]
> {"key":"value"}
Fiddle: https://jsfiddle.net/mrlew/a08qL18d/

Related

Build object in JavaScript from PHP form input name

There are a couple of similar questions but none covers the case when a string looks like some-name[][some-key]. I have tried JSON.parse('some-name[][some-key]'); but it doesn't parse it.
Is there a way to convert such string to a JavaScript object that will look like { 'some-name': { 0: { 'some-key': '' } } }?
This is a name of a form field. It's normally parsed by PHP but I'd like to parse it with JavaScript the same way. I basically have <input name="some-name[][some-key]"> and I'd like to convert that to var something = { 'some-name': { 0: { 'some-key': VALUE-OF-THIS-FIELD } } }.
Try this:
JSON.parse('{ "some-name": [ { "some-key": "" } ] }');
I don't know exactly how you're doing this, but assuming they are all that format (name[][key]) and you need to do them one by one - this works for me:
var fieldObj = {};
function parseFieldName(nameStr)
{
var parts = nameStr.match(/[^[\]]+/g);
var name = parts[0];
var key = typeof parts[parts.length-1] != 'undefined' ? parts[parts.length-1] : false;
if(key===false) return false;
else
{
if(!fieldObj.hasOwnProperty(name)) fieldObj[name] = [];
var o = {};
o[key] = 'val';
fieldObj[name].push(o);
}
}
parseFieldName('some-name[][some-key]');
parseFieldName('some-name[][some-key2]');
parseFieldName('some-name2[][some-key]');
console.log(fieldObj); //Firebug shows: Object { some-name=[2], some-name2=[1]} -- stringified: {"some-name":[{"some-key":"val"},{"some-key2":"val"}],"some-name2":[{"some-key":"val"}]}
o[key] = 'val'; could of course be changed to o[key] = $("[name="+nameStr+"]").val() or however you want to deal with it.
Try this:
var input = …,
something = {};
var names = input.name.match(/^[^[\]]*|[^[\]]*(?=\])/g);
for (var o=something, i=0; i<names.length-1; i++) {
if (names[i])
o = o[names[i]] || (o[names[i]] = names[i+1] ? {} : []);
else
o.push(o = names[i+1] ? {} : []);
}
if (names[i])
o[names[i]] = input.value;
else
o.push(input.value);
Edit: according to your updated example, you can make something like this (view below). This will work - but only with the current example.
var convertor = function(element) {
var elementName = element.getAttribute('name');
var inpIndex = elementName.substring(0, elementName.indexOf('[')),
keyIndex = elementName.substring(elementName.lastIndexOf('[') + 1, elementName.lastIndexOf(']'));
var strToObj = "var x = {'" + inpIndex + "': [{'" + keyIndex + "': '" + element.value + "'}]}";
eval(strToObj);
return x;
};
var myObject = convertor(document.getElementById('yourInputID'));
Example here: http://paulrad.com/stackoverflow/string-to-array-object.html
(result is visible in the console.log)
old response
Use eval.. but your string must have a valid javascript syntax
So:
var str = "arr[][123] = 'toto'";
eval(str);
console.log(arr);
Will return a syntax error
Valid syntax will be:
var str = "var arr = []; arr[123] = 'toto'";
var x = eval(str);
console.log(arr);

how to create and assign a value to a variable created dynamically?

I'm trying to get this to work:
function whatever(arg) {
eval(arg) + '_group' = [];
}
The purpose is to have only 1 function instead having three with basically the same content but with different variable names.
At the end I want to have something like:
a_group = [];
b_group = [];
Doing this way, I'm getting the error:
ReferenceError: Invalid left-hand side in assignment
EDIT
Here is the original function that I'm trying to make work. But it won't work.
function collect_all_values_for(field_name) {
switch(field_name) {
case 'states':
use = 'state';
case 'cities':
use = 'city';
case 'neighborhoods':
use = 'neighborhood';
}
window[field_name + '_group'] = [];
n_fields = $('[id^=' + use + '_]').length-1;
i = 0;
field_value = 0;
for (i = 0; i<= n_fields; i++) {
if (i == 0) {
field_value = $('#' + use).val();
}else{
field_value = $('#' + use + '_id' + i).val();
}
//states_group.push(field_value);
window[field_name + '_group'].push(field_value);
}
}
Looking on the console output:
states_group
[undefined, undefined, undefined]
And then I should be able to call it as:
collect_all_values_for('states');
collect_all_values_for('cities');
collect_all_values_for('neighborhoods');
Thanks in advance.
function whatever(arg) {
window[arg + '_group'] = [];
}
This will set a_group, b_group as global variable.
To access those variable use:
window['a_group'], window['b_group'] and so on.
According to edit
In your switch you should use break;.
switch(field_name) {
case 'states':
use = 'state';
break;
case 'cities':
use = 'city';
break;
case 'neighborhoods':
use = 'neighborhood';
break;
}
Using local Object (without window object) and better
var myObject = {};
function whatever(arg) {
myObject[arg + '_group'] = [];
// output: { 'a_group' : [], 'b_group' : [], .. }
}
// to set value
myObject[arg + '_group'].push( some_value );
// to get value
myObject[arg + '_group'];
Although you really shouldn't use eval this should help
eval(arg + '_group') = [];
Just to increase #theparadox's answer.
I prefer to use the following way to make a switch.
var options = {
'states' : 'state',
'cities': 'city',
'neighborhoods': 'neighborhood'
};
use = options[field_name];
demo
Or if you just want to remove the last letter, you can do this.
use = field_name.slice(0,-1);
demo

How to use $.extend() with variables

I'm trying to make a script to use multiple values in window.location.hash but i'm having a problem with the $.extend() function of jquery
I've tried two ways, but both didn't work out.
var MultiHash = {
params: {},
getHash: function () {
var hashString = document.location.hash.replace('#', '').split('&');
for (var i=0; i < hashString.length; i++) {
var key = hashString[i].split('=')[0];
var value = decodeURIComponent(hashString[i].split('=')[1]);
// First way
var a = {key: value};
// Second way
var a = {};
a[key] = value;
$.extend(params, a);
}
return params;
},
...
}
Is anyone seeing the problem?
first you should write :
$.extend(this.params, a); or you cant access param
there may be other issues.
EDIT
it makes sense you return a instead of this.params in my opinion.
$.extend(a,this.params);
return a
There are two problems wrong with what you're trying to do. The first of which being a reference problem as the params variable for that object should be referenced as this.params. The second problem being that you are not saving the result of the object extension. All of this occurs in the following line:
$.extend(params, a);
It should read something like this instead:
this.params = $.extend(this.params, a);
try this one :
var MultiHash = {
params: {},
getHash: function () {
var hashString = document.location.hash.replace('#', '').split('&');
var a = [];
for (var i=0; i < hashString.length; i++) {
var key = hashString[i].split('=')[0];
var value = decodeURIComponent(hashString[i].split('=')[1]);
a.push(key + ":'" + value + "'");
}
$.extend(this.params,(new Function("return {" + a.Join(",") + "}"))());
return this.params;
},
...
}

javascript abstract console logging

I want to make a function, like this.
For example:
function Logger() {
this.log = function(msg) {
console.log(msg);
}
}
And I want to use it in functions/modules etc, and that all works fine.
But the default console in my browser normally give the fileName + lineNumber.
Now when I abstract this functionality, the fileName and lineNumber is not where I put my instance.log(). Because it will say from where the console.log is being called, not the function itself.
So my question:
How can I get the correct information from where I want to use my logger?
Or give me, please, any tips to improve this functionality.
function Logger() {
this.log = console.log.bind(console);
}
I asked about this some time ago: Create shortcut to console.log() in Chrome.
Try using backtrace function like this one :
function printStackTrace() {
var callstack = [];
var isCallstackPopulated = false;
try {
i.dont.exist += 0; //doesn't exist- that's the point
} catch (e) {
if (e.stack) { //Firefox
var lines = e.stack.split('\n');
for (var i = 0, len = lines.length; i & lt; len; i++) {
if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/)) {
callstack.push(lines[i]);
}
}
//Remove call to printStackTrace()
callstack.shift();
isCallstackPopulated = true;
}
else if (window.opera & amp; & amp; e.message) { //Opera
var lines = e.message.split('\n');
for (var i = 0, len = lines.length; i & lt; len; i++) {
if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/)) {
var entry = lines[i];
//Append next line also since it has the file info
if (lines[i + 1]) {
entry += ' at ' + lines[i + 1];
i++;
}
callstack.push(entry);
}
}
//Remove call to printStackTrace()
callstack.shift();
isCallstackPopulated = true;
}
}
if (!isCallstackPopulated) { //IE and Safari
var currentFunction = arguments.callee.caller;
while (currentFunction) {
var fn = currentFunction.toString();
var fname = fn.substring(fn.indexOf( & amp; quot;
function & amp; quot;) + 8, fn.indexOf('')) || 'anonymous';
callstack.push(fname);
currentFunction = currentFunction.caller;
}
}
output(callstack);
}
function output(arr) {
//Optput however you want
alert(arr.join('\n\n'));
}
Try assigning the function:
(function () {
window.log = (console && console.log
? console.log
: function () {
// Alternative log
});
})();
Later just call log('Message') in your code.

Customized Stack Traces in Google Chrome Developer Tools?

I'm looking to customize the items that show up in the strack trace panel in the Scripts tab of Google Chrome's developers tools. Specifically, I want to filter out items in the stack trace and to add more descriptive names to some of the items on the stack trace without having to rename my objects and functions.
I found V8's Stack Trace API at http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi but overriding Error.prepareStackTrace doesn't seem to have any effect.
The description on that page is definitely a little hard to follow, here's how it's done:
Error.prepareStackTrace = function(error, stack) {
return stack;
};
var someObj = {
someMethod : function () {
crash();
}
}
function bar(barArg) { someObj.someMethod(); };
function foo(fooArg) { bar("barArgString"); };
function getTrace(e) {
var stack = e.stack;
var trace = "";
for (var i = 0; i < stack.length; i++) {
var frame = stack[i],
func = frame.getFunction();
trace += "\r" + frame.getThis() + "." + frame.getFunctionName();
}
return trace;
}
try {
foo("fooArgString");
} catch (e) {
alert("trace from catch(): " + getTrace(e));
}
This will show:
trace from catch():
[object Object].someObj.someMethod
[object Window].bar
[object Window].foo
[object Window].
The last frame is global scope (no function name).
Essentially your override of prepareStackTrace() causes error.stack to become whatever you return from prepareStackTrace(). The trick is that the second argument to prepareStackTrace() is an Array of CallSite objects - the objects that support getThis(), getFunctionName() etc.
The code above overrides prepareStackTrace() so that it returns the Array of CallSite objects ("stack" parameter above), so this means when you try..catch an Error, Error.stack is going to contain the Array of CallSite objects instead of the usual stack trace in String form. Another approach would be to process the CallSite objects inside of your replacement prepareStackTrace() function and return your alternative stack trace as a String.
Note the CallSite objects are really finicky. Try to do frame.toString(), or just try to alert(frame) (implicitly this involves toString()) and it crashes and Chrome's developer tools show no error.
Here's the code that did the trick for me:
<head>
<script>
Error.prepareStackTrace = function()
{
return "MyStackObject";
}
try {
throw new Error();
} catch (e) {
console.log(e.stack);
}
</script>
</head>
The documentation has moved here:
https://github.com/v8/v8/wiki/Stack-Trace-API
Just put this at the beginning of your javascript code, it formats a nice stack trace:
Error.prepareStackTrace = function(error, stack) {
var trace = '';
var max_width = 0;
for (var i = 0; i < stack.length; i++){
var frame = stack[i];
var typeLength = 0;
typeLength = (frame.getTypeName() !== null && frame.getTypeName() !== '[object global]') ? frame.getTypeName().length : 0;
typeLength = typeLength.length > 50 ? 50 : typeLength;
functionlength = frame.getFunctionName() !== null ? frame.getFunctionName().length : '<anonymous>'.length;
functionlength = functionlength > 50 ? 50 : functionlength;
if (typeLength + functionlength > max_width)
max_width = typeLength + functionlength;
}
for (var i = 0; i < stack.length; i++) {
var frame = stack[i];
var filepath = frame.getFileName();
var typeName = '';
if (frame.getTypeName() !== null && frame.getTypeName() !== '[object global]')
typeName = frame.getTypeName().substring(0, 50) + '.';
var functionName = '<anonymous>';
if (frame.getFunctionName() !== null)
functionName = frame.getFunctionName().substring(0, 50);
var space = '';
var width = max_width - (typeName.length + functionName.length) + 2;
space = Array(width).join(' ');
var line = ' at ' + typeName + functionName + space + filepath +
' (' + frame.getLineNumber() +
':' + frame.getColumnNumber() + ')\n';
trace += line;
}
return trace;
};
Here's an example to the test the code:
function A() { B(); }
function B() { C(); }
function C() { throw new Error('asd'); }
try {
A();
} catch (e) { print(e + '\n' + e.stack); }

Categories

Resources