AngularJS - Create dynamic properties to an object/model from json - json

OK, we all know this works:
vm.myObject = {
required : "This field requires data",
.....
}
But how can I create that same object dynamically when the property 'keys' and 'values' come from a json file, eg:
json:
[
{ "key" :"required", "value": "This field requires data"},
.....
]
service:
var myObject = {}
DynamicObjSvc.get()
.success(function(data){
data.forEach(function(item){
// pass each key as an object property
// and pass its respective value
?????????
})
.....
UPDATE:
Kavemen was mostly correct, this turned out to be the solution:
var myObject = {};
DynamicObjSvc.all()
.success(function(data){
angular.forEach(data, function(msg) {
myObject[msg.key] = msg.value; <-- his answer was incorrect here
});
$fgConfigProviderRef.validation.message(myObject);
})
.error(function(err){
console.log(err.message);
})

You can use angular.forEach and the bracket notation for setting (and getting) object properties in Javascript
var myObject = {}
DynamicObjSvc.get().success(
function(data) {
angular.forEach(data, function(value, key) {
myObject[key] = value;
});
}
);
See also Working with Objects from MDN
EDIT
I see now that your data is really an array of objects, not just a single object, so yes, the code above could lead you astray.
In any case, the method of setting an object's properties dynamically using the bracket notation is sound; the loop could be reworked to handle your data array as such:
//we have an array of objects now
var myObjects = [];
DynamicObjSvc.get().success(
function(data) {
//for each object in the data array
for(var i = 0; i < data.length; i++) {
//create and populate a new object for the ith data element
var newObject = {};
angular.forEach(data[i], function(value, key) {
newObject[key] = value;
});
//and add it to the overall collection
myObjects.push(newObject);
}
}
);

Related

Get the keys of the first object JSON [duplicate]

Is there an elegant way to access the first property of an object...
where you don't know the name of your properties
without using a loop like for .. in or jQuery's $.each
For example, I need to access foo1 object without knowing the name of foo1:
var example = {
foo1: { /* stuff1 */},
foo2: { /* stuff2 */},
foo3: { /* stuff3 */}
};
var obj = { first: 'someVal' };
obj[Object.keys(obj)[0]]; //returns 'someVal'
Object.values(obj)[0]; // returns 'someVal'
Using this you can access also other properties by indexes. Be aware tho! Object.keys or Object.values return order is not guaranteed as per ECMAScript however unofficially it is by all major browsers implementations, please read https://stackoverflow.com/a/23202095 for details on this.
Try the for … in loop and break after the first iteration:
for (var prop in object) {
// object[prop]
break;
}
You can also do Object.values(example)[0].
You can use Object.values() to access values of an object:
var obj = { first: 'someVal' };
Object.values(obj)[0]; // someVal
Use Object.keys to get an array of the properties on an object. Example:
var example = {
foo1: { /* stuff1 */},
foo2: { /* stuff2 */},
foo3: { /* stuff3 */}
};
var keys = Object.keys(example); // => ["foo1", "foo2", "foo3"] (Note: the order here is not reliable)
Documentation and cross-browser shim provided here. An example of its use can be found in another one of my answers here.
Edit: for clarity, I just want to echo what was correctly stated in other answers: the key order in JavaScript objects is undefined.
A one-liner version:
var val = example[function() { for (var k in example) return k }()];
There isn't a "first" property. Object keys are unordered.
If you loop over them with for (var foo in bar) you will get them in some order, but it may change in future (especially if you add or remove other keys).
The top answer could generate the whole array and then capture from the list. Here is an another effective shortcut
var obj = { first: 'someVal' };
Object.entries(obj)[0][1] // someVal
Solution with lodash library:
_.find(example) // => {name: "foo1"}
but there is no guarantee of the object properties internal storage order because it depends on javascript VM implementation.
Here is a cleaner way of getting the first key:
var object = {
foo1: 'value of the first property "foo1"',
foo2: { /* stuff2 */},
foo3: { /* stuff3 */}
};
let [firstKey] = Object.keys(object)
console.log(firstKey)
console.log(object[firstKey])
if someone prefers array destructuring
const [firstKey] = Object.keys(object);
No. An object literal, as defined by MDN is:
a list of zero or more pairs of property names and associated values of an object, enclosed in curly braces ({}).
Therefore an object literal is not an array, and you can only access the properties using their explicit name or a for loop using the in keyword.
To get the first key name in the object you can use:
var obj = { first: 'someVal' };
Object.keys(obj)[0]; //returns 'first'
Returns a string, so you cant access nested objects if there were, like:
var obj = { first: { someVal : { id : 1} }; Here with that solution you can't access id.
The best solution if you want to get the actual object is using lodash like:
obj[_.first(_.keys(obj))].id
To return the value of the first key, (if you don't know exactly the first key name):
var obj = { first: 'someVal' };
obj[Object.keys(obj)[0]]; //returns 'someVal'
if you know the key name just use:
obj.first
or
obj['first']
This has been covered here before.
The concept of first does not apply to object properties, and the order of a for...in loop is not guaranteed by the specs, however in practice it is reliably FIFO except critically for chrome (bug report). Make your decisions accordingly.
I don't recommend you to use Object.keys since its not supported in old IE versions. But if you really need that, you could use the code above to guarantee the back compatibility:
if (!Object.keys) {
Object.keys = (function () {
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
],
dontEnumsLength = dontEnums.length;
return function (obj) {
if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');
var result = [];
for (var prop in obj) {
if (hasOwnProperty.call(obj, prop)) result.push(prop);
}
if (hasDontEnumBug) {
for (var i=0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
}
}
return result;
}})()};
Feature Firefox (Gecko)4 (2.0) Chrome 5 Internet Explorer 9 Opera 12 Safari 5
More info: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys
But if you only need the first one, we could arrange a shorter solution like:
var data = {"key1":"123","key2":"456"};
var first = {};
for(key in data){
if(data.hasOwnProperty(key)){
first.key = key;
first.content = data[key];
break;
}
}
console.log(first); // {key:"key",content:"123"}
If you need to access "the first property of an object", it might mean that there is something wrong with your logic. The order of an object's properties should not matter.
A more efficient way to do this, without calling Object.keys() or Object.values() which returns an array:
Object.prototype.firstKey = function () {
for (const k in this) {
if (Object.prototype.hasOwnProperty.call(this, k)) return k;
}
return null;
};
Then you can use it like:
const obj = {a: 1, b: 2, c: 3}
console.log(obj.firstKey()) //=> 'a'
This doesn't necessarily return the first key, see Elements order in a "for (… in …)" loop
we can also do with this approch.
var example = {
foo1: { /* stuff1 */},
foo2: { /* stuff2 */},
foo3: { /* stuff3 */}
};
Object.entries(example)[0][1];
This is an old question but most of the solutions assume that we know the attribute's name which it is not the case for example if you are trying to visualize data from files that the user can upload or similar cases.
This is a simple function that I use and works in both cases that you know the variable and if not it will return the first attribute of the object (sorted alphabetically)
The label function receives an object d and extract the key if exits, otherwise returns the first attribute of the object.
const data = [
{ label: "A", value: 10 },
{ label: "B", value: 15 },
{ label: "C", value: 20 },
{ label: "D", value: 25 },
{ label: "E", value: 30 }
]
const keys = ['label', 0, '', null, undefined]
const label = (d, k) => k ? d[k] : Object.values(d)[0]
data.forEach(d => {
console.log(`first: ${label(d)}, label: ${label(d, keys[0])}`)
})
keys.forEach(k => {
console.log(`label of ${k}: ${label(data[0], k)}`)
})
For values like 0, '', null, and undefined will return the first element of the array.
this is my solution
const dataToSend = {email:'king#gmail.com',password:'12345'};
const formData = new FormData();
for (let i = 0; i < Object.keys(dataToSend).length; i++) {
formData.append(Object.keys(dataToSend)[i],
Object.values(dataToSend)[i]);
}
console.log(formData);
Any reason not to do this?
> example.map(x => x.name);
(3) ["foo1", "foo2", "foo3"]
Basic syntax to iterate through key-value gracefully
const object1 = {
a: 'somestring',
b: 42
};
for (const [key, value] of Object.entries(object1)) {
console.log(`${key}: ${value}`);
}
// expected output:
// "a: somestring"
// "b: 42"
As others have pointed out, if the order of properties is important, storing them in an object is not a good idea. Instead, you should use an array via square brackets. E.g.,
var example = [ {/* stuff1 */}, { /* stuff2 */}, { /* stuff3 */}];
var first = example[0];
Note that you lose the 'foo' identifiers. But you could add a name property to the contained objects:
var example = [
{name: 'foo1', /* stuff1 */},
{name: 'foo2', /* stuff2 */},
{name: 'foo3', /* stuff3 */}
];
var whatWasFirst = example[0].name;
For those seeking an answer to a similar question, namely: "How do I find one or more properties that match a certain pattern?", I'd recommend using Object.keys(). To extend benekastah's answer:
for (const propName of Object.keys(example)) {
if (propName.startsWith('foo')) {
console.log(`Found propName ${propName} with value ${example[propName]}`);
break;
}
}

adding elements to json string(array) FLUTTER

I have a JSON string, inside of it I have an array, I want to add data to it as I tried to do it below:
String myJSON = '{"listOfSubtasks":["dasd","dadd","dadsd"]}';
arrayToStringAndBack(addElement) async {
var json = jsonDecode(myJSON);
var getArray = json['listOfSubtasks']; //returns [dasd,dadd,dadsd]
setState(() {
getArray.add(addElement);
});
// as I want to push it to a db I convert [dasd,dadd,dadsd] to a String ["dasd","dadd","dadsd"]
String arrayToString = jsonEncode(getArray);
print(arrayToString);
}
...
textfieldform
- onSaved: (val) {
subtasks = val;
arrayToStringAndBack(val);
},
...
When I type smth and click on a submit button an element is added to the end of an array but once I try to do it one more time, to add an element, the last element that was added changes to one I created.
I want to add as many elements as I want, not just a single one
Solved
var arrayOfSubTasks = [];
arrayToStringAndBack(addElement, arr) async {
var json = jsonDecode(myJSON);
var getArray = json['listOfSubtasks'];
setState(() {
getArray.add(arr);
});
String arrayToString = jsonEncode(getArray);
print(arrayToString);
}
...
onSaved: (val) {
subtasks = val;
setState(() {
arrayOfSubTasks.add(val);
});
arrayToStringAndBack(val, arrayOfSubTasks);
},
You can treat your list of subtasks as a List to be able to add String with List.add(). Then encode the List to a json with jsonEncode()

LocalStorage: get every value from each key

I want to go through every key and get the name value from each key.
This is how my LocalStorage looks like.
key: 3 Value:
{"name":"Kevin","country":"Canada","about":"Test","image":""}
key: 4 Value:
{"name":"Homer","country":"Canada","about":"Test","image":""}
I want to getboth of these names and add them to my array. I tried it with this method:
for(var key in localStorage){
let user = JSON.parse(localStorage.getItem(key));
this.users.push(user);
}
Error I get is:
SyntaxError: Unexpected token e in JSON at position 1
var keys = Object.keys(localStorage);
keys.forEach(key=>{
var json_str =localStorage.getItem(key)
try {
var abc = JSON.parse(json_str);
this.user = abc;
} catch (e) {
console.log(e)
}
})
when you say I want to getboth of these names, i don't get it but either way you can try something like:
var keys = Object.keys(localStorage);
for(var i=0;i<keys.length;i++){
var key = keys[i];
console.log(key, localStorage[key]);
//store here "both names" where you want them
//you can also access each element with localStorage[key].name, localStorage[key].country, etc.
}
This is a refinement of Robert's answer.
Just enumerate all of the values (The keys themselves do not matter) in localStorage that have a name property that is a string. Then return that array.
Based on your own answer, you likely have inconsistent mutable state as moving your temporary variable to instance scope should not impact your situation.
function getUsers() {
return Object.values(localStorage)
.map(json => {
try {
return JSON.parse(json);
}
catch (e) {
return undefined;
}
})
.filter((user?: any): user is {name: string} => user && typeof user.name === 'string');
}
const users = getUsers();
You can consider using my library ngx-store to deal with localStorage, sessionStorage, cookies and a bit more in Angular. To achieve what you want you will be able to store whole array in storage or just use code like the below with your current data structure:
import { LocalStorageService } from 'ngx-store';
export class Example {
public users: Array<any> = [];
constructor(public localStorageService: LocalStorageService) {
this.localStorageService.utility.forEach((value, key) => this.users.push(value));
}
}
Really, it can be just that simple ;)
You can use method hasOwnProperty('propertyName') to check name available or not in object. Then perform the operation that you want.
let localStorage = {
"key1": {"name":"Kevin","country":"Canada","about":"Test","image":""},
"key2": {"name":"Homer","country":"Canada","about":"Test","image":""}
}
for(let key of Object.keys(localStorage)){
if(localStorage[key].hasOwnProperty('name')){
console.log(localStorage[key]['name']);
}
}
const allItems = []
const keys = Object.keys(window.localStorage); // all keys
keys.forEach(key=> {
const item = JSON.parse(localStorage.getItem(key) + ''); //item with type Object
allItems.push(item);
});
console.log(allItems) // arry of object
I manage to solve it, was a simple error by always initializing a new let user inside the loop.
I moved out the user and the rest of the code works.
user: any;
getUsers():void{
for(var key in localStorage){
this.user = JSON.parse(localStorage.getItem(key));
this.users.push(this.user);
}
}

Filtering json values

I have a process that returns a json object:
data={key1:[], key2:[], key3:[{key1:"a"}, {key2:"b"}], key4:[{key1:"c"}, {key2:"d"}]}
I want know if there is a simple way to filter this json object to remove the properties where the value is an empty array.
Once filtered I can then loop through the remaining properties and action the array elements.
First, we have to iterate over properties in an object.
for (var prop in data) {
if (data.hasOwnProperty(prop)) {
// Logic here
}
}
Then it's a simple check to filter out empty array properties
if (data[prop].length == 0) {
delete data[prop]
}
The full solution,
for (var prop in data) {
if (data.hasOwnProperty(prop)) {
if (data[prop].length == 0) {
delete data[prop]
}
}
}
I would prefer to create a new object that omits the empty arrays instead of deleting from the existing object.
var data={key1:[], key2:[], key3:[{key1:"a"}, {key2:"b"}], key4:[{key1:"c"}, {key2:"d"}]}
var cleanData = Object.keys(data).reduce((obj, key) => {
if (data[key] && data[key].length) {
obj[key] = data[key]
}
return obj
}, {})
Using lodash should make this pretty simple:
var filtered = _.omitBy(data, function(value) {
return Array.isArray(value) && value.length == 0;
});
You can now loop through the remaining elements in the filtered object to take further actions on them.
Try this working demo :
var data = {
key1:[],
key2:[],
key3:[
{key1:"a"},
{key2:"b"}
],
key4:[
{key1:"c"},
{key2:"d"}
]
};
for (var i in data) {
if (data[i].length == 0) {
delete data[i]
}
}
console.log(data);

Decypher ES6 const destructuring declaration

Can someone help me decypher this ES6 statement?
const {
isFetching,
lastUpdated,
items: posts
} = postsByReddit[selectedReddit] || {
isFetching: true,
items: []
}
I pulled it from the Redux async example - https://github.com/reactjs/redux/blob/master/examples/async/containers/App.js#L81
The code is simply declaring three constants, getting them from similarly named properties on an object if it is non-empty, otherwise get them from an object literal that acts as default values.
I trust that you are confused over the object like syntax rather than the const keyword.
var|let|const { ... } = ... is an object destructuring declaration.
var|let|const [ ... ] = ... is an array destructuring declaration.
Both are short hand for "break down right hand side and assign to left hand side".
Destructuring can be done on array or object using different brackets.
It can be part of a declaration or as stand-alone assignment.
const { isFetching } = obj; // Same as const isFetching = obj.isFetching
var [ a, b ] = ary; // Same as var a = ary[0], b = ary[1]
[ a ] = [ 1 ]; // Same as a = 1
For object destructuring, you can specify the property name.
For array, you can skip elements by leaving blank commas.
Destructuring can also form a hierarchy and be mixed.
const { items: posts } = obj; // Same as const posts = obj.items
var [ , , c ] = ary; // Same as var c = ary[2]
let { foo: [ { bar } ], bas } = obj; // Same as let bar = obj.foo[0].bar, bas = obj.bas
When destructuring null or undefined, or array destructure on non-iterable, it will throw TypeError.
Otherwise, if a matching part cannot be found, its value is undefined, unless a default is set.
let { err1 } = null; // TypeError
let [ err3 ] = {}; // TypeError
let [ { err2 } ] = [ undefined ]; // TypeError
let [ no ] = []; // undefined
let { body } = {}; // undefined
let { here = this } = {}; // here === this
let { valueOf } = 0; // Surprise! valueOf === Number.prototype.valueOf
Array destructuring works on any "iterable" objects, such as Map, Set, or NodeList.
Of course, these iterable objects can also be destructed as objects.
const doc = document;
let [ a0, a1, a2 ] = doc.querySelectorAll( 'a' ); // Get first three <a> into a0, a1, a2
let { 0: a, length } = doc.querySelectorAll( 'a' ); // Get first <a> and number of <a>
Finally, don't forget that destructuring can be used in any declarations, not just in function body:
function log ({ method = 'log', message }) {
console[ method ]( message );
}
log({ method: "info", message: "This calls console.info" });
log({ message: "This defaults to console.log" });
for ( let i = 0, list = frames, { length } = frames ; i < length ; i++ ) {
console.log( list[ i ] ); // Log each frame
}
Note that because destructuring depends on left hand side to specify how to destructre right hand side,
you cannot use destructring to assign to object properties.
This also excludes the usage of calculated property name in destructuring.
As you have seen, destructuring is a simple shorthand concept that will help you do more with less code.
It is well supported in Chrome, Edge, Firefox, Node.js, and Safari,
so you can start learn and use it now!
For EcmaScript5 (IE11) compatibility, Babel and Traceur transpilers
can turn most ES6/ES7 code into ES5, including destructuring.
If still unclear, feel free to come to StackOverflow JavaScript chatroom.
As the second most popular room on SO, experts are available 24/7 :)
This is an additional response to the already given. Destructuring also supports default values, which enables us to simplify the code:
const {
isFetching = true,
lastUpdated,
items = []
} = postsByReddit[selectedReddit] || {};
Basically:
var isFecthing;
var lastUpdated;
var posts;
if (postsByReddit[selectedReddit]) {
isFecthing = postsByReddit[selectedReddit].isFecthing;
lastUpdated = postsByReddit[selectedReddit].lastUpdated;
posts = postsByReddit[selectedReddit].items.posts;
} else {
isFecthing = true;
items = [];
}

Categories