Is there any way to convert Ember Object into plain javascript object? - javascript

I could not find any way to accomplish the task of such conversion as I could not find any means of getting Ember.js properties for the object. Ember.keys returns only the properties I set in create or with get and the properties declared in Ember.extend do not show up there. I use such properties to set up default values (e.g. [] for array properties)

Here is my dirty workaround
var newModel = JSON.parse(JSON.stringify(model));

I would do something similar to the person above, but I'd do it a little bit differently.
Mixin
App.NativeObject = Ember.Mixin.create({
toNative: function() {
var properties = [];
for (var key in this) {
if (jQuery.inArray(Ember.typeOf(object[key]), ['string', 'number', 'boolean']) !== -1) {
properties.push(key);
}
}
return this.getProperties(properties);
}
});
Object
Then you just need to implement the App.NativeObject mixin in your objects that you would like the toNative on:
var Object = Ember.Object.extend(App.NativeObject, {
name: 'Adam',
count: 4
});
We then have the toNative method on all the objects that implement our mixin.
Obligatory jsFiddle: http://jsfiddle.net/jumUx/

If your object is a subclass of ember-data model notice you can use the toJSON method otherwise you can use:
JSON.parse(JSON.stringify(emberObj))
To grab any values which support native json serialization (i.e. not functions/methods)

This worked for me:
myModel.toJSON({includeId: true})
I'm using Ember 3.

This is what I did and it works quite well. Note, this should be ready only, as any changes to an object or array in the copied object will affect the original object
App.BaseValidations = Ember.Object.create({
toObject: function() {
var destination = {}
for (var k in this) {
if (this.hasOwnProperty(k) && typeof(this[k]) !== 'function') {
destination[k] = this[k];
}
}
return destination;
}
})

something quite simple that worked properly enough for me is :
Ember.Object.reopen({
toJson: function() {
return JSON.parse(JSON.stringify(this));
}
});
at app loading time.

At the moment I solve it with the following snippet:
App.plainCopy = function (obj) {
if (Ember.isArray(obj)) {
return obj.map(App.plainCopy);
} else if (typeof(obj) === "object") {
if (App.Plainable.detect(obj)) {
return obj.plainCopy();
} else {
throw new Error(Ember.String.fmt("%# is not Plainable", [obj]));
}
} else {
return obj;
}
}
App.Plainable = Ember.Mixin.create({
plainCopy: function() {
var props = Ember.keys(this);
var proto = this.constructor.prototype;
for(p in proto) {
if (proto.hasOwnProperty(p) && typeof(this[p])!=="function") {
props.push(p);
}
}
var copy = {};
props.forEach(function(p) {
copy[p] = App.plainCopy(this.get(p));
}, this);
return copy;
}
});
It does not go up the class hierarchy and does not look into mixins (as I use for data objects which are quite simple form that point of view)

With modern (3.17) ember, I've used myEmberObject.getProperties('id', 'name', 'foo', 'bar')
It produces a plain object.

Another possible solution that may suit your needs while not being fully recursive for nested Ember objects:
// where myEmberObject is.. an ember object
var plainJavaScriptObject = myEmberObject.toJSON();
This will only include actual properties that you've defined and no Ember internals. Again, the drawback here is that any nested Ember objects will not, themselves, be converted but will appear as Strings in style of "".

Related

Best way to define functions on JavaScript prototypes [duplicate]

STORE = {
item : function() {
}
};
STORE.item.prototype.add = function() { alert('test 123'); };
STORE.item.add();
I have been trying to figure out what's wrong with this quite a while. Why doesn't this work? However, it works when I use the follow:
STORE.item.prototype.add();
The prototype object is meant to be used on constructor functions, basically functions that will be called using the new operator to create new object instances.
Functions in JavaScript are first-class objects, which means you can add members to them and treat them just like ordinary objects:
var STORE = {
item : function() {
}
};
STORE.item.add = function() { alert('test 123'); };
STORE.item.add();
A typical use of the prototype object as I said before, is when you instantiate an object by calling a constructor function with the new operator, for example:
function SomeObject() {} // a constructor function
SomeObject.prototype.someMethod = function () {};
var obj = new SomeObject();
All the instances of SomeObject will inherit the members from the SomeObject.prototype, because those members will be accessed through the prototype chain.
Every function in JavaScript has a prototype object because there is no way to know which functions are intended to be used as constructors.
After many years, when JavaScript (ES2015 arrives) we have finally Object.setPrototypeOf() method
const STORE = {
item: function() {}
};
Object.setPrototypeOf(STORE.item, {
add: function() {
alert('test 123');
}
})
STORE.item.add();
You can use JSON revivers to turn your JSON into class objects at parse time. The EcmaScript 5 draft has adopted the JSON2 reviver scheme described at http://JSON.org/js.html
var myObject = JSON.parse(myJSONtext, reviver);
The optional reviver parameter is a
function that will be called for every
key and value at every level of the
final result. Each value will be
replaced by the result of the reviver
function. This can be used to reform
generic objects into instances of
pseudoclasses, or to transform date
strings into Date objects.
myData = JSON.parse(text, function (key, value) {
var type;
if (value && typeof value === 'object') {
type = value.type;
if (typeof type === 'string' && typeof window[type] === 'function') {
return new (window[type])(value);
}
}
return value;
});
As of this writing this is possible by using the __proto__ property. Just in case anyone here is checking at present and probably in the future.
const dog = {
name: 'canine',
bark: function() {
console.log('woof woof!')
}
}
const pug = {}
pug.__proto__ = dog;
pug.bark();
However, the recommended way of adding prototype in this case is using the Object.create. So the above code will be translated to:
const pug = Object.create(dog)
pug.bark();
Or you can also use Object.setPrototypeOf as mentioned in one of the answers.
Hope that helps.
STORE = {
item : function() {
}
};
this command would create a STORE object. you could check by typeof STORE;. It should return 'object'. And if you type STORE.item; it returns 'function ..'.
Since it is an ordinary object, thus if you want to change item function, you could just access its properties/method with this command.
STORE.item = function() { alert('test 123'); };
Try STORE.item; it's still should return 'function ..'.
Try STORE.item(); then alert will be shown.

Removing and reattaching properties mapped to functions from javascript objects

I have an existing client side application that makes use of javascript objects that look something like this:
var myObject = {
Id: 1,
Name: 'Foo',
Property1: 123,
Property2: 'ABC',
MyMethod: function() { ///do something },
MyMethod2: function() { /// do something else }
};
I am now looking to try to persist these objects using a service such as Firebase. Firebase doesn't like the properties that contain the functions, so I want to know if there is a 'simple' way of stripping out the offending functions when saving to Firebase and then reattaching them on retrieval without having to create copies of each of the objects.
A fairly common pattern is to have a constructor function with the relevant functions attached to it, and to have that constructor accept a raw version of the object that it uses to populate itself as well as a "toRaw" or similar function that gives you the raw copy.
For example:
function Thingy(raw) {
var name;
for (name in raw) {
if (raw.hasOwnProperty(name)) {
this[name] = raw[name];
}
}
}
Thingy.prototype.MyMethod = function() { /* ... */ };
Thingy.prototype.MyMethod2 = function() { /* ... */ };
Thingy.prototype.toRaw = function() {
var raw, name, value;
for (name in this) {
if (this.hasOwnProperty(name)) {
value = this[name];
if (typeof value !== "function") {
if (value.toRaw) {
raw[name] = value.toRaw();
} else {
raw[name] = this[name];
}
}
}
}
};
Then when saving to Firebase:
write(myObject.toRaw());
...and when reading from Firebase:
var obj = new Thingy(read());
More complicated handling would involve putting a memo on the raw object to tell you whether one of the object's properties is, itself, using this pattern, so you know to call the constructor for it rather than just copying it. (The eagle-eyed will note that the example above is assymetrical, it allows for toRaw on properties when serializing in toRaw, but doesn't when deserializing in Thingy.)

Is there some way to add meta-data to JavaScript objects?

I would like to add key-value pairs of metadata to arbitrary JavaScript objects. This metadata should not affect code that is not aware of the metadata, that means for example
JSON.stringify(obj) === JSON.stringify(obj.WithMetaData('key', 'value'))
MetaData aware code should be able to retrieve the data by key, i.e.
obj.WithMetaData('key', 'value').GetMetaData('key') === 'value'
Is there any way to do it - in node.js? If so, does it work with builtin types such as String and even Number? (Edit Thinking about it, I don't care about real primitives like numbers, but having that for string instances would be nice).
Some Background: What I'm trying to do is cache values that are derived from an object with the object itself, so that
to meta data unaware code, the meta data enriched object will look the same as the original object w/o meta
code that needs the derived values can get it out of the meta-data if already cached
the cache will get garbage collected alongside the object
Another way would be to store a hash table with the caches somewhere, but you'd never know when the object gets garbage collected. Every object instance would have to be taken care of manually, so that the caches don't leak.
(btw clojure has this feature: http://clojure.org/metadata)
You can use ECMA5's new object properties API to store properties on objects that will not show up in enumeration but are nonetheless retrievable.
var myObj = {};
myObj.real_property = 'hello';
Object.defineProperty(myObj, 'meta_property', {value: 'some meta value'});
for (var i in myObj)
alert(i+' = '+myObj[i]); //only one property - #real_property
alert(myObj.meta_property); //"some meta value"
More information here: link
However you're not going to be able to do this on primitive types such as strings or numbers, only on complex types.
[EDIT]
Another approach might be to utilise a data type's prototype to store meta. (Warning, hack ahead). So for strings:
String.prototype.meta = {};
String.prototype.addMeta = function(name, val) { this.meta[name] = val; }
String.prototype.getMeta = function(name) { return this.meta[name]; };
var str = 'some string value';
str.addMeta('meta', 'val');
alert(str.getMeta('meta'));
However this is clearly not ideal. For one thing, if the string was collected or aliased (since simple data types are copied by value, not reference) you would lose this meta. Only the first approach has any mileage in a real-world environment, to be honest.
ES6 spec introduces Map and WeakMap. You can enable these in node by running node --harmony and by enabling the experimental javascript flag in Chrome, (it's also in Firefox by default). Maps and WeakMaps allow objects to be used as keys which can be be used to store metadata about objects that isn't visible to anyone without access to the specific map/weakmap. This is a pattern I now use a lot:
function createStorage(creator){
creator = creator || Object.create.bind(null, null, {});
var map = new Map;
return function storage(o, v){
if (1 in arguments) {
map.set(o, v);
} else {
v = map.get(o);
if (v == null) {
v = creator(o);
map.set(o, v);
}
}
return v;
};
}
Use is simple and powerful:
var _ = createStorage();
_(someObject).meta= 'secret';
_(5).meta = [5];
var five = new Number(5);
_(five).meta = 'five';
console.log(_(someObject).name);
console.log(_(5).meta);
console.log(_(five).meta);
It also facilitates some interesting uses for separating implementation from interface:
var _ = createStorage(function(o){ return new Backing(o) });
function Backing(o){
this.facade = o;
}
Backing.prototype.doesStuff = function(){
return 'real value';
}
function Facade(){
_(this);
}
Facade.prototype.doSomething = function doSomething(){
return _(this).doesStuff();
}
There is no "comment" system in JSON. The best you can hope for is to add a property with an unlikely name, and add that key contaning the metadata. You can then read the metadata back out if you know it's metadata, but other setups will just see it as another property. And if someone uses for..in...
You could just add the Metadata as a "private" variable!?
var Obj = function (meta) {
var meta = meta;
this.getMetaData = function (key) {
//do something with the meta object
return meta;
};
};
var ins_ob = new Obj({meta:'meta'});
var ins_ob2 = new Obj();
if(JSON.stringify(ins_ob) === JSON.stringify(ins_ob2)) {
console.log('hoorai');
};
If you want object-level metadata, you could create a class that extends Object. Getters and setters are not enumerable and, obviously, neither are private fields.
class MetadataObject extends Object {
#metadata = undefined;
get metadata() { return this.#metadata; }
set metadata(value) { this.#metadata; }
}
var obj = new MetadataObject();
obj.a = 1;
obj.b = 2;
obj.metadata = { test: 123 };
console.log(obj); // { a: 1, b: 2 }
console.log(obj.metadata); // { test: 123 }
console.log(JSON.stringify(obj)); // '{"a":1,"b":2}'
You can even simplify the implementation using a Map. Without a setter on metadata, you have to use Map methods to modify it.
class MetadataObject extends Object {
#metadata = new Map();
get metadata() { return this.#metadata; }
}
var obj = new MetadataObject();
obj.a = 1;
obj.b = 2;
obj.metadata.set('test', 123);
console.log(obj); // { a: 1, b: 2 }
console.log(obj.metadata.get('test')); // 123
console.log(JSON.stringify(obj)); // '{"a":1,"b":2}'
I ran into a situation where I needed property level metadata, and used the latter implementation.
obj.id = 1;
obj.metadata.set('id', 'metadata for the id property');

jquery using objects as filters

Is there any way to have DOM elements selectable through objects?
For example I want to be able to associate objects to DOM elements like so:
var obj = { a: 1, b:2 };
$('a').click(function() { this.selectThing = obj });
And later on...
$.something(obj);
Or even better:
$('a|selectThing?=', obj);
Something like that. You can see that I want to associate an object to a DOM element in such a way that I can grab the element with the object.
I know this can be done with the filter() method, my question is if there's a more elegant way that doesn't use filter() to do this.
EDIT:
To clarify, I want to be able to use an object kind of like a selector, so I can do something similar to this $(obj) obviously that won't work, but you get the idea (I hope)
EDIT #2:
I want to be able to do something like this:
var obj = { prop: 'prop' };
$('a').bindTo(obj);
$.retreive(obj) // should equal $('a')
I don't want it to alter obj in any way though (obj should still be {prop: 'prop'} only).
demo
var $div1 = $('.box1');
var $div2 = $('.box2');
var obj = { a: $div1, b: $div2 };
obj.a.css({background:'red'});
Or the short way: var obj = { a: $('.box1'), b: $('.box2') };
demo jsBin 2
var obj = $('.box1, .box2'); // store objects
obj.css({background:'red'}); // access collection
You're looking for $.data. This method associates any JavaScript object or primitive with a DOM element. Under the hood, it's not adding the data as an expando to the DOM element or anything--instead, jQuery maintains its own object cache of DOM elements and data hashes. But that's under the hood; the point is, I think it's exactly what you're looking for.
$('#example').data('foo', { bar: 'quux' }); // returns the jquery object containing '#example', like most jQuery methods
Then, later:
console.log($('#example').data('foo')); // returns {bar: 'quux'}
I dont think this is easily achievable. Let me clarify:
To achieve what you want you would require a hashmap that allows objects in the position of keys. JavaScript does not (yet) support objects as keys in hashmaps though. So, for example, the following does not work:
var key = {value: 'key'};
var data {value: 'data'};
var map = {};
map[key] = data;
There are other solutions to achieve this in current javascript implementations, eg. a double lookup:
var key = {value: 'key'};
var data {value: 'data'};
var map = { keys: [], data: [], get: function (key) {
var k = this.keys.indexOf(key);
if (k >= 0) {
return this.data[k];
} else return undefined;
}, set: function (key, val) {
var k = this.keys.indexOf(key);
if (k < 0) {
k = this.keys.push(k) - 1;
}
this.data[k] = val;
} };
map.set(key, data);
map.get(key).value;
This implementation however is of a terrible performance. There is a proposal for a so called WeakMap in JavaScript Harmony. Firefox I believe is currently the only browser implementing them, though. Since the feature required is not widely available and workarounds are of poor performance I would recommend trying to figure out a different way of achieving what you are trying to.
Extend jQuery with three methods:
jQuery.bindObj(data)
jQuery.unbindObj(data)
$.retrieve(data)
Your code looks like:
$('a').bindObj({blorg: 'shmorg'});
console.log($.retrieve({blorg: 'shmorg'})); // logs live result of $('a');
Full source: http://jsfiddle.net/nUUSV/6/.
The trick to this solution is storing the selectors/identifiers based to the jQuery constructor in one array, and the objects bound to those selectors/identifiers in another array, then using $.inArray to get the index of the object upon retrieval and using that index to grab the bound jQuery collection.
As I understand, you're looking for some sugar way to run multiple named searches on the DOM and have results filtered in a namespace object.
If so, I guess the following jquery extension might be helpfull to you:
$.fn.seek = function (selectors) {
var container = this,
found = {};
$.each(selectors, function (name) {
if ($.isPlainObject(selectors[name])) {
found[name] = $(container).seek(selectors[name]);
}
else if ($.type(selectors[name]) === 'string') {
found[name] = $(container).find(selectors[name]);
}
});
return found;
}
And here's the example of how the above extension might be applicable to your cases:
var res = $('body').seek({
links: 'a',
headers: 'h1,h2,h3,h4,h5,h6'
});
$(res.links).css({ color: 'green' });
$(res.headers).css({ color: 'red' });
I hope this helps you.
Not sure if this is what you are looking for. Perhaps you could write a custom selector based on the jquery selector, which handles objects with a selector-property the way you like. A selectable object would look like
var objSelector = {'selector' : '#select-me', 'a' : 'somestring', 'b' : 1243};
So you are free to use it like any other object, but you have to add the selector property. Than you add your custom selector:
$$ = (function($) {
return function(el, tag) {
if (typeof el === 'object' && el.selector !== undefined) {
return $(el.selector);
}
return $(el);
}
}($));
Now you can do things like
$$(objSelector).css({'border':'1px solid red'});
See an implementation on http://jsfiddle.net/JXcnJ/
If I understood correctly then, I think you need to define a property and say enumerable as false. See below,
Note: Below is just an example to demonstrate and not exactly meant to do such stuff,
DEMO
$(function() {
$.fn.bindTo = function(o) {
var _that = this;
Object.defineProperty(o, 'myFx', {
value: function() { return $(_that); },
writable: true,
enumerable: false,
configurable: true
});
}
$.retrieve = function(obj) {
return obj.myFx();
}
var obj = {
prop: 'prop'
};
$('#test').bindTo(obj);
$($.retrieve(obj)).html('Test');
//below is for proof
for (i in obj) {
alert(obj[i]);
}
});
Reference: http://yehudakatz.com/2011/08/12/understanding-prototypes-in-javascript/

managing object construction parameters in javascript

I am posting this in hopes that someone might have dealt with a similar problem.
I am using a javascript object that encapsulates paramaters to intialize greater objects in my code, like so :
function MyObject(setup)
{
this.mysetup = setup;
if(typeof this.mysetup == "undefined") { this.mysetup = {} }
if(typeof this.mysetup.stringParameter == "undefined")
{
this.mysetup.stringParameter="string default value"
}
if(typeof this.mysetup.objParameter == "undefined")
{
this.mysetup.objParameter == {}
}
else
{
if(typeof this.mysetup.objParameter.member1 == "undefined")
{
this.mysetup.objParameter.member1 = "member1 default value"
}
}
// ...and so on
}
This way I can make sure not every parameter needs to be in setup, and still MyObject can resort to default values for what is missing.
However, this is a tedious thing to write and quite error prone. So I thought I'd try for a solution that checks the setup against a setupPrototype:
function MyObject(setup)
{
this.setupPrototype = {
stringParameter : "string default value",
objectParameter : { member1 : "member default value"}
}
}
and try to compare the setup against this.setupPrototype.
The function I'm putting together for this purpose looks like
parseSetup = function (obj, objPrototype)
{
var returnedObj = {};
var hasMembers = false;
if(typeof obj=="undefined")
{
returnedObj = objPrototype;
return returnedObj;
}
for(member in objPrototype)
{
hasMembers = true;
//if prototype member is not part of initialization object
if (typeof obj[member]=="undefined")
{
returnedObj[member] = objPrototype[member];
}
else
{
if(objPrototype[member] instanceof Object)
{
if(objPrototype[member] instanceof Array)
{
returnedObj[member]=[];
for(var i=0; i<objPrototype[member].length; i++)
{
returnedObj[member].push(parseSetup(obj[member][i], objPrototype[member][i]))
}
}
else{
returnedObj[member] = parseSetup(obj[member], objPrototype[member])
}
}
else
returnedObj[member] = obj[member];
}
}
if(!hasMembers)
{
if (typeof obj == "undefined")
{
returnedObj = objPrototype;
}
else
returnedObj = obj;
}
return returnedObj;
}
This however is still not up to par.
An additional issue, which I'm debating is whether the original 'setup' should retain any of its own initial properties, or just have whatever is in the prototype. Also, it would be pointless to require that the prototype itself be aware of every possible value the setup might contain, especially for deep nested objects.
So my question is, are you aware of any proper way to solve this problem and end up with a setup object that, where its parameters are missing, can get default values from the prototype, but also not lose its own where they somehow need to be kept?
Many thanks
I would recommend using jQuery and then taking advantage of the $.extend() function, as described on the jQuery plugins page. Basically, you define your default parameters as an object within the constructor method, and then use $.extend() to overwrite only the properties that are supplied in the parameter to your function.
So you might end up with something like:
var MyObject = function (options) {
this.defaultOptions = {
stringParameter: "string default value",
objParameter: {}
};
this.options = $.extend(true, this.defaultOptions, options);
};
To instantiate with the default parameters:
var obj1 = new MyObject({});
To instantiate with an overridden stringParameter:
var obj2 = new MyObject({stringParameter: 'overridden value'});
You can see a demo of this in action here.

Categories

Resources