I have tried to copy the objects as text, but it show just [object object]. Before this I had tried with copy commend it was success but not now.Is that chrome issue?
What I tried?
Just Right click on the object and store as global variable from chrome console window, then next just used copy(temp6) command and tried to paste in notepad++.
It should ideally copy the object with the copy command that you wrote.
I just tried it and worked for me.
Something else that you can try to do is to stringify that object and then copy it.
Ex.
copy(JSON.stringify(temp6))
If the object already logged
Right-click on the object in console and click Store as a global
variable the output will be something like temp1
Copy and paste below code in chrome console and hit enter
(function(console){
console.save = function(data, filename){
if(!data) {
console.error('Console.save: No data')
return;
}
if(!filename) filename = 'console.json'
if(typeof data === "object"){
data = JSON.stringify(data, undefined, 4)
}
var blob = new Blob([data], {type: 'text/json'}),
e = document.createEvent('MouseEvents'),
a = document.createElement('a')
a.download = filename
a.href = window.URL.createObjectURL(blob)
a.dataset.downloadurl = ['text/json', a.download, a.href].join(':')
e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
a.dispatchEvent(e)
}
})(console)
Then you can use the function for downloading,
console.save(temp1);
-If it shows Uncaught TypeError: Converting circular structure to JSON
then you need decycle JSON object and paste below code in chrome browser console and hit enter
if (typeof JSON.decycle !== "function") {
JSON.decycle = function decycle(object, replacer) {
"use strict";
var objects = new WeakMap(); // object to path mappings
return (function derez(value, path) {
var old_path;
var nu;
if (replacer !== undefined) {
value = replacer(value);
}
if (
typeof value === "object" && value !== null &&
!(value instanceof Boolean) &&
!(value instanceof Date) &&
!(value instanceof Number) &&
!(value instanceof RegExp) &&
!(value instanceof String)
) {
old_path = objects.get(value);
if (old_path !== undefined) {
return {$ref: old_path};
}
objects.set(value, path);
if (Array.isArray(value)) {
nu = [];
value.forEach(function (element, i) {
nu[i] = derez(element, path + "[" + i + "]");
});
} else {
nu = {};
Object.keys(value).forEach(function (name) {
nu[name] = derez(
value[name],
path + "[" + JSON.stringify(name) + "]"
);
});
}
return nu;
}
return value;
}(object, "$"));
};
}
if (typeof JSON.retrocycle !== "function") {
JSON.retrocycle = function retrocycle($) {
"use strict";
var px = /^\$(?:\[(?:\d+|"(?:[^\\"\u0000-\u001f]|\\([\\"\/bfnrt]|u[0-9a-zA-Z]{4}))*")\])*$/;
(function rez(value) {
if (value && typeof value === "object") {
if (Array.isArray(value)) {
value.forEach(function (element, i) {
if (typeof element === "object" && element !== null) {
var path = element.$ref;
if (typeof path === "string" && px.test(path)) {
value[i] = eval(path);
} else {
rez(element);
}
}
});
} else {
Object.keys(value).forEach(function (name) {
var item = value[name];
if (typeof item === "object" && item !== null) {
var path = item.$ref;
if (typeof path === "string" && px.test(path)) {
value[name] = eval(path);
} else {
rez(item);
}
}
});
}
}
}($));
return $;
};
}
Then finally execute code for downloading.
console.save(JSON.decycle(temp1));
You can use command in console as follows:
Let say our object is:
var object = {x:"xyz"}
Now use below command in console -
copy(JSON.stringify(object))
object is now available to clipboard.You can now use Ctrl + v to use this object.
You should check thecount object to avoid circular reference, before using copy(JSON.stringify(count)), please see here
there can be many ways to do this. One way could be to do JSON.stringify(yourObject) and then copy the output.
You can also do this without having to write any code. At least with later version of chrome.
When you right click the object you get this context:
But if you left click the line to highlight it, the right click the console line you get this context menu:
The "Save as..." option will create text file (*.log) of everything "as is" currently on the console log. So if you want to see more of the object simply expand it as far as you need.
collapsed example:
let tmpArr = []; tmpArr.push([]); tmpArr[0].push({ some: 'test'}); tmpArr[0].push({ some: 'next'}); console.log(tmpArr);
VM242:1 [Array(2)]0: (2) [{…}, {…}]length: 1[[Prototype]]: Array(0)
undefined
null
null
expanded example:
let tmpArr = []; tmpArr.push([]); tmpArr[0].push({ some: 'test'}); tmpArr[0].push({ some: 'next'}); console.log(tmpArr);
VM242:1 [Array(2)]0: Array(2)0: some: "test"[[Prototype]]: Object1: some: "next"[[Prototype]]: Objectlength: 2[[Prototype]]: Array(0)length: 1[[Prototype]]: Array(0)
undefined
null
null
Related
I am using node.js and as a side project i am creating a module that reads a .json file ,parse it then create directory structure based on object properties & object values.
Object properties(keys) would be the path to itself/to files & object values would be the list of files for that path
i have tried to recurse downwards through the object but i dont know how i extract the path from the inner-most object of each object
Also object would be dynamic as would be created by the user.
var path = 'c:/templates/<angular-app>';
var template = {
//outline of 'angular-app'
src:{
jade:['main.jade'],
scripts:{
modules:{
render:['index.js'],
winodws:['index.js'],
header:['header.js' ,'controller.js'],
SCSS:['index.scss' ,'setup.scss'],
}
}
},
compiled:['angular.js','angular-material.js' ,'fallback.js'],
built:{
frontEnd:[],//if the array is empty then create the path anyways
backEnd:[],
assets:{
fontAwesome:['font-awesome.css'],
img:[],
svg:[]
}
}
}
//desired result...
let out = [
'c:/template name/src/jade/main.jade',
'c:/template name/src/scripts/index.js',
'c:/template name/src/scripts/modules/render/index.js',
'c:/template name/compiled/angular.js',
'c:/template name/compiled/angular-material.js',
'c:/template name/compiled/fallback.js',
'c:/template name/built/frontEnd/',
'c:/template name/built/backEnd/',
//...ect...
];
Here's an example on how you can write this recursively:
var path = 'c:/templates';
var template = {
//outline of 'angular-app'
src: {
jade: ['main.jade'],
scripts: {
modules: {
render: ['index.js'],
winodws: ['index.js'],
header: ['header.js', 'controller.js'],
SCSS: ['index.scss', 'setup.scss'],
}
}
},
compiled: ['angular.js', 'angular-material.js', 'fallback.js'],
built: {
frontEnd: [], //if the array is empty then create the path anyways
backEnd: [],
assets: {
fontAwesome: ['font-awesome.css'],
img: [],
svg: []
}
}
}
function recurse(item, path, result) {
//create default output if not passed-in
result = result || [];
//item is an object, iterate its properties
for (let key in item) {
let value = item[key];
let newPath = path + "/" + key;
if (typeof value === "string") {
//if the property is a string, just append to the result
result.push(newPath + "/" + value);
} else if (Array.isArray(value)) {
//if an array
if (value.length === 0) {
//just the directory name
result.push(newPath + "/");
} else {
//itearate all files
value.forEach(function(arrayItem) {
result.push(newPath + "/" + arrayItem);
});
}
} else {
//this is an object, recursively build results
recurse(value, newPath, result);
}
}
return result;
}
var output = recurse(template, path);
console.log(output);
My solution for this problem would be as follows;
function getPaths(o, root = "", result = []) {
var ok = Object.keys(o);
return ok.reduce((a,k) => { var p = root + k + "/";
typeof o[k] == "object" && o[k] !== null &&
Array.isArray(o[k]) ? o[k].length ? o[k].forEach(f => a.push(p+=f))
: a.push(p)
: getPaths(o[k],p,a);
return a;
},result);
}
var path = 'c:/templates/',
template = {
//outline of 'angular-app'
src:{
jade:['main.jade'],
scripts:{
modules:{
render:['index.js'],
winodws:['index.js'],
header:['header.js' ,'controller.js'],
SCSS:['index.scss' ,'setup.scss'],
}
}
},
compiled:['angular.js','angular-material.js' ,'fallback.js'],
built:{
frontEnd:[],//if the array is empty then create the path anyways
backEnd:[],
assets:{
fontAwesome:['font-awesome.css'],
img:[],
svg:[]
}
}
},
paths = getPaths(template,path);
console.log(paths);
It's just one simple function called getPaths Actually it has a pretty basic recursive run. If your object is well structured (do not include any properties other than objects and arrays and no null values) you may even drop the typeof o[k] == "object" && o[k] !== null && line too. Sorry for my unorthodox indenting style but this is how i find to deal with the code more easy when doing ternaries, logical shortcuts and array methods with ES6 arrow callbacks.
I'm using the very simple Refify npm module to handle circular structure JSON. It stringifies a circular structure JSON object in Node.js to then send to the client. My Angular frontend receives the stringified JSON and needs to call the parse method of refify to convert it back to a usable object.
How do I include the refify node module in my Angular frontend so I can reference refify?
Backend usage looks like so:
var refify = require("refify");
app.get("/api/entries, function(req, res){
var circularJSON = //a circular JSON object
res.send(refify.stringify(circularJSON));
});
The frontend reference would look like this:
$http.get("/api/entries").success(function(data){
$scope.entries = refify.parse(data);
});
You can either use browserify as a build step, or you could use wzrd.in CDN, which is a CDN for npm modules.
browserify as a build step
Use node-style require() to organize your browser code and load modules installed by npm. Browserify will recursively analyze all the require() calls in your app in order to build a bundle you can serve up to the browser in a single <script> tag. For more information, and examples, click here.
wzrd.in CDN
<script src="https://wzrd.in/standalone/refify#latest"></script>
<script>
window.refify // You can use refify now!
</script>
You can go to https://wzrd.in/standalone/refify#latest, copy the code, and paste it into your own file if you want. See jsfiddle here.
Here is the forked version of Refify you can use in node.js as well as browsers.
Forked Refify
You can simply download the index.js and include it in your AngularJS application. and use it.
see the below code, I have added the whole forked index.js file in snippet and example at the end.
(function(obj) {
if (typeof exports === 'undefined') {
obj.refify = refify;
} else {
module.exports = refify;
}
function refify(obj) {
var objs = [];
var paths = []
var keyStack = [];
var objStack = [];
return walk(obj);
function walk(it) {
if (typeof it !== 'object') {
return it;
}
objs.push(it);
paths.push(keyStack.slice())
objStack.push(it)
var copy = initCopy(it);
for (var k in it) {
keyStack.push(k);
var v = it[k];
var i = objs.indexOf(v);
if (i == -1) {
copy[k] = walk(v)
} else {
var $ref = '#/' + paths[i].join('/');
copy[k] = {
$ref: $ref
};
}
keyStack.pop();
}
objStack.pop();
return copy;
}
}
refify.parse = function(it) {
if (typeof it !== 'object') it = JSON.parse(it);
var keyStack = [];
var copy = initCopy(it);
walk(it);
return copy;
function walk(obj) {
if (typeof obj !== 'object') {
set(copy, keyStack.slice(), obj);
return;
}
for (var k in obj) {
keyStack.push(k);
var current = obj[k];
var objPath = parseRef(current);
while (objPath) {
current = get(copy, objPath);
objPath = parseRef(current);
}
if (current === obj[k]) {
// We did *not* follow a reference
set(copy, keyStack.slice(), initCopy(current));
walk(current);
} else {
// We *did* follow a reference
set(copy, keyStack.slice(), current);
}
keyStack.pop();
}
}
}
refify.stringify = function(obj, replacer, spaces) {
return JSON.stringify(refify(obj), replacer, spaces)
}
function parseRef(value) {
if (typeof value !== 'object') return false;
if (!value.$ref) return false;
var path = value.$ref == '#/' ? [] : value.$ref.split('/').slice(1);
return path
}
function get(obj, path) {
if (!path.length) return obj;
if (typeof obj !== 'object') return;
var next = obj[path.shift()];
return get(next, path);
}
refify.set = set;
function set(obj, path, value) {
if (path.length === 0) throw new Error("Cannot replace root object");
var key = path.shift();
if (!path.length) {
obj[key] = value;
return;
}
switch (typeof obj[key]) {
case 'undefined':
obj[key] = isNaN(parseInt(key, 10)) ? {} : [];
break;
case 'object':
break;
default:
throw new Error("Tried to set property " + key + " of non-object " + obj[key]);
}
set(obj[key], path, value);
}
function initCopy(obj) {
if (typeof obj !== 'object') return obj;
return Array.isArray(obj) ? [] : {}
}
}(this));
// Example with forked version
var obj = {
inside: {
name: 'Stackoverflow',
id: '98776'
}
};
obj.inside.parent = obj;
var refifyObject= refify(obj);
document.getElementById("out").innerHTML = JSON.stringify(refifyObject);
<div id="out"></div>
if you want use module in browser, you can use Commonjs and AMD
for example :
requirejs.org
browserify
commonjs.org
systemjs
you can convert refify to module ( browserify ,requirejs,commonjs,...) and use.
Useful Links :
create module in RequireJS
writing modular js/
Often in a response from a remote API call, I receive nested objects:
var response = {
data : {
users : [
{
name : 'Mr. White'
}
]
}
}
I want to check whether the first user's name is 'Mr. White', and would naturally want to write something like.
var existed = response.data.users[0].name === 'Mr. White'
However I cannot be sure if all the objects are present, so to avoid exceptions instead I end up writing:
var existed = response && response.data && response.data.users && response.data.users[0].name === 'Mr. White'
Is there a nicer way to do this? Another ugly option that comes to mind is:
var existed = false;
try {
var existed = response.data.users[0].name === 'Mr. White';
} catch(e) { }
In addition to vanilla javascript, I usually have underscore.js and jquery available too.
Edit:
Oops, noticed I asked a dupe of javascript test for existence of nested object key.
An interesting option based on those answers is:
var existed = (((response || {}).data || {}).users || [{}])[0].name === 'Mr. White';
You could hide this naughty try/catch block inside a function like this one :
function resolve(root, path){
try {
return (new Function(
'root', 'return root.' + path + ';'
))(root);
} catch (e) {}
}
var tree = { level1: [{ key: 'value' }] };
resolve(tree, 'level1[0].key'); // "value"
resolve(tree, 'level1[1].key'); // undefined
More on this : https://stackoverflow.com/a/18381564/1636522
I would use the try catch approach but wrap it in a function to hide the ugliness.
Instead of a try/catch, this should be done via checking whether each level in the object is defined or not.
go for
if(typeof(response)!="undefined"
&& typeof(response.data)!="undefined"
&& typeof(response.data.users)!="undefined"
&& typeof(response.data.users[0])!="undefined"
&& typeof(response.data.users[0].name)!="undefined"
) {
//executes only if response.data.users[0].name is existing
}
Here is a function which I used in one of my projects http://jsfiddle.net/JBBAJ/
var object = {
data: {
users: [
{
firstName: "White"
},
{
firstName: "Black"
}
]
}
}
var read = function(path, obj) {
var path = path.split(".");
var item = path.shift();
if(item.indexOf("]") == item.length-1) {
// array
item = item.split("[");
var arrayName = item.shift();
var arrayIndex = parseInt(item.shift().replace("]", ""));
var arr = obj[arrayName || ""];
if(arr && arr[arrayIndex]) {
return read(path.join("."), arr[arrayIndex]);
} else {
return null;
}
} else {
// object
if(obj[item]) {
if(path.length === 0) {
return obj[item];
} else {
return read(path.join("."), obj[item]);
}
} else {
return null;
}
}
}
console.log(read("data.users[0].firstName", object)); // White
console.log(read("data.users[1].firstName", object)); // Black
console.log(read("data.test.users[0]", object)); // null
The idea is to pass your path as a string along with your object. The idea was to prevent the throwing of an exception and receive just null as result of the path is wrong. The good thing is that the function works with every path and you don't need to write long if statements.
I am aware that IDBObjectStore.getAll is not part of the IndexedDB standard and that it might never be. But it is implemented in FireFox, and it makes your code prettier if you do have to retrieve a lot of objects from the database.
Would it be possible to make some kind of polyfill or something to allow getAll to work in other browsers that support IndexedDB? The actual functionality of getAll is simple, but I don't know how to deal with the asynchronous nature of IndexedDB in the context of replicating its precise syntax in non-Firefox browsers.
I made a GitHub repo for a shim to support getAll in other browsers, which seems to work well enough in Chrome. The code is repeated below for posterity:
(function () {
"use strict";
var Event, getAll, IDBIndex, IDBObjectStore, IDBRequest;
IDBObjectStore = window.IDBObjectStore || window.webkitIDBObjectStore || window.mozIDBObjectStore || window.msIDBObjectStore;
IDBIndex = window.IDBIndex || window.webkitIDBIndex || window.mozIDBIndex || window.msIDBIndex;
if (typeof IDBObjectStore.prototype.getAll !== "undefined" && typeof IDBIndex.prototype.getAll !== "undefined") {
return;
}
// https://github.com/axemclion/IndexedDBShim/blob/gh-pages/src/IDBRequest.js
IDBRequest = function () {
this.onsuccess = null;
this.readyState = "pending";
};
// https://github.com/axemclion/IndexedDBShim/blob/gh-pages/src/Event.js
Event = function (type, debug) {
return {
"type": type,
debug: debug,
bubbles: false,
cancelable: false,
eventPhase: 0,
timeStamp: new Date()
};
};
getAll = function (key) {
var request, result;
key = typeof key !== "undefined" ? key : null;
request = new IDBRequest();
result = [];
// this is either an IDBObjectStore or an IDBIndex, depending on the context.
this.openCursor(key).onsuccess = function (event) {
var cursor, e, target;
cursor = event.target.result;
if (cursor) {
result.push(cursor.value);
cursor.continue();
} else {
if (typeof request.onsuccess === "function") {
e = new Event("success");
e.target = {
readyState: "done",
result: result
};
request.onsuccess(e);
}
}
};
return request;
};
if (typeof IDBObjectStore.prototype.getAll === "undefined") {
IDBObjectStore.prototype.getAll = getAll;
}
if (typeof IDBIndex.prototype.getAll === "undefined") {
IDBIndex.prototype.getAll = getAll;
}
}());
I'm creating a page to help diagnose the problem our users are experiencing with our web pages (you know, asking a user "What browser are you using?" usually leads to "Internet").
This page already submits to me all the HTTP headers and now I'm trying to have JavaScript give some more informations, so I thought it would be great to have the user's navigator JavaScript object and I started looking how to serialize it so I can submit it through a form.
The problem is I'm not able to serialize the navigator object using any JSON library I know of, everyone returns an empty object (?!), so I decided to write an ad-hoc serializer.
You can find the code here:
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
function serialize (object) {
var type = typeof object;
if (object === null) {
return '"nullValue"';
}
if (type == 'string' || type === 'number' || type === 'boolean') {
return '"' + object + '"';
}
else if (type === 'function') {
return '"functionValue"';
}
else if (type === 'object') {
var output = '{';
for (var item in object) {
if (item !== 'enabledPlugin') {
output += '"' + item + '":' + serialize(object[item]) + ',';
}
}
return output.replace(/\,$/, '') + '}';
}
else if (type === 'undefined') {
return '"undefinedError"';
}
else {
return '"unknownTypeError"';
}
};
$(document).ready(function () {
$('#navigator').text(serialize(navigator));
});
</script>
<style type="text/css">
#navigator {
font-family: monospaced;
}
</style>
<title>Serialize</title>
</head>
<body>
<h1>Serialize</h1>
<p id="navigator"></p>
</body>
</html>
This code seems to work perfectly in Firefox, Opera, Chrome and Safari but (obviously) doesn't work in Internet Explorer (at least version 8.0), it complains that "Property or method not supported by the object" at line for (var item in object) {.
Do you have any hint on how to fix the code or how to reach the goal (serialize the navigator object) by other means?
Solution (v 2.0):
Replace
for (var item in object) {
if (item !== 'enabledPlugin') {
output += '"' + item + '":' + serialize(object[item]) + ',';
}
}
with
for (var item in object) {
try {
if (item !== 'enabledPlugin') {
output += '"' + item + '":' + serialize(object[item]) + ',';
}
}
catch (e) {
}
}
and it works.
Try putting it inside a new object
var _navigator = {};
for (var i in navigator) _navigator[i] = navigator[i];
And then serialize it (maybe using some JSON library if the browser doesn't have native JSON API, I use json2.js):
$('#navigator').text(JSON.stringify(_navigator));
Edit: It seems that Internet Explorer doesn't allow navigator.plugins and navigator.mimeTypes to be iterated over, so this works:
var _navigator = {};
for (var i in navigator) _navigator[i] = navigator[i];
delete _navigator.plugins;
delete _navigator.mimeTypes;
$('#navigator').text(JSON.stringify(_navigator));
JSON in accepted answer contains only top level elements. Check this out https://jsfiddle.net/j1zb7qm0/ - _navigator.connection is empty. I've wrote a small func to collect all nested properties:
function recur(obj) {
var result = {}, _tmp;
for (var i in obj) {
// enabledPlugin is too nested, also skip functions
if (i === 'enabledPlugin' || typeof obj[i] === 'function') {
continue;
} else if (typeof obj[i] === 'object') {
// get props recursively
_tmp = recur(obj[i]);
// if object is not {}
if (Object.keys(_tmp).length) {
result[i] = _tmp;
}
} else {
// string, number or boolean
result[i] = obj[i];
}
}
return result;
}
You can use it like this var _navigator = recur(navigator) or create your own wrapper. In fact you can use it to iterate over and copy any nested object.