So I'm trying to edit this rss feed with these 2 functions because of the media:content property which I have had no luck accessing directly. the functions I have below work for creating a new value called mediaContent which I can then easily access. The issue is in the rss feed not all objects will have media:content and I want to add a default value for the objects that don't have that property so I have consistency in my objects. Otherwise I end up with undefined on on some of mediaContent in my new object. I wanted to start just added a default value in when media:content is not present in the object but these ||'s are not working as I would have expected. How can I get my else if to punch in a default value if media:content does not exist? I'm probably missing something easy.
function getMediaContent(value) {
for (var i in value) {
if (i === "media:content") {
console.log("MC::", i)
return value[i].$;
} else if (i !== "title" || i !== "link" || i !== "pubDate" || i !== "isoDate" || i !== "guid" || i !== "contentSnippet" || i !== "content") {
debugger;
return "no media content"
}
}
}
function getNewsLinks() {
return newsItems.map(value => ({
value,
mediaContent: getMediaContent(value)
}))
}
SOLUTION (based on accepted answer)
function getMediaContent(value) {
return "media:content" in value ? value["media:content"].$ : "no media content";
}
works perfectly. Thanks!
Since you're just looking to see if a property exists on an object, you can use the in operator:
function getMediaContent(value) {
return "media:content" in value ? value["media:content"].$ : "no media content";
}
That checks if the property exists, and if so, gets the value of its $ property. Otherwise, returns the default value.
I needed something similar and optionally it would work for multi-layered JSON objects. Here is the function I use:
function getFromJSON(obj, ...args) {
for (const arg of args) {
if (!Array.isArray(arg)) {
if (arg in obj) {
obj = obj[arg]
} else {
return `${arg} not found in JSON`;
}
} else {
for (const argOpt of arg) {
if (argOpt in obj) {
obj = obj[argOpt]
break;
}
}
}
}
return obj
}
In addition, you can pass multiple keys in an array if you want to get the value of whichever exists.
I have a method that takes a language abbreviation and matches it using a .constant dictionary, and returns the matching language name.
How can I do an evaluation with .filter to check whether the passed isoCode/language abbreviation exists?
Here is my method:
angular.module('portalDashboardApp')
.service('ISOtoLanguageService', ['Languages', function(Languages) {
this.returnLanguage = function(isoCode) {
var categoryObject = Languages.filter(function ( categoryObject ) {
return categoryObject.code === isoCode;
})[0];
return categoryObject.name;
};
}]);
Here is the method with some error catching I have tried:
angular.module('portalDashboardApp')
.service('ISOtoLanguageService', ['Languages', function(Languages) {
this.returnLanguage = function(isoCode) {
var categoryObject = Languages.filter(function (categoryObject) {
if (isoCode != null || isoCode != undefined) {
return categoryObject.code === isoCode;
}
else {
return categoryObject.code === 'und';
}
})[0];
if (categoryObject.name != undefined || categoryObject.name != null) {
return categoryObject.name;
}
else {
return "undefined";
}
};
}]);
Thank you!
I would recommend you organize your data at Languagesin an object or map, it'll be much faster and simpler when you fetch your translation by an abbreviation. A short example:
angular.module('portalDashboardApp')
.factory('Languages', function(){
var dictionary = {
ISO: {name: 'International Organization for Standardization'}
};
return {
get: function(abbr){
return dict[abbr];
}
};
}).service('ISOtoLanguageService', ['Languages', function(Languages) {
this.returnLanguage = function(isoCode) {
if(!isoCode) {
return "Answer for empty isoCode";
}
var categoryObject = Languages.get(isoCode);
return (categoryObject || {}).name || "I don't know this abbr";
};
}]);
I'm not sure that this JS works without any syntax error (I've not try to launch it) but idea is that you don't need array and filter on big dictionaries and you are able to get any abbreviation from dict with O(1) complexity even with huge dictionary.
If you don't want to have a refactoring with your code you can do something like this:
angular.module('portalDashboardApp')
.service('ISOtoLanguageService', ['Languages', function(Languages) {
this.returnLanguage = function(isoCode) {
if (!isoCode) {
return;
}
var resultAbbrs = Languages.filter(function (categoryObject) {
return categoryObject.code === isoCode;
});
if (resultAbbrs.length > 0) {
return resultAbbrs[0].name;
}
};
}]);
In this case if isoCode is null, undefined or empty string or this key is not found in dictionary return undefined will be by default. Outside you should check a result of this function with if (result === undefined) ...
I hope it helped you)
I am trying to post an object only if it's not empty. However I have code which causes properties to become undefined -- and when that happens, the obj is not empty anymore and the post still happens.
userSearchData = {};
$('#addContactForm').keyup(function()
{
var email = $(this).find('input[name="email"]').val();
var username = $(this).find('input[name="username"]').val();
var fullName = $(this).find('input[name="fullName"]').val();
userSearchData.email = email.length >= 3 ? email : undefined;
userSearchData.username = username.length >= 3 ? username : undefined;
userSearchData.fullName = fullName.length >= 3 ? fullName : undefined;
console.log(userSearchData);
if ( !isEmpty(userSearchData) )
{
console.log("Is empty")
$.post( '/post/addContact', { userSearchData: userSearchData }, function( data )
{
console.log( data );
});
}
});
It's a "search" form, so if a user types for example "Blabla" as the username, and then erases letters to make it "Bl", then the username variable gets undefined, so it's not being sent when doing the post (I console log the object on the server side and the undefined variables are not considered which is good).
How can I make my variables completely removed, instead of undefined when their length is below 3?
I could probably modify the isEmpty function to return false if all keys are undefined, would that be better to do that? If so, how would you do it?
var hasOwnProperty = Object.prototype.hasOwnProperty;
function isEmpty (obj)
{
// null and undefined are "empty"
if (obj == null) return true;
// Assume if it has a length property with a non-zero value
// that that property is correct.
if (obj.length > 0) return false;
if (obj.length === 0) return true;
// Otherwise, does it have any properties of its own?
// Note that this doesn't handle
// toString and valueOf enumeration bugs in IE < 9
for (var key in obj) {
if (hasOwnProperty.call(obj, key)) return false;
}
return true;
}
The whole thing seems rather pointless, you can just do this instead
$('#addContactForm').on('keyup', function() {
var userSearchData = {}, self = this;
$.each(['email', 'username', 'fullName'], function(_, el) {
var val = $(self).find('input[name="'+el+'"]').val();
if ( val.length > 3 ) userSearchData[el] = val;
});
$.post( '/post/addContact', { userSearchData: userSearchData }, function( data ) {
console.log( data );
});
});
Only add the properties to the object if the condition is met.
if ( username.length >=3 ) {
userSearchData.username = username;
}
if ( username in userSearchData ) {
// do stuff
}
you can delete properties in JS, but the better fix is to just make sure your code posts when it should.
if (obj === null || obj === undefined) return;
or something might help you here.
Also, for(key in obj) is old-style "iterate over prototype as well", and highly discouraged, so you probably want this instead:
var keys = Object.keys(obj);
if(keys.length === 0) ...
keys.forEach(function(key) { ... });
Do you mean you want do this?
if(!isEmpty(userSearchData)){
$.post( '/post/addContact', { userSearchData: userSearchData }, function( data )
{
console.log( data );
});
}
I am looking for an efficient way to translate my Ember object to a json string, to use it in a websocket message below
/*
* Model
*/
App.node = Ember.Object.extend({
name: 'theName',
type: 'theType',
value: 'theValue',
})
The websocket method:
App.io.emit('node', {node: hash});
hash should be the json representation of the node. {name: thename, type: theType, ..}
There must be a fast onliner to do this.. I dont want to do it manualy since i have many attributes and they are likely to change..
As stated you can take inspiration from the ember-runtime/lib/core.js#inspect function to get the keys of an object, see http://jsfiddle.net/pangratz666/UUusD/
App.Jsonable = Ember.Mixin.create({
getJson: function() {
var v, ret = [];
for (var key in this) {
if (this.hasOwnProperty(key)) {
v = this[key];
if (v === 'toString') {
continue;
} // ignore useless items
if (Ember.typeOf(v) === 'function') {
continue;
}
ret.push(key);
}
}
return this.getProperties.apply(this, ret);
}
});
Note, since commit 1124005 - which is available in ember-latest.js and in the next release - you can pass the ret array directly to getProperties, so the return statement of the getJson function looks like this:
return this.getProperties(ret);
You can get a plain JS object (or hash) from an Ember.Object instance by calling getProperties() with a list of keys.
If you want it as a string, you can use JSON.stringify().
For example:
var obj = Ember.Object.create({firstName: 'Erik', lastName: 'Bryn', login: 'ebryn'}),
hash = obj.getProperties('firstName', 'lastName'), // => {firstName: 'Erik', lastName: 'Bryn'}
stringHash = JSON.stringify(hash); // => '{"firstName": "Erik", "lastName": "Bryn"}'
I have also been struggling with this. As Mirko says, if you pass the ember object to JSON.stringify you will get circular reference error. However if you store the object inside one property and use stringify on that object, it works, even nested subproperties.
var node = Ember.Object.create({
data: {
name: 'theName',
type: 'theType',
value: 'theValue'
}
});
console.log(JSON.stringify(node.get('data')));
However, this only works in Chrome, Safari and Firefox. In IE8 I get a stack overflow so this isn't a viable solution.
I have resorted to creating JSON schemas over my object models and written a recursive function to iterate over the objects using the properties in the schemas and then construct pure Javascript objects which I can then stringify and send to my server. I also use the schemas for validation so this solution works pretty well for me but if you have very large and dynamic data models this isn't possible. I'm also interested in simpler ways to accomplish this.
I modifed #pangratz solution slightly to make it handle nested hierarchies of Jsonables:
App.Jsonable = Ember.Mixin.create({
getJson: function() {
var v, json = {};
for (var key in this) {
if (this.hasOwnProperty(key)) {
v = this[key];
if (v === 'toString') {
continue;
}
if (Ember.typeOf(v) === 'function') {
continue;
}
if (App.Jsonable.detect(v))
v = v.getJson();
json[key] = v;
}
}
return json;
}
});
App.io.emit('node', {node: node.toJSON()});
Or if you have an ID property and want to include it:
App.io.emit('node', {node: node.toJSON({includeId: true})});
Will this work for you?
var json = JSON.stringify( Ember.getMeta( App.node, 'values') );
The false is optional, but would be more performant if you do not intend to modify any of the properties, which is the case according to your question. This works for me, but I am wary that Ember.meta is a private method and may work differently or not even be available in future releases. (Although, it isn't immediately clear to me if Ember.getMeta() is private). You can view it in its latest source form here:
https://github.com/emberjs/ember.js/blob/master/packages/ember-metal/lib/utils.js
The values property contains only 'normal' properties. You can collect any cached, computed properties from Ember.meta( App.node, false ).cached. So, provided you use jQuery with your build, you can easily merge these two objects like so:
$.extend( {}, Ember.getMeta(App.node, 'values'), Ember.getMeta(App.node, 'cache') );
Sadly, I haven't found a way to get sub-structures like array properties in this manner.
I've written an extensive article on how you can convert ember models into native objects or JSON which may help you or others :)
http://pixelchild.com.au/post/44614363941/how-to-convert-ember-objects-to-json
http://byronsalau.com/blog/convert-ember-objects-to-json/
I modified #Kevin-pauli solution to make it works with arrays as well:
App.Jsonable = Ember.Mixin.create({
getJson: function() {
var v, json = {}, inspectArray = function (aSome) {
if (Ember.typeof(aSome) === 'array') {
return aSome.map(inspectArray);
}
if (Jsonable.detect(aSome)) {
return aSome.getJson();
}
return aSome;
};
for (var key in this) {
if (this.hasOwnProperty(key)) {
v = this[key];
if (v === 'toString') {
continue;
}
if (Ember.typeOf(v) === 'function') {
continue;
}
if (Ember.typeOf(v) === 'array') {
v = v.map(inspectArray);
}
if (App.Jsonable.detect(v))
v = v.getJson();
json[key] = v;
}
}
return json;
}
});
I also made some further modification to get the best of both worlds. With the following version I check if the Jsonable object has a specific property that informs me on which of its properties should be serialized:
App.Jsonable = Ember.Mixin.create({
getJson: function() {
var v, json = {}, base, inspectArray = function (aSome) {
if (Ember.typeof(aSome) === 'array') {
return aSome.map(inspectArray);
}
if (Jsonable.detect(aSome)) {
return aSome.getJson();
}
return aSome;
};
if (!Ember.isNone(this.get('jsonProperties'))) {
// the object has a selective list of properties to inspect
base = this.getProperties(this.get('jsonProperties'));
} else {
// no list given: let's use all the properties
base = this;
}
for (var key in base) {
if (base.hasOwnProperty(key)) {
v = base[key];
if (v === 'toString') {
continue;
}
if (Ember.typeOf(v) === 'function') {
continue;
}
if (Ember.typeOf(v) === 'array') {
v = v.map(inspectArray);
}
if (App.Jsonable.detect(v))
v = v.getJson();
json[key] = v;
}
}
return json;
}
});
I am using this little tweak and I am happy with it. I hope it'll help others as well!
Thanks to #pangratz and #Kevin-Pauli for their solution!
Here I take #leo, #pangratz and #kevin-pauli solution a little step further. Now it iterates not only with arrays but also through has many relationships, it doesn't check if a value has the type Array but it calls the isArray function defined in Ember's API.
Coffeescript
App.Jsonable = Em.Mixin.create
getJson: ->
jsonValue = (attr) ->
return attr.map(jsonValue) if Em.isArray(attr)
return attr.getJson() if App.Jsonable.detect(attr)
attr
base =
if Em.isNone(#get('jsonProperties'))
# no list given: let's use all the properties
this
else
# the object has a selective list of properties to inspect
#getProperties(#get('jsonProperties'))
hash = {}
for own key, value of base
continue if value is 'toString' or Em.typeOf(value) is 'function'
json[key] = jsonValue(value)
json
Javascript
var hasProp = {}.hasOwnProperty;
App.Jsonable = Em.Mixin.create({
getJson: function() {
var base, hash, hashValue, key, value;
jsonValue = function(attr) {
if (Em.isArray(attr)) {
return attr.map(jsonValue);
}
if (App.Jsonable.detect(attr)) {
return attr.getJson();
}
return attr;
};
base = Em.isNone(this.get('jsonProperties')) ? this : this.getProperties(this.get('jsonProperties'));
json = {};
for (key in base) {
if (!hasProp.call(base, key)) continue;
value = base[key];
if (value === 'toString' || Em.typeOf(value) === 'function') {
continue;
}
json[key] = jsonValue(value);
}
return json;
}
});
Ember Data Model's object counts with a toJSON method which optionally receives an plain object with includeId property used to convert an Ember Data Model into a JSON with the properties of the model.
https://api.emberjs.com/ember-data/2.10/classes/DS.Model/methods/toJSON?anchor=toJSON
You can use it as follows:
const objects = models.map((model) => model.toJSON({ includeId: true }));
Hope it helps. Enjoy!
I have:
fixed and simplified code
added circular reference prevention
added use of get of value
removed all of the default properties of an empty component
//Modified by Shimon Doodkin
//Based on answers of: #leo, #pangratz, #kevin-pauli, #Klaus
//http://stackoverflow.com/questions/8669340
App.Jsonable = Em.Mixin.create({
getJson : function (keysToSkip, visited) {
//getJson() called with no arguments,
// they are to pass on values during recursion.
if (!keysToSkip)
keysToSkip = Object.keys(Ember.Component.create());
if (!visited)
visited = [];
visited.push(this);
var getIsFunction;
var jsonValue = function (attr, key, obj) {
if (Em.isArray(attr))
return attr.map(jsonValue);
if (App.Jsonable.detect(attr))
return attr.getJson(keysToSkip, visited);
return getIsFunction?obj.get(key):attr;
};
var base;
if (!Em.isNone(this.get('jsonProperties')))
base = this.getProperties(this.get('jsonProperties'));
else
base = this;
getIsFunction=Em.typeOf(base.get) === 'function';
var json = {};
var hasProp = Object.prototype.hasOwnProperty;
for (var key in base) {
if (!hasProp.call(base, key) || keysToSkip.indexOf(key) != -1)
continue;
var value = base[key];
// there are usual circular references
// on keys: ownerView, controller, context === base
if ( value === base ||
value === 'toString' ||
Em.typeOf(value) === 'function')
continue;
// optional, works also without this,
// the rule above if value === base covers the usual case
if (visited.indexOf(value) != -1)
continue;
json[key] = jsonValue(value, key, base);
}
visited.pop();
return json;
}
});
/*
example:
DeliveryInfoInput = Ember.Object.extend(App.Jsonable,{
jsonProperties: ["title","value","name"], //Optionally specify properties for json
title:"",
value:"",
input:false,
textarea:false,
size:22,
rows:"",
name:"",
hint:""
})
*/
Ember.js appears to have a JSON library available. I hopped into a console (Firebug) on one the Todos example and the following worked for me:
hash = { test:4 }
JSON.stringify(hash)
So you should be able to just change your line to
App.io.emit('node', { node:JSON.stringify(hash) })
From the node REPL thing,
> d = {}
{}
> d === {}
false
> d == {}
false
Given I have an empty dictionary, how do I make sure it is an empty dictionary ?
function isEmpty(obj) {
return Object.keys(obj).length === 0;
}
You could extend Object.prototype with this isEmpty method to check whether an object has no own properties:
Object.prototype.isEmpty = function() {
for (var prop in this) if (this.hasOwnProperty(prop)) return false;
return true;
};
How about using jQuery?
$.isEmptyObject(d)
Since it has no attributes, a for loop won't have anything to iterate over. To give credit where it's due, I found this suggestion here.
function isEmpty(ob){
for(var i in ob){ return false;}
return true;
}
isEmpty({a:1}) // false
isEmpty({}) // true
This is what jQuery uses, works just fine. Though this does require the jQuery script to use isEmptyObject.
isEmptyObject: function( obj ) {
for ( var name in obj ) {
return false;
}
return true;
}
//Example
var temp = {};
$.isEmptyObject(temp); // returns True
temp ['a'] = 'some data';
$.isEmptyObject(temp); // returns False
If including jQuery is not an option, simply create a separate pure javascript function.
function isEmptyObject( obj ) {
for ( var name in obj ) {
return false;
}
return true;
}
//Example
var temp = {};
isEmptyObject(temp); // returns True
temp ['b'] = 'some data';
isEmptyObject(temp); // returns False
I'm far from a JavaScript scholar, but does the following work?
if (Object.getOwnPropertyNames(d).length == 0) {
// object is empty
}
It has the advantage of being a one line pure function call.
var SomeDictionary = {};
if(jQuery.isEmptyObject(SomeDictionary))
// Write some code for dictionary is empty condition
else
// Write some code for dictionary not empty condition
This Works fine.
If performance isn't a consideration, this is a simple method that's easy to remember:
JSON.stringify(obj) === '{}'
Obviously you don't want to be stringifying large objects in a loop, though.
You'd have to check that it was of type 'object' like so:
(typeof(d) === 'object')
And then implement a short 'size' function to check it's empty, as mentioned here.
If you try this on Node.js use this snippet, based on this code here
Object.defineProperty(Object.prototype, "isEmpty", {
enumerable: false,
value: function() {
for (var prop in this) if (this.hasOwnProperty(prop)) return false;
return true;
}
}
);