AngularJS change property value based on another array - json

I have a json data structured as:
$scope.items = [{"Color" : "Red", "Size": "Small" }, { "Color" : "Orange" "Size": "Small"}, {"Color" : "Green" "Size": "Extra-Large"}];
then I have a properties json data:
$scope.properties = [{"PropertyName" : "Color", "FilteredAs" : "AllColors"}, {"PropertyName" : "Size", "FilteredAs" : "AllSizes"}]
I am doing a server-side filtering that's why there's a FilteredAs property in my properties json data. What I want to happen is:
If (items.key = properties.PropertyName)
example: "Color" (which is the first property in the items array) == "PropertyName" : "Color"
then that corresponding object's FilteredAs property in the properties array is "FilteredAs" : "AllColors", AllColors will be changed to "Red".
Any ideas on how to achieve this? Thanks!
EDIT: This is what I have for now:
angular.forEach($scope.items, function (value, key) {
for (var i = 0; i<= $scope.properties.length; i++) {
if ($scope.properties[i].PropertyName == $scope.items[value]) {
$scope.properties[i].SearchText = $scope.items[key];
}
}

If I understand it correctly as $scope.properties is an array you would need to foreach through the objects and identify the property that is for Color. Below should do what your looking for.
$scope.properties.forEach(function (property) {
if (property.PropertyName === "Color") {
property.FilteredAs = "Red" // Or whatever value or variable you have got back from webservice
}
});
Hope I have understood correctly and that this helps.
EDIT:
Because $scope.items is an array angular.forEach doesn't work that same way as it does for an object. You would need to change the code to be something like below.
angular.forEach($scope.items, function (item) {
for (var i = 0; i<= $scope.properties.length; i++) {
if ($scope.properties[i].PropertyName == "Color") {
$scope.properties[i].SearchText = item.Color;
}
}
With this though the value of $scope.properties[i].SearchText will always be the last Color in the $scope.items array. You might need to add some checked to ensure the right color is selected from the array with what your WebService says.

Related

Restructuring JSON Response in Angular 2+

I'm currently receiving a web api JSON response that is heavily nested and I want to restructure it plucking out only the data I need and making it more simple.
How would I do this in Angular 2+/Typescript?
Any help would be really appreciated.
Say I have something like this:
"O1": {
"P1": "Something",
"A1": [{
"P2": "Something",
"A2": [{
"P3": "Something"
}]
}]
"P4": "Something"
}
and I want to restructure it to this :
"O1": {
"P1": "Something",
"P2": "Something",
"P3": "Something"
}
Can I rebuild the model in a class in the constructor? If so, I haven't been able to find anything online as of yet.
Let me know if I need to provide any further info.
Thanks
Let's flatten the initial object using the snippet which was proposed. And then we can filter those properties which we need to include in the final object:
function filterObj(obj: any, propsForFilter: string[]) {
const result = {};
for (let prop in obj) {
const filteredProp = propsForFilter.find(p => prop.includes(p));
if (filteredProp) {
result[filteredProp] = obj[prop];
}
}
return result;
}
const flattened = flattenObject(obj);
console.log(flattened, filterObj(flattened, ['P1', 'P2']));
This method filterObj accepts the array of properties in order to include them in the final result. Hope this will be helpful for you.
Found this snippet in github:
https://gist.github.com/penguinboy/762197
var flattenObject = function(ob) {
var toReturn = {};
for (var i in ob) {
if (!ob.hasOwnProperty(i)) continue;
if ((typeof ob[i]) == 'object') {
var flatObject = flattenObject(ob[i]);
for (var x in flatObject) {
if (!flatObject.hasOwnProperty(x)) continue;
toReturn[i + '.' + x] = flatObject[x];
}
} else {
toReturn[i] = ob[i];
}
}
return toReturn;
}

Add new attribute to JSON

Using Node js and Sequelize ORM, i'm getting a data set. I need to add a new attribute to received data and send it to client side. This is what i tried.
Code Block 1
var varAddOns = { "id" : 5, "Name" : "Cheese"};
global.meal.findOne(
{
where: { id: 5 }
}).then(varMeal => {
var obj = {};
obj = varMeal;
obj.addons = varAddOns;
res.send(obj);
});
It returns a json like below. (Actually it does not contain "addons" data)
Code Block 2
{
"id": 12,
"mealName": "Burger",
"description": "Oily food",
}
but actually what i want is,
Code Block 3
{
"id": 12,
"mealName": "Burger",
"description": "Oily food",
"addons" : {
"id" : 5,
"Name" : "Cheese"
}
}
I tried something like below and it also wont work. (It returns same json as "Code Block 2'.)
Code Block 4
var newJson = {};
newJson = JSON.stringify(varMeal);
newJson['addons'] = varAddOns;
var retVal = JSON.parse(newJson);
res.send(retVal);
Can you help me to figure out, where the issue is?
EDIT
Code Block 5
var newJson = {};
newJson = varMeal;
newJson['addons'] = varAddOn;
var retVal = newJson;// JSON.parse(newJson);
res.send(retVal);
I tried 'Code block 5' as well. Same result comes out as 'Code block 2'. When I use JSON.parse(newJson), it was thrown an error. (Error is Unexpected token o in JSON at position 1)
You need to call .get on your model instance, and then attach extra properties to it:
var varAddOns = { "id" : 5, "Name" : "Cheese"};
global.meal.findOne(
{
where: { id: 5 }
}).then(varMeal => {
var obj = {};
obj = varMeal.get();
obj.addons = varAddOns;
res.send(obj);
});
A few things:
When you call findOne, Sequelize return a model instance, not a plain JS object with your data.
If you want to add extra properties to send to your user, you will first need to convert your model instance to a JS object with your data. You can do this by calling varMeal.get(). From there, you can add extra properties to it.
There is no need to prepend your variables with "var". It would be better to simply name your variable meal
you need the JSON to be an object when you are declaring newJson['addons'] as a nested object
Have you tried (in code block 4) not stringifying varMeal?

React state and JSON and arrays => faulty result

Edit: So, I found the solution to my initial question, which made me realize I have another issue.
It seemed to be easier than I thought
setNumbers(e) {
e.preventDefault();
var already_exists = false;
var ls_data = this.state.storedNumbers;
var rname = document.getElementById('name').value;
var rnumb = document.getElementById('nummer').value;
var ls_key = this.state.ls_key;
for (key in ls_data) {
if(ls_data.hasOwnProperty(key) === true) {
if(ls_data[key].name === rname) {
if(ls_data[key].Number === rnumb) {
already_exists = true;
}
}
}
}
if(!already_exists) {
ls_key++;
ls_data[ls_key] = {
name: rname,
Number: rnumb
};
localStorage.setItem("ls_numbers", JSON.stringify(this.state.storedNumbers));
localStorage.setItem("ls_key", ls_key);
this.setState({
ls_key: localStorage.getItem("ls_key"),
});
}
}
But now my issue is, that I can't iterate over it, because it is a nested object and not an array. So .map will not work (this.state.storedNumbers.map is not a function).
Changing storedNumber to an array sadly doesn't solve the issue, as
ls_data[ls_key] = {
name: rname,
Number: rnumb
};
isn't working in an array. So now my question is. Can I use my ls_key variable to create a name object in my array? Using the code above results in:
[
null,
{
"name" : "Person 1",
"Number" : "XXXXXXXX"
},
{
"name" : "Person 2",
"Number" : "XXXXXXXX"
}
]
while the array should look like:
[
"1": {
"name" : "Person 1",
"Number" : "XXXXXXXX"
},
"2": {
"name" : "Person 2",
"Number" : "XXXXXXXX"
}
]
Or is there a way to iterate over the nested JSON result, as .map does for an array?
Alright then, just figured it out myself:
The reason my data got malformed (initial question), still in the blue about that. I've changed a lot of code and reverted to the original code again, et voila, miraculously it all worked. Can't tell you what the difference was. After that I could easily simplify the code as shown in the edited question.
To iterate over the data, the code below was my solution. Should you have a more cleaner solution, let me know!
{this.state.storedNumbers.length < 1
? <li className='list-group-item'><strong>Geen recente nummers...</strong><span className='pull-right'><span className='glyphicon glyphicon-warning glyph-xl'></span></span></li>
: Object.keys(this.state.storedNumbers).map((number) => {
return (
<div className='item' key={number}>
<a className='list-group-item list-link'>
<strong>{this.state.storedNumbers[number].name}</strong> - ({this.state.storedNumbers[number].Number})
</a>
<span className='button-delete glyph-xl'>
<i className='glyphicon glyphicon-trash glyph-xl' aria-hidden='true'></i>
</span>
</div>
)})
}

Searching in JSON for specific value using AngularJS

I am trying to filter my JSON object by a specific property value set to Log: true
If an object has this property set to false, I want to filter it out. Here is an example of the JSON structure:
$scope.Main =
{
"MyBook" :
{
"Title": "The Road",
"Type" : "Text",
"Log" : false
},
"MyCat":
{
"Name" : "Penny",
"Type" : "Pet",
"Log" : true
},
"Car":
{
"Make" : "Toyota",
"Model" : "Camry",
"Type" : "Vehicle",
"Log" : false
}
}
As you can see, the objects themselves are not similar, but they all contains a log property.
Online Demo
This is how I would filtered an object while searching for a property value equals true
var sampleObj = {/* you sample object*/};
var filtered = Object.keys(sampleObj).reduce(function(arr,prop){
if(Object.keys(sampleObj[prop])
.filter(function (p) {return p === "Log";})){
if(sampleObj[prop].Log==true){
arr.push(sampleObj[prop]);
}
}
return arr;
},[]);
console.log(filtered);
Since you are using angular probably you would want to use a custom filter instead:
Something close to:
custom filter:
angular.module('myApp', []).filter('myFilter', function() {
return function(sampleObj, param1) {
return Object.keys(sampleObj).reduce(function(arr,prop){
if(Object.keys(sampleObj[prop])
.filter(function (p) {return p === "Log";})){
if(sampleObj[prop].Log==param1){
arr.push(sampleObj[prop]);
}
}
return arr;
},[]);
};
});
and in your html
<li ng-repeat="item in sampleObj | myFilter: true">
try using the underscorejs library.
you can use some of their functions like _.filter and _.has to filter the list.
here's an example of how i would try to implement that object:
var filtered = _.filter($scope.Main, function(obj) {
return _.has(obj, "Log") && obj.Log;
}
Use a custom Angular filter:
.filter('filterLog', function(){
return function(items){
for (var item in items) {
if (items[item].Log === false) delete items[item];
}
return items;
}
})
Then, in your view, you could output the filtered list like so:
<li ng-repeat="(key, value) in Main | filterLog">{{value}}</li>
If you need to use it in a controller, you could:
$scope.filtered = $filter('filterLog')($scope.Main);
Demo

detecting if object has children or not

I have the following problem, i have to know if an element has children or not. if the object looks a followed:
Object [
Object[["name" : "lisa"], ["age" : "14"], ["gender" : "female"]],
Object[["name" : "bjorn"], ["age" : "40"], ["gender" : "male"]],
Object[["name" : "zoe"], ["age" : "24"], ["gender" : "female"]]
]
it should follow 1 route, if it looks as following:
Object[["name" : "lisa"], ["age" : "14"], ["gender" : "female"]]
it should follow another route. In general, the first example object is a collection of the second example object. so in other words:
if (example 1) {
...do this...
} else if (example 2) {
...do that...
}
Your syntax looks weird. The normal way of defining an object (eg hashmap) would be
var myObj:* = {}
//Or if it's an array, as in your case;
var myArr:Array = [{name: "lisa", age:14, gender:"female"}, {...etc}]
There's no easy way to see if an object has entries however. This is how I usually do it;
var hasEntries:Boolean = false;
for(var key:String in myObj) {
hasNodes = true;
break;
}