Setting JSON node name to variable value - javascript

I've spent most of my time in languages like Java and C++ but I'm trying to pick up JavaScript. What I'm attempting to accomplish is a way to set the parent node name by the value of the variable passed. I am using Firebase if that makes a difference in this code but I didn't think it would.
var parent_node_name = "EPLU200";
var onComplete = function(error) {
if (error) {
console.log('Synchronization failed');
} else {
console.log('Synchronization succeeded');
}
};
// update adds the data without replacing all of the other nodes
myFirebaseRef.update({
parent_node_name: { // trying to change this part to not save as "parent_node_name"
id2: "1175", // but instead as "EPLU200"
...
}
}, onComplete);
The action saves to my Firebase server just fine but the problem is passing the actual value of the variable instead of reading the variable name.
Is there any workaround in JavaScript? I tried searching for it but I didn't know what to call it.

Depending on the environment (i.e node?)
myFirebaseRef.update({
[parent_node_name]: {
id2: "1175",
...
}
}, onComplete);
See the code commented as Computed property names (ES6) in New Notations in ES2015 doumentation at MDN
if that doesn't work, you have to do this
var obj = {};
obj[parent_node_name] = {
id2: "1175",
...
};
myFirebaseRef.update(obj, onComplete);

Related

Dexie.js delete one item with id not working

Hi this my simple project js code example
const deleteOneNote = (id) => {
const db = openNoteDb();
db.notes.where('id').equals(id).delete();
}
$(document).on("click", ".remove_note", function () {
const id = $(this).parent().parent().attr("id");
const db = openNoteDb();
db.notes.where('id').above(-1).modify(result => {
if (result.id == id) {
deleteOneNote(result.id);
window.location.reload(true)
}
})
})
But my delete function not working I am dont understand Please help me..
First of all, your function deleteOneNote() must return the promise from db.transaction() so you can wait for the delete to complete. Alternatively make the function async and await the promise returned by db.transaction(). Whatever you choose, the caller of your function must also await your function before testing if the delete was successful or not.
Then, I also see a common problem on the code, which is that the Dexie instance is created on-demand, which would lead to memory leak unless you close it when done. Instead, declare db on top-level so it will live throwout your entire application life time and let you functions use that same db instance everywhere.
A third common mistake (which might not be this cause though) is that people supply a string when the key was stored as a number, or vice versa. Make sure that the id supplied to your function is off the same type as in the object you want to delete.
// Declare one single Dexie instance in your entire application
// and use it from all functions.
const db = new Dexie("NotesDB");
// If you use modules, keep this code in a module and
// add an 'export' before 'const db = new Dexie("NotesDB");
db.version(1).stores({
notes: `
id,
time,
note,
noteBackColor,
noteTextColor,
projectType,
alarm`,
});
// Let you functions use the singleton Dexie instance:
const deleteOneNote = (id) => {
return db.transaction('rw', db.notes, function () {
// Note: Doing this in a transaction is over-kill, but ok.
return db.notes.delete(id);
}).catch((err) => {
console.log(err);
throw err; // Also, you probably want to rethrow the error...
});
}
Now, these are code recommendations from Dexie's best-practices section and not nescessarily reason for why your code fails to delete an item.
A more interesting thing is:
What's the value of the "id" property in your database of the object that you want to delete? I assume your object looks something like{id: "x", time: "y", ...}.
What argument do you pass to your function? If the object you are deleting looks like described in previous bullet, the value of the id argument must be exactly the string "x" - not the object and not an array or any other type - a string with the exact value "x".
A working test for this code would be:
const foo = {id: "x", time: "y"};
db.notes.put(foo).then(async () => {
if (await db.notes.get("x")) {
console.log("My object is there!");
} else {
console.log("My object is not there!");
}
console.log("Now deleting it...");
await deleteOneNote("x");
if (await db.notes.get("x")) {
console.log("My object is there!");
} else {
console.log("My object is not there!");
}
}).catch(console.error);
The result from running this test should be:
My object is there!
Now deleting it...
My object is not there!

How to include or detect the name of a new Object when it's created from a Constructor

I have a constructor that include a debug/log code and also a self destruct method
I tried to find info on internet about how to detect the new objects names in the process of creation, but the only recommendation that I found was pass the name as a property.
for example
var counter = {}
counter.a =new TimerFlex({debug: true, timerId:'counter.a'});
I found unnecessary to pass counter.a as a timerId:'counter.a' there should be a native way to detect the name from the Constructor or from the new object instance.
I am looking for something like ObjectProperties('name') that returns counter.a so I don't need to include it manually as a property.
Adding more info
#CertainPerformance What I need is to differentiate different objects running in parallel or nested, so I can see in the console.
counter.a data...
counter.b data...
counter.a data...
counter.c data... etc
also these objects have only a unique name, no reference as counter.a = counter.c
Another feature or TimerFlex is a method to self desruct
this.purgeCount = function(manualId) {
if (!this.timerId && manualId) {
this.timerId = manualId;
this.txtId = manualId;
}
if (this.timerId) {
clearTimeout(this.t);
this.timer_is_on = 0;
setTimeout ( ()=> { console.log(this.txtId + " Destructed" ) },500);
setTimeout ( this.timerId +".__proto__ = null", 1000);
setTimeout ( this.timerId +" = null",1100);
setTimeout ( "delete " + this.timerId, 1200);
} else {
if (this.debug) console.log("timerId is undefined, unable to purge automatically");
}
}
While I don't have a demo yet of this Constructor this is related to my previous question How to have the same Javascript Self Invoking Function Pattern running more that one time in paralel without overwriting values?
Objects don't have names - but constructors!
Javascript objects are memory references when accessed via a variables. The object is created in the memory and any number of variables can point to that address.
Look at the following example
var anObjectReference = new Object();
anObjectReference.name = 'My Object'
var anotherReference = anObjectReference;
console.log(anotherReference.name); //Expected output "My Object"
In this above scenario, it is illogical for the object to return anObjectReference or anotherReference when called the hypothetical method which would return the variable name.
Which one.... really?
In this context, if you want to condition the method execution based on the variable which accesses the object, have an argument passed to indicate the variable (or the scenario) to a method you call.
In JavaScript, you can access an object instance's properties through the same notation as a dictionary. For example: counter['a'].
If your intent is to use counter.a within your new TimerFlex instance, why not just pass counter?
counter.a = new TimerFlex({debug: true, timerId: counter});
// Somewhere within the logic of TimerFlex...
// var a = counter.a;
This is definitely possible but is a bit ugly for obvious reasons. Needless to say, you must try to avoid such code.
However, I think this can have some application in debugging. My solution makes use of the ability to get the line number for a code using Error object and then reading the source file to get the identifier.
let fs = require('fs');
class Foo {
constructor(bar, lineAndFile) {
this.bar = bar;
this.lineAndFile = lineAndFile;
}
toString() {
return `${this.bar} ${this.lineAndFile}`
}
}
let foo = new Foo(5, getLineAndFile());
console.log(foo.toString()); // 5 /Users/XXX/XXX/temp.js:11:22
readIdentifierFromFile(foo.lineAndFile); // let foo
function getErrorObject(){
try { throw Error('') } catch(err) { return err; }
}
function getLineAndFile() {
let err = getErrorObject();
let callerLine = err.stack.split("\n")[4];
let index = callerLine.indexOf("(");
return callerLine.slice(index+1, callerLine.length-1);
}
function readIdentifierFromFile(lineAndFile) {
let file = lineAndFile.split(':')[0];
let line = lineAndFile.split(':')[1];
fs.readFile(file, 'utf-8', (err, data) => {
if (err) throw err;
console.log(data.split('\n')[parseInt(line)-1].split('=')[0].trim());
})
}
If you want to store the variable name with the Object reference, you can read the file synchronously once and then parse it to get the identifier from the required line number whenever required.

Passing metadata between functions

I created an API with Node.js, and I don't want the API to change nor do I want to add extra parameters to a function. However, the internal code in the library needs to now send some metadata between an internal API method and an external facing method.
Is there a way to pass (meta) data between functions somehow in JS that does not involve parameters/arguments?
TL;DR, it would be really useful to pass metadata between functions for the purposes of JS APIs, that should not change signatures.
(One trick is if the function is created everytime it is called, you can assign data onto the function object itself, but that is not true in this case (function is not being created everytime it is called).)
The trick I am currently using - and it is not a good one - there is an options {} object being used in the API. I am passing a hidden property in that objects object "__preParsed". The user will use that objects object as they normally would, behind the scenes I use it for some bookkeeping stuff that they don't need to know about.
Ok here is the code:
//public API
beforeEach.cb = function (desc, opts, fn) {
const _args = pragmatik.parse(arguments, rules.hookSignature);
_args[ 1 ].cb = true;
return beforeEach.apply(ctx, _args);
};
beforeEach = function (desc, opts, aBeforeEach) {
handleSetupComplete(zuite);
const _args = pragmatik.parse(arguments, rules.hookSignature);
const obj = { //have to do this until destructuring works
desc: _args[ 0 ],
opts: _args[ 1 ],
fn: _args[ 2 ]
};
handleBadOptionsForEachHook(obj.opts, zuite);
return 'there is more code but I omitted it';
};
as you can see the first method calls the second, or the second can be called directly, both are public APIs.
We need to parse the arguments in both calls, but as an optimization, we shouldn't have to parse them a second time if the second method was called by the first instead of directly.
The solution I will use for the moment is:
beforeEach.cb = function (desc, opts, fn) {
const _args = pragmatik.parse(arguments, rules.hookSignature);
_args[ 1 ].cb = true;
_args[ 1 ].__preParsed = true;
return beforeEach.apply(ctx, _args);
};
the opts options object is public, but the user won't know about the __preParsed property. The internal API will.
The problem with this is that the user can call the public API directly without an options object, and since the signature is very much varargs, then I really don't know until I have parsed it with my parse engine, which arg if any is the objects object!
You could abuse the this object to carry non-argument metadata in as follows by invoking your function using Function.prototype.call:
function inner (arg1, arg2) {
console.log('inner called with', arg1, arg2)
console.log('inner metadata', this._meta_count)
}
inner.call({_meta_count: 17}, 'ARG ONE', 'ARG TWO')
inner.call({_meta_count: 18}, 'ARG ONE B', 'ARG TWO B')
You could just add a new undocumented parameter to the end. JavaScript won't care and previous calls will still work, why is that a problem for you?
If you are checking parameter count and throwing errors, you could expect the hidden parameter to be an object with a magic property, if it's not, throw the error.
function go(a, b, c, _internal) {
if (_internal && ! _internal.hasOwnProperty('_magic')) {
throw new Error('invalid internal parameter passed');
}
}
You can get a little more paranoid and store the magic property as a Symbol, then the caller couldn't pass it by accident, they would have to be acting nefariously.
function go(a, b, c, _internal) {
if (_internal && !_internal.hasOwnProperty(go.internalParamProp)) {
throw new Error('invalid internal parameter passed');
}
console.log("Internal param", _internal && _internal[go.internalParamProp])
}
// Symbol for the magic property name to avoid accidental passing of internal param
go.internalParamProp = Symbol('');
// Passing the internal param
// Uses JS syntax that is not yet supported in some browsers
// If it's a concern, use or var obj={}; obj[go.internalParamProp] = 45
go(1, 2, 3, {
[go.internalParamProp]: 45
})
// Regular call
go(1, 2, 3)
// Invalid call
go(1, 2, 3, 4)

js get set with dynamic variables in node-opcua

Examples on node-opcua # https://github.com/node-opcua/node-opcua say that I need to rewrite code for every variable added to the OPC server, this is achieved calling 'addressSpace.addVariable()'... But if I have 1000 variables it could be an hard task... and eventually each custom user want a code rewrite, it could be tedious... so I'm trying to do it dynamically.
The opc read 'tags' from another custom server (not OPC).
With this 'tags' the opc server needs to add them to node 'device'.
When the OPC server node-opcua find a get or set of a variable coming from the net, it call the get or set of the correct variable:
for (var i = 0; i < tags.GetTags.length; i++)
{
variables[tags.GetTags[i].Tag] = {"value" : 0.0, "is_set" : false};
addressSpace.addVariable({
componentOf: device, // Parent node
browseName: tags.GetTags[i].Tag, // Variable name
dataType: "Double", // Type
value: {
get: function () {
//console.log(Object.getOwnPropertyNames(this));
return new opcua.Variant({dataType: opcua.DataType.Double, value: variables[this["browseName"]].value }); // WORKS
},
set: function (variant) {
//console.log(Object.getOwnPropertyNames(this));
variables[this["browseName"]].value = parseFloat(variant.value); // this["browseName"] = UNDEFINED!!!
variables[this["browseName"]].is_set = true;
return opcua.StatusCodes.Good;
}
}
});
console.log(tags.GetTags[i].Tag);
}
As I say I tried to use the 'this' in get and set functions with half luck, the get has a 'this.browseName' (the tag name) property that can be used to dynamic read my variables and it currently works.
The problem is with the set, in set 'this.browseName' and 'this.nodeId' don't exist! So it gives 'undefined' error. It also doesn't exist in variant variable.
Do you know a work-around to use dynamic variables with the above code? I need to have one for loop with one get and one set definitions for all variables (tags), that read and write a multi-property object or an array of objects, like 1 get and 1 set definitions that write the right variable in a n records array.
PS: I found on stack overflow this:
var foo = {
a: 5,
b: 6,
init: function() {
this.c = this.a + this.b;
return this;
}
}
But in my case node-opcua Variable doesn't has a 'this' working like the example. In the 'set' (like init): this.browseName (like a) and this.nodeId (like b) are not reachable.
Gotcha,
you need to cast get and set properties as functions like:
addressSpace.addVariable({
componentOf: device,
browseName: _vars[i].Tag,
dataType: "Double",
value: {
get: CastGetter(i),
set: CastSetter(i)
}
});
with
function CastGetter(index) {
return function() {
return new opcua.Variant({dataType: opcua.DataType.Double, value: opc_vars[index].Value });
};
}
function CastSetter(index) {
return function (variant) {
opc_vars[index].Value = parseFloat(variant.value);
opc_vars[index].IsSet = true;
return opcua.StatusCodes.Good;
};
}
you will use an index to get and set values in the array, casting function like this will provide index to be "hard coded" in those get and set properties.

chrome.storage.sync.set not saving values

So I've run into a bit of snag with regards to local storage on Google Chrome. From what I've researched, my syntax seems to be correct, but for some reason the value is not being saved. Here's my code:
chrome.storage.sync.get(accName, function(data) {
var accData = data[accName];
// Stuff
chrome.storage.sync.set({ accName: accData }, function() {
alert('Data saved');
});
});
Every time I re-run it, data[accName] returns undefined. I've tried the same code with literal values for the sync.set parameters (eg. { 'john32': ['fk35kd'] }), and that seems to work, so I'm really confused as to what the issue could be. Any help would be appreciated.
The issue was trying to plug accName into an object literal inside the set statement (credit to Rob above). What I'd end up with was an object with a property 'accName' rather than the value of accName itself. Here's a fix.
var obj = {};
obj[accName] = accData;
chrome.storage.sync.set(obj, function() {
alert('Data saved');
});
Update
ES6 now allows computed property names in object literals, so the above can be achieved with:
chrome.storage.sync.set({ [accName]: accData }, function() {
alert('Data saved');
});

Categories

Resources