Custom sorting of objects by key in ng-repeat - javascript

I have an object stored in $scope.addresscards inside a controller. The js is given below:
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.addresscards = {
"work_address": {
"location":"workLoc",
"address": "workAddr",
"flat_no": "worknumber",
"landmark": "workLandmark"
},
"random1_address": {
"location":"someLoc",
"address": "SomeAddr",
"flat_no": "Somenumber",
"landmark": "someLandmark"
},
"home_address": {
"location":"homeLoc",
"address": "homeAddr",
"flat_no": "homenumber",
"landmark": "homeLandmark"
},
"random2_address": {
"location":"someLoc2",
"address": "SomeAddr2",
"flat_no": "Somenumber2",
"landmark": "someLandmark2"
}
};
}
I'm using ng-repeat to display the addresses. Here is the HTML:
<div ng-controller="MyCtrl">
<ul ng-repeat="(addressKey,addressVal) in addresscards">
<li>{{addressKey}} has :: {{addressVal.location}},{{addressVal.address}}, {{addressVal.location}}, {{addressVal.address}}</li>
</ul>
</div>
My output is:
home_address has :: homeLoc, homeAddr, homeLoc, homeAddr
random1_address has :: someLoc, SomeAddr, someLoc, SomeAddr
random2_address has :: someLoc2, SomeAddr2, someLoc2, SomeAddr2
work_address has :: workLoc, workAddr, workLoc, workAddr
I want to display the output such that, if the object has home_address it should be displayed 1st, then if the object has work_address it should be displayed. Then rest of the object should be showed alphabetically.
Here is expected result that I want to display:
home_address has :: homeLoc, homeAddr, homeLoc, homeAddr
work_address has :: workLoc, workAddr, workLoc, workAddr
random1_address has :: someLoc, SomeAddr, someLoc, SomeAddr
random2_address has :: someLoc2, SomeAddr2, someLoc2, SomeAddr2
I tried it using orderBy, It doesn't work on objects. How do I achieve this?

You can add a property to your address objects
$scope.addresscards = {
"work_address": {
"location":"workLoc",
"address": "workAddr",
"flat_no": "worknumber",
"landmark": "workLandmark",
"sort" : "2"
},
"random1_address": {
"location":"someLoc",
"address": "SomeAddr",
"flat_no": "Somenumber",
"landmark": "someLandmark"
},
"home_address": {
"location":"homeLoc",
"address": "homeAddr",
"flat_no": "homenumber",
"landmark": "homeLandmark",
"sort" : "1"
},
"random2_address": {
"location":"someLoc2",
"address": "SomeAddr2",
"flat_no": "Somenumber2",
"landmark": "someLandmark2"
}
};
and in your ng-repeat you can orderBy multiple fields first by sort to display home and work address first and then by address key for alphabetical order.
<ul ng-repeat="(addressKey,addressVal) in addresscards | orderBy:['sort','addressKey']">
<li>{{addressKey}} has :: {{addressVal.location}},{{addressVal.address}}, {{addressVal.location}}, {{addressVal.address}}</li>
</ul>
or in your controller you can sort all other addresses and append home and work address to the beginning of your list.
Plunker

Related

Script that stores multiple values from JSON dictionary into array

I have over 1000s of dictionaries in JSON after an API request. How do create a script that iterates over all dictionaries and stores the values of one of the key-value pairs?
example
},"testData"
{
"testJSON": "test",
"phone": null,
"address: "122 main st"
}, "testData1"
{
"testJSON": "test1",
"phone": null,
"address: "123 main st"
},
For example, how do I get the "address" field of every single JSON dictionary?
You need to first parse your json, like this:
var json = JSON.parse(jsonString);
then you could iterate your json keys and do something with the root values, like such:
for(var el in json)
{
console.log(json[el]) // will log every root element
console.log(json[el].phone) // will log phone of each element
}
example fiddle: https://jsfiddle.net/1ky6dzen/
In python this can be done like this:
data = [{
"testJSON": "test",
"phone": null,
"address: "122 main st"
}, "testData1"
{
"testJSON": "test1",
"phone": null,
"address: "123 main st"
}]
my_array = []
for obj in data:
my_array.append(obj['address'])
print(my_array)
Hope this is what you were after :)
Use forEach loop to iterate over the keys of the object
var a={"testData":
{
"testJSON": "test",
"phone": null,
"address": "122 main st"
}, "testData1":
{
"testJSON": "test1",
"phone": null,
"address": "123 main st"
}};
Object.keys(a).forEach(e=>console.log(a[e].address))

Angularjs orderby on toggle and removing orderby

So I am trying to use the orderby function of angularjs. Currently I have an original data set.
$scope.customers = [
{"name" : "Bottom-Dollar Marketse" ,"city" : "Tsawassen"},
{"name" : "Alfreds Futterkiste", "city" : "Berlin"},
{"name" : "Bon app", "city" : "Marseille"},
{"name" : "Cactus Comidas para llevar", "city" : "Buenos Aires"},
{"name" : "Bolido Comidas preparadas", "city" : "Madrid"},
{"name" : "Around the Horn", "city" : "London"},
{"name" : "B's Beverages", "city" : "London"}
];
$scope.reverse= false;
$scope.toggleOrder = function(){
$scope.reverse=!$scope.reverse;
}
If I use the following to display my customers, I would get the array reverse ordered by the city. Currently I could click on the toggle button and reverse the array if wanted to.
<button ng-click="toggleOrder()">ToggleReverse</button >
<li ng-repeat="x in customers | orderBy : 'city': reverse">{{x.name + ", " + x.city}}</li>
But now the issue is if I didn't want the orderBy function at all. If I wanted to get my original customers data without any order how could I do that with the same toggleOrder function?
For instance, When I load the data it would be the original array. If 1st click of the toggleOrder button, it would sort in based on city, 2nd click of the toggleOrder button would reverse sort the city, and third click of the toggleOrder button would have no sort and give me the original array, and so on.
If the orderBy function isn't the best to go by let me know.
Any help would be great!
I'm not sure why you want to add this feature on your application, but here you go:
(function() {
'use strict';
angular
.module('app', [])
.constant('BUTTON_VALUES', {
1: 'Ascending',
2: 'Descending',
3: 'No order',
})
.controller('MainCtrl', MainCtrl);
MainCtrl.$inject = ['$scope', 'BUTTON_VALUES'];
function MainCtrl($scope, BUTTON_VALUES) {
$scope.customers = [
{
"name": "Bottom-Dollar Marketse",
"city": "Tsawassen"
},
{
"name": "Alfreds Futterkiste",
"city": "Berlin"
},
{
"name": "Bon app",
"city": "Marseille"
},
{
"name": "Cactus Comidas para llevar",
"city": "Buenos Aires"
},
{
"name": "Bolido Comidas preparadas",
"city": "Madrid"
},
{
"name": "Around the Horn",
"city": "London"
},
{
"name": "B's Beverages",
"city": "London"
}
];
$scope.btnValue = BUTTON_VALUES[3];
$scope.reverse = true;
$scope.orderParam = '';
var increment = 0;
$scope.toggleOrder = function() {
increment++;
$scope.btnValue = BUTTON_VALUES[increment];
switch (increment) {
case 1:
case 2:
$scope.orderParam = 'city';
$scope.reverse = !$scope.reverse;
break;
case 3:
$scope.orderParam = '';
increment = 0;
break;
}
}
}
})();
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
</head>
<body ng-controller="MainCtrl">
<button ng-click="toggleOrder()">{{btnValue}}</button>
<pre ng-bind-template="Order - {{orderParam}}"></pre>
<pre ng-bind-template="Reverse? {{reverse}}"></pre>
<hr>
<li ng-repeat="x in customers | orderBy : orderParam: orderParam && reverse">{{x.name + ", " + x.city}}</li>
</body>
</html>
Note: I added a constant as an example to demonstrate how you can handle your button name.
I hope it helps.
So, you want the original order the third time you click on the order by button. Seems doable but complicated. Maybe instead you should have another button that is labeled "original order" and a hidden column that lists the index of your original order. Pushing that button orders by that original index.
/edited I rather use another approach of angualrjs filters which is basically taking string as param and matching it to the object in list.
jsfiddle.net/2q14sryb
Hope it works!

json not getting printed in the correct order [duplicate]

This question already has answers here:
Iterate over jQuery JSON object in original order
(4 answers)
Closed 6 years ago.
I have a json file named places.json. the contents are
{
"Europe": [
{
"name": "London",
"country": "England"
},
{
"name": "Paris",
"country": "France"
}
],
"Asia": [
{
"name": "Delhi",
"country": "India"
},
{
"name": "Tokyo",
"country": "Japan"
}
],
"Africa": [
{
"name": "CapeTown",
"country": "SouthAfrica"
},
{
"name": "Abuja",
"country": "Nigeria"
}
]
}
This is just a part of the file.The file quite big.
Now I am getting this file through angular js as
myApp.controller('cityController', ['$scope', '$http', function ($scope, $http) {
$http.get('places.json').success(function (data) {
$scope.items = data;
}).error(function (data) {
console.log(data);
});
}]);
And then I am printing the data in my html page as
<div ng-repeat="(key,val) in items">
<p> {{key}}</p>
<div ng-repeat="place in val">
<p>{{place.name}}</p>
<p>{{place.country}}</p>
</div>
</div>
I am getting the output but not in the correct order. (i.e) I am getting Asia printed first with its places and Europe and so on. Why is this happening. How can I get printed in the correct order.
the order of keys in an object is not defined. most browsers implement them ordered alphabatically, but they may be returned in which order they ever want.
if you need them to be ordered you will have to put them into an array instead and put the name of each into a new property (e.g. "name")
Definition of an Object from ECMAScript Third Edition (pdf):
4.3.3 Object An object is a member of the type Object. It is an unordered collection of properties each of which contains a primitive
value, object, or function. A function stored in a property of an
object is called a method.

Parsing Uneven data/ json object using ng-repeat

fiddle here http://jsfiddle.net/prantikv/1nvdzv24/9/
i have some uneven data like so
[{
"fname": "Tonja", //common
"lname": "Mize",
"tel": "(963)784-1098",
"address": "3999 Quis Ln",
"city": "Sebring",
"state": "MI",
"zip": 76593
},
{
"fname": "Stella", //common
"Othername": "Lester",
"mobile": "(936)898-2886"
}];
notice only the fname property is common between the two objects
so when i do this
<li ng-repeat="(key,val) in populationList | filter:name">
{{ val.**fname**}}
</li>
i do get the fname but the data is uneven so i cannot figure out how to go through over each object. also the length of the object is different as well.
what i want to do is to filter the data over a select list
<select ng-model="name">
<option value="Tonja" selected="Tonja">Tonja</option>
<option value="Stella">Stella</option>
</select>
but i am unable to figure out a way to display the unmatched properties of objects
is there a way i get all the key:value pairs on the sub data dynamically?
WORKING DEMO
Your Html,
<div ng-app='app'>
<div ng-controller="DemoCtrl">
<select ng-options="item.fname for item in populationList | fieldList:'fname'" ng-model="myItem" ng-change="changeSelection(myItem)">
</select>
<li ng-repeat="key in availableKeys">
{{selectedObject[key]}}
</li>
</div>
</div>
JS
angular.module('filters',[]).
filter('fieldList', function() {
return function(populationList, parameter) {
var filteredArray = [];
angular.forEach(populationList, function(value, index) {
if(value.hasOwnProperty(parameter)) {
filteredArray.push(value);
}
});
return filteredArray;
};
});
angular.module('app',['filters'])
.controller('DemoCtrl', function($scope) {
$scope.changeSelection = function(item) {
$scope.selectedObject = item;
$scope.availableKeys = Object.keys($scope.selectedObject);
};
$scope.populationList = [{
"fname": "Tonja", //common
"lname": "Mize",
"tel": "(963)784-1098",
"address": "3999 Quis Ln",
"city": "Sebring",
"state": "MI",
"zip": 76593
},
{
"fname": "Stella", //common
"Othername": "Lester",
"mobile": "(936)898-2886"
}];
});

How to dynamically populate display objects in Angular JS based on properties from the JSON object.?

I am reading the below json value from a module.js
.controller('home.person',['$scope','$filter','personResource',function($scope,$filter,personResource) {
$scope.searchPerson = function() {
var params = $scope.search || {};
params.skip=0;
params.take =10;
$scope.personDetails =
{
"apiversion": "0.1",
"code": 200,
"status": "OK",
"mydata": {
"myrecords": [
{
"models": [
{
"name": "Selva",
"dob": "10/10/1981"
}
],
"Address1": "ABC Street",
"Address2": "Apt 123",
"City": "NewCity1",
"State": "Georgia"
},
{
"models": [
{
"name": "Kumar",
"dob": "10/10/1982"
}
],
"Address1": "BCD Street",
"Address2": "Apt 345",
"City": "NewCity2",
"State": "Ohio",
"Country":"USA"
},
{
"models": [
{
"name": "Pranav",
"dob": "10/10/1983"
}
],
"Address1": "EFG Street",
"Address2": "Apt 678",
"City": "NewCity3",
"State": "NewYork",
"Country":"USA",
"Zipcode" :"123456"
}
]
}
}
}
}])
Now i am able to statically build the UX. But my each record set's key value pair count is different. So i want to build my html dynamically as per the current record set's count.Country & Zipcode is not exist in all records so i need to build dynamically the build and populate the html output.Most of the time, my json output is dynamic. Instead of persondetails, i may get the json output of a product details instead of PersonDetails.
<div ng-show="personDetails.mydata.myrecords.length > 0" ng-repeat="recordSingle in personDetails.mydata.myrecords">
<div >
<span >Address1: {{recordSingle.Address1}}</span>
<span >Address2: {{recordSingle.Address2}}</span>
<span>City: {{recordSingle.City}}</span>
<span>State: {{recordSingle.State}}</span>
<span>Country: {{recordSingle.Country}}</span>
<span>Zipcode: {{recordSingle.Zipcode}}</span>
</div>
</div>
One way is to use ng-if statement, for the optional span elements:
<span ng-if="recordSingle.Address1">Address1: {{recordSingle.Address1}}</span>
[Update #1: updated based on revised comments to question]
[Update #2: fixed typos in function and included plunkr]
I now understand that you want to dynamically build the display objects based on properties from the JSON object. In this case, I would iterate through the properties of the object. I would use a function to produce this array of properties for each object so that you can filter out any prototype chains. I would also remove out any unwanted propoerties, such as the internal $$hashKey and perhaps the array objects e.g.
In your controller:
$scope.getPropertyNames = getPropertyNames;
function getPropertyNames(obj) {
var props = [];
for (var key in obj) {
if (obj.hasOwnProperty(key) && !angular.isArray(obj[key]) && key !== '$$hashKey') {
props.push(key);
}
}
return props;
}
Then in your HTML view:
<div ng-repeat="record in personDetails.mydata.myrecords">
<div ng-repeat="prop in getPropertyNames(record)">
<span ng-bind="prop"></span>: <span ng-bind="record[prop]"></span>
</div>
</div>
This works for me... see this plunker. It is displaying each of the properties of the object in the array dynamically (you could have any property in the object). Is this not what you are trying to achieve?

Categories

Resources