Is it possible to pass JSON object to ejs renderFile? - node.js

I'd rather not have to type out each field name of my ejs file. Here is what i'd like to do:
let html = null;
EJS.renderFile('./public/views/results.ejs', {JSON_OBJECT}, (err, str) => {
html = str;
});

Something encapsulated in {} will create a new object.
So in
var JSON_OBJECT = {test: "value"};
var obj2 = {JSON_OBJECT}
obj2 will be an object with a property named JSON_OBJECT, which in itself has a property test.
EJS.renderFile accepts a JSON object as its second parameter. The properties the object can contain are described in the package description of ejs.

Related

Compact way to assign nested property to root of a new object

I'm wondering if there's a compact way to pull a property from an object, and then assign said property to the root of a new object, using the same property name.
Basically, I'd like to do the following without needing the first line:
const targetProp = someObj.data.targetProp;
const newObj = {
targetProp
}
What I'd imagine it might look like:
const newObj = {
[someObj.data.targetProp]
}
Where newObj would then have a property named 'targetProp', with the value of someObj.data.targetProp
There's no need for an extra variable:
const newObj = {
targetProp: someObj.data.targetProp
}
Destructuring is an option, which will reduce the size of the original code, but that requires keeping a first line:
const { targetProp } = someObj.data;
const newObj = { targetProp };
I don't think there's anything better than these two options.

Argument "data" is not a valid Document. Input is not a plain JavaScript object

I am getting below error .
Error: Argument "data" is not a valid Document. Input is not a plain JavaScript object.
at Object.exports.(anonymous function) [as isDocument] (/user_code/node_modules/firebase-admin/node_modules/#google-cloud/firestore/src/validate.js:86:15)
at WriteBatch.set (/user_code/node_modules/firebase-admin/node_modules/#google-cloud/firestore/src/write-batch.js:286:14)
at DocumentReference.set (/user_code/node_modules/firebase-admin/node_modules/#google-cloud/firestore/src/reference.js:420:8)
at PainEntryService.createEntry (/user_code/services/entry-service.js:19:30)
at /user_code/services/intentService.js:22:36
at Function.<anonymous> (/user_code/node_modules/actions-on-google/dist/service/dialogflow/dialogflow.js:146:23)
at next (native)
at /user_code/node_modules/actions-on-google/dist/service/dialogflow/dialogflow.js:22:71
at __awaiter (/user_code/node_modules/actions-on-google/dist/service/dialogflow/dialogflow.js:18:12)
at Function.handler (/user_code/node_modules/actions-on-google/dist/service/dialogflow/dialogflow.js:84:16)
I am using below code for creating the document
var docRef = this.dbManager.collection('tetst).doc(subjectId);
var setAlan = docRef.set(EntryEntity.toJSON);
I have below code in the toJSON method
public toJSON(): testEntry {
let returnJSON = {
"entry_id": this.entry_id,
"subject_id": this.subject_id,
"entry_date": this.entry_date,
"questionnaire": this.questionnaire,
"entry_start_timestamp": this.entry_start_timestamp,
"entry_end_timestamp": this.entry_end_timestamp,
"entry_complete": this.entry_complete,
//"responses": this.responses,
"last_answered_question" : this.last_answered_question,
"entry_status" : this.entry_status
}
return returnJSON;
}
I am framing json object in the above method. If i print the json object, i am getting below content
{ entry_id: 'df2b4ad4-6a70-4304-a71f-3a63773ada61',
subject_id: 'ABwppHHkzfY1Whp-lCHNnvEcuqvsbMKtZsg_ui9vc4jtpXSiAbh0fNsg6LxGkYq-Va3SOrwcvD-HAs7VQA',
entry_date: '2018-06-15',
questionnaire: 1,
entry_start_timestamp: '2018-06-15T09:38:10.266Z',
entry_end_timestamp: '2018-06-15T09:38:10.266Z',
entry_complete: false,
last_answered_question: 0,
entry_status: 'active' }
How to solve above issue? is there any issue with json object?
You need to call the toJSON method. Currently you are passing a reference to a method to set when you need to pass the return value of the called method.
Change
var setAlan = docRef.set(EntryEntity.toJSON);
to
var setAlan = docRef.set(EntryEntity.toJSON());

How to use dynamic variable name in nodejs

I need a dynamic variable in nodejs .
I use the allocine-api, and she return, a different object when I use it . For example :
allocine.api(type, {code: code}, function(error, result) {
if(error){
console.log('Error : '+ error);
return;
}
socket.emit("allocine_"+type ,result);
});
if type is "movie", result contain a movie object, but if type is "tvseries", result contain a tvseries object. So I need to take the variable "originalTitle" in "tvseries" or "movie" object, so I need to make this :
result.<type>.originalTitle
But, how to use the contain of "type" for this ?
I have try with the javascript method, and the use of "window['type']", but it's don't work in nodeJs .
as javascript objects elements can be accessed as an associative array ( cf mozilla js doc )
using myobject.myproperties is strictly equal to use myobject["myproperties"]
so if a var hold the properties name to read var myvar = "myproperties"; you could also use myobject[myvar]
so, concretely :
var o = {
tvseries : {
originalTitle : "hello world"
}
}, type = "tvseries";
console.log( o[type].originalTitle );
jsfiddle
also, if the result object get only one sub object, named by the type, you can get type name directly from it
var type = Object.keys( myobject )[0];
jsfiddle
or more simply :
var theTitle = myobject[ Object.keys( myobject )[0] ].originalTitle;
jsfiddle
var results = {};
results.a = {originalTitle: "One"};
var results2 = {b:{originalTitle: "Two"}};
console.log(results['a'].originalTitle); //now one
console.log(results2['b'].originalTitle); //now Two
With two ways of creating the object.
Try the fiddle:
http://jsfiddle.net/rmoskal/6rf0juq6/

FabricJs - How do I Add properties to each object

I need to introduce few additional properties to existing object properties set.
like:
ID
Geo Location
etc
Whenever I draw a shape, I need to add additional properties to the shape and need to get from toDataLessJSON()
As of version 1.7.0 levon's code stopped working. All you need to do is to fix as follows:
// Save additional attributes in Serialization
fabric.Object.prototype.toObject = (function (toObject) {
return function (properties) {
return fabric.util.object.extend(toObject.call(this, properties), {
textID: this.textID
});
};
})(fabric.Object.prototype.toObject);
You have to receive properties argument and pass it on to toObject.
Here's a code for adding custom properties and saving them in JSON serialization for any object on canvas. (I used standard javascript object properties, but it works for me)
canvas.myImages = {};
fabric.Image.fromURL('SOME-IMAGE-URL.jpg', function(img) {
canvas.myImages.push(img);
var i = canvas.myImages.length-1;
canvas.myImages[i].ID = 1; // add your custom attributes
canvas.myImages[i].GeoLocation = [40, 40];
canvas.add(canvas.myImages[i]);
canvas.renderAll();
});
And you then include the custom attribute in object serialization.
// Save additional attributes in Serialization
fabric.Object.prototype.toObject = (function (toObject) {
return function () {
return fabric.util.object.extend(toObject.call(this), {
textID: this.textID
});
};
})(fabric.Object.prototype.toObject);
// Test Serialization
var json = JSON.stringify(canvas.toDatalessJSON());
console.log(json);
canvas.clear();
// and load everything from the same json
canvas.loadFromDatalessJSON(json, function() {
// making sure to render canvas at the end
canvas.renderAll();
}

Object.defineProperty on any property [duplicate]

I am aware of how to create getters and setters for properties whose names one already knows, by doing something like this:
// A trivial example:
function MyObject(val){
this.count = 0;
this.value = val;
}
MyObject.prototype = {
get value(){
return this.count < 2 ? "Go away" : this._value;
},
set value(val){
this._value = val + (++this.count);
}
};
var a = new MyObject('foo');
alert(a.value); // --> "Go away"
a.value = 'bar';
alert(a.value); // --> "bar2"
Now, my question is, is it possible to define sort of catch-all getters and setters like these? I.e., create getters and setters for any property name which isn't already defined.
The concept is possible in PHP using the __get() and __set() magic methods (see the PHP documentation for information on these), so I'm really asking is there a JavaScript equivalent to these?
Needless to say, I'd ideally like a solution that is cross-browser compatible.
This changed as of the ES2015 (aka "ES6") specification: JavaScript now has proxies. Proxies let you create objects that are true proxies for (facades on) other objects. Here's a simple example that turns any property values that are strings to all caps on retrieval, and returns "missing" instead of undefined for a property that doesn't exist:
"use strict";
if (typeof Proxy == "undefined") {
throw new Error("This browser doesn't support Proxy");
}
let original = {
example: "value",
};
let proxy = new Proxy(original, {
get(target, name, receiver) {
if (Reflect.has(target, name)) {
let rv = Reflect.get(target, name, receiver);
if (typeof rv === "string") {
rv = rv.toUpperCase();
}
return rv;
}
return "missing";
}
});
console.log(`original.example = ${original.example}`); // "original.example = value"
console.log(`proxy.example = ${proxy.example}`); // "proxy.example = VALUE"
console.log(`proxy.unknown = ${proxy.unknown}`); // "proxy.unknown = missing"
original.example = "updated";
console.log(`original.example = ${original.example}`); // "original.example = updated"
console.log(`proxy.example = ${proxy.example}`); // "proxy.example = UPDATED"
Operations you don't override have their default behavior. In the above, all we override is get, but there's a whole list of operations you can hook into.
In the get handler function's arguments list:
target is the object being proxied (original, in our case).
name is (of course) the name of the property being retrieved, which is usually a string but could also be a Symbol.
receiver is the object that should be used as this in the getter function if the property is an accessor rather than a data property. In the normal case this is the proxy or something that inherits from it, but it can be anything since the trap may be triggered by Reflect.get.
This lets you create an object with the catch-all getter and setter feature you want:
"use strict";
if (typeof Proxy == "undefined") {
throw new Error("This browser doesn't support Proxy");
}
let obj = new Proxy({}, {
get(target, name, receiver) {
if (!Reflect.has(target, name)) {
console.log("Getting non-existent property '" + name + "'");
return undefined;
}
return Reflect.get(target, name, receiver);
},
set(target, name, value, receiver) {
if (!Reflect.has(target, name)) {
console.log(`Setting non-existent property '${name}', initial value: ${value}`);
}
return Reflect.set(target, name, value, receiver);
}
});
console.log(`[before] obj.example = ${obj.example}`);
obj.example = "value";
console.log(`[after] obj.example = ${obj.example}`);
The output of the above is:
Getting non-existent property 'example'
[before] obj.example = undefined
Setting non-existent property 'example', initial value: value
[after] obj.example = value
Note how we get the "non-existent" message when we try to retrieve example when it doesn't yet exist, and again when we create it, but not after that.
Answer from 2011 (obsoleted by the above, still relevant to environments limited to ES5 features like Internet Explorer):
No, JavaScript doesn't have a catch-all property feature. The accessor syntax you're using is covered in Section 11.1.5 of the spec, and doesn't offer any wildcard or something like that.
You could, of course, implement a function to do it, but I'm guessing you probably don't want to use f = obj.prop("example"); rather than f = obj.example; and obj.prop("example", value); rather than obj.example = value; (which would be necessary for the function to handle unknown properties).
FWIW, the getter function (I didn't bother with setter logic) would look something like this:
MyObject.prototype.prop = function(propName) {
if (propName in this) {
// This object or its prototype already has this property,
// return the existing value.
return this[propName];
}
// ...Catch-all, deal with undefined property here...
};
But again, I can't imagine you'd really want to do that, because of how it changes how you use the object.
Preface:
T.J. Crowder's answer mentions a Proxy, which will be needed for a catch-all getter/setter for properties which don't exist, as the OP was asking for. Depending on what behavior is actually wanted with dynamic getters/setters, a Proxy may not actually be necessary though; or, potentially, you may want to use a combination of a Proxy with what I'll show you below.
(P.S. I have experimented with Proxy thoroughly in Firefox on Linux recently and have found it to be very capable, but also somewhat confusing/difficult to work with and get right. More importantly, I have also found it to be quite slow (at least in relation to how optimized JavaScript tends to be nowadays) - I'm talking in the realm of deca-multiples slower.)
To implement dynamically created getters and setters specifically, you can use Object.defineProperty() or Object.defineProperties(). This is also quite fast.
The gist is that you can define a getter and/or setter on an object like so:
let obj = {};
let val = 0;
Object.defineProperty(obj, 'prop', { //<- This object is called a "property descriptor".
//Alternatively, use: `get() {}`
get: function() {
return val;
},
//Alternatively, use: `set(newValue) {}`
set: function(newValue) {
val = newValue;
}
});
//Calls the getter function.
console.log(obj.prop);
let copy = obj.prop;
//Etc.
//Calls the setter function.
obj.prop = 10;
++obj.prop;
//Etc.
Several things to note here:
You cannot use the value property in the property descriptor (not shown above) simultaneously with get and/or set; from the docs:
Property descriptors present in objects come in two main flavors: data descriptors and accessor descriptors. A data descriptor is a property that has a value, which may or may not be writable. An accessor descriptor is a property described by a getter-setter pair of functions. A descriptor must be one of these two flavors; it cannot be both.
Thus, you'll note that I created a val property outside of the Object.defineProperty() call/property descriptor. This is standard behavior.
As per the error here, don't set writable to true in the property descriptor if you use get or set.
You might want to consider setting configurable and enumerable, however, depending on what you're after; from the docs:
configurable
true if and only if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object.
Defaults to false.
enumerable
true if and only if this property shows up during enumeration of the properties on the corresponding object.
Defaults to false.
On this note, these may also be of interest:
Object.getOwnPropertyNames(obj): gets all properties of an object, even non-enumerable ones (AFAIK this is the only way to do so!).
Object.getOwnPropertyDescriptor(obj, prop): gets the property descriptor of an object, the object that was passed to Object.defineProperty() above.
obj.propertyIsEnumerable(prop);: for an individual property on a specific object instance, call this function on the object instance to determine whether the specific property is enumerable or not.
The following could be an original approach to this problem:
var obj = {
emptyValue: null,
get: function(prop){
if(typeof this[prop] == "undefined")
return this.emptyValue;
else
return this[prop];
},
set: function(prop,value){
this[prop] = value;
}
}
In order to use it the properties should be passed as strings.
So here is an example of how it works:
//To set a property
obj.set('myProperty','myValue');
//To get a property
var myVar = obj.get('myProperty');
Edit:
An improved, more object-oriented approach based on what I proposed is the following:
function MyObject() {
var emptyValue = null;
var obj = {};
this.get = function(prop){
return (typeof obj[prop] == "undefined") ? emptyValue : obj[prop];
};
this.set = function(prop,value){
obj[prop] = value;
};
}
var newObj = new MyObject();
newObj.set('myProperty','MyValue');
alert(newObj.get('myProperty'));
You can see it working here.
I was looking for something and I figured out on my own.
/*
This function takes an object and converts to a proxy object.
It also takes care of proxying nested objectsa and array.
*/
let getProxy = (original) => {
return new Proxy(original, {
get(target, name, receiver) {
let rv = Reflect.get(target, name, receiver);
return rv;
},
set(target, name, value, receiver) {
// Proxies new objects
if(typeof value === "object"){
value = getProxy(value);
}
return Reflect.set(target, name, value, receiver);
}
})
}
let first = {};
let proxy = getProxy(first);
/*
Here are the tests
*/
proxy.name={} // object
proxy.name.first={} // nested object
proxy.name.first.names=[] // nested array
proxy.name.first.names[0]={first:"vetri"} // nested array with an object
/*
Here are the serialised values
*/
console.log(JSON.stringify(first)) // {"name":{"first":{"names":[{"first":"vetri"}]}}}
console.log(JSON.stringify(proxy)) // {"name":{"first":{"names":[{"first":"vetri"}]}}}
var x={}
var propName = 'value'
var get = Function("return this['" + propName + "']")
var set = Function("newValue", "this['" + propName + "'] = newValue")
var handler = { 'get': get, 'set': set, enumerable: true, configurable: true }
Object.defineProperty(x, propName, handler)
this works for me

Resources