AngularJs grouping by property - angularjs

I need a way to order a list by its properties.
I have this plunker: http://jsfiddle.net/Tropicalista/aF2aL/1/
but don't know hoe to proceed. I need a way to order the list based on what I select in checkboxes...
function myCtrl($scope){
$scope.friends = [
{
name: "Michael",
gender: "Male",
hair: "Brunette"
},
{
name: "George Michael",
gender: "Male",
hair: "Brunette"
},
{
name: "Gob",
gender: "Male",
hair: "Brunette"
},
{
name: "Tobias",
gender: "Male",
hair: "Black"
},
{
name: "Lindsay",
gender: "Female",
hair: "Blonde"
},
{
name: "Maeby",
gender: "Female",
hair: "Black"
}
];
$scope.orderBy = function(target){
$scope.groups = _.groupBy($scope.friends, target);
}
$scope.activeGroups = {};
}
And this is my html:
<input type="checkbox" ng-click="orderBy('name')" />Name
<input type="checkbox" ng-click="orderBy('gender')" />Gender
<input type="checkbox" ng-click="orderBy('hair')" />Hair
<div data-ng-repeat="(myFilter, users) in groups">
<h2>{{myFilter}}</h2>
<ul>
<li data-ng-repeat="user in users">
{{ user.name }}
</li>
</ul>
</div>

First, for something like this, I much prefer using a radio instead of a checkbox. It is semantically correct. Check boxes indicate that you can group by more than one field, and it doesn't appear, from your question, that you are trying to do that.
Knowing that, you can define your radios like this:
<input type="radio" ng-model="grouping" value="name" />Name
<input type="radio" ng-model="grouping" value="gender" />Gender
<input type="radio" ng-model="grouping" value="hair" />Hair
Now, you can just tell your ng-repeat to group based on a groupedFriends collection:
<div data-ng-repeat="(group, users) in groupedFriends">
<h2>{{group}}</h2>
<ul>
<li data-ng-repeat="user in users">
{{ user.name }}
</li>
</ul>
</div>
And then your controller just watches the grouping variable and group the data:
$scope.$watch('grouping', function() {
$scope.groupedFriends = _.groupBy($scope.friends, $scope.grouping);
});
$scope.grouping = "gender";
Here is a working fiddle.
STEVE HOLT!

You can use groupBy of angular.filter module, It's easy to use, and actually more fast than lodash implementation see: link.
Usage: (key, val) in collection | groupBy: 'property' or nested.property
here's an example:
JS:
$scope.players = [
{name: 'Gene', team: 'alpha'},
{name: 'George', team: 'beta'},
{name: 'Steve', team: 'gamma'},
{name: 'Paula', team: 'beta'},
{name: 'Scruath', team: 'gamma'}
];
HTML:
<ul ng-repeat="(key, value) in players | groupBy: 'team'">
Group name: {{ key }}
<li ng-repeat="player in value">
player: {{ player.name }}
</li>
</ul>
RESULT:
Group name: alpha
* player: Gene
Group name: beta
* player: George
* player: Paula
Group name: gamma
* player: Steve
* player: Scruath
UPDATE: jsbin

Related

Wrong array item after using orderby filter AngularJS

I have an app that works well displaying a list of students. When you click on each name, it displays more info about that particular student. However, if I change the order of names through select options or search, wrong student info is displayed.
Here is my view:
<input type="text" ng-model="expression" placeholder="Search Student" />
<div class="select">
<span>Sort By: </span>
<select ng-model="order" ng-show="students.length > 0">
<option selected value="name">Name A-Z</option>
<option value="-name">Name Z-A</option>
<option value="room">Room (first to last)</option>
<option value="-room">Room (last to first)</option>
</select>
</div>
<div ng-repeat="student in students | orderBy: order | filter:expression">
<div class="info">
<div class="img">
<img ng-src="{{student.image}}">
</div>
<h2 style="color: #007acc;"> Student Details For:</h2>
<hr>
<h2>{{student.name}}</h2>
<a ng-href="#!/students/{{$index}}"><button>View Student
Details</button></a>
</div>
</div>
Here is my Js:
var data = [
{
name: "Andrea Toe",
sex: "Female",
room: 12,
cell: "076 861 6184",
image: "images/female.jpg",
checkin: "June 2016"
},
{
name: "John Doe",
sex: "Female",
room: 3,
cell: "063 961 7190",
image: "images/lebo.jpg",
checkin: "01 Feb 2018"
},
{
name: "James Drew",
sex: "Male",
room: 1,
cell: "076 910 3069",
image: "images/male.jpeg",
checkin: "01 Feb 2018"
}
];
app.controller("studentsCtrl", function($scope){
$scope.students = data;
});
app.controller('studentInfoCtrl', ['$scope', '$routeParams',
function($scope, $routeParams) {
$scope.info = data[$routeParams.id];
}]);
What should I do to get it to display correct info even after using search filter or reordering using oderBy?
It is because, when creating the link to the "student details", you use the $index scope variable.
This $index is introduced by the ng-repeat directive and will represent the:
iterator offset of the repeated element (0..length-1)
(from the documentation linked here)
In short, the $index you use to uniquely identify a student when building the corresponding link to their details page depends entirely on its position in the page. It does not at all identify the resource itself!
What you could do is have an id property assigned to each student along with their name, sex etc., like so:
var data = [{
id: 0,
name: "Andrea Toe",
}, {
id: 1,
name: "John Doe",
}, {
id: 2,
name: "James Drew",
}];
And simply refer to that newly introduced property in the urls you create!
<a ng-href="#!/students/{{ student.id }}"><button>View Student Details</button></a>
Searching and sorting are working fine for me:
var data = [{
id: 1,
name: "Andrea Toe",
sex: "Female",
room: 12,
cell: "076 861 6184",
image: "images/female.jpg",
checkin: "June 2016"
},
{
id: 2,
name: "John Doe",
sex: "Female",
room: 3,
cell: "063 961 7190",
image: "images/lebo.jpg",
checkin: "01 Feb 2018"
},
{
id: 3,
name: "James Drew",
sex: "Male",
room: 1,
cell: "076 910 3069",
image: "images/male.jpeg",
checkin: "01 Feb 2018"
}
];
app = angular.module("myapp", []);
app.controller("studentsCtrl", function($scope) {
$scope.students = data;
});
app.controller('studentInfoCtrl', ['$scope', '$routeParams',
function($scope, $routeParams) {
$scope.info = data.filter(function(d){
return d.id == $routeParams.id;
})[0];
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.1/angular.min.js"></script>
<div ng-app="myapp" ng-controller="studentsCtrl">
<input type="text" ng-model="expression" placeholder="Search Student" />
<div class="select">
<span>Sort By: </span>
<select ng-model="order" ng-show="students.length > 0">
<option selected value="name">Name A-Z</option>
<option value="-name">Name Z-A</option>
<option value="room">Room (first to last)</option>
<option value="-room">Room (last to first)</option>
</select>
</div>
<div ng-repeat="student in students | filter:expression | orderBy: order ">
<div class="info">
<!-- <div class="img">
<img ng-src="{{student.image}}">
</div> -->
<h2 style="color: #007acc;"> Student Details For:</h2>
<hr>
<h2>{{student.name}}</h2>
<a ng-href="#!/students/{{student.id}}"><button>View Student
Details</button></a>
</div>
</div>
</div>

Angulajs: How to apply filter using select form after clicking save button?

In table I'm displaying name, designation and company of employees. I want to use select form to select the name of company. When I select company name and then click save button as result I only want to display names, designations and company of employees that for example work for Google.
Also I want to have displayed number of how many employee is it.
But kinnda got stucked my save button is not working, and also don't have number of employe.
file.html
<body ng-controller="MyController">
<div>
<table>
<tr>
<th style="width:10%">#</th>
<th style="width:20%">Name</th>
<th style="width:40%">Designation</th>
<th style="width:30%">Company</th>
</tr>
<tr ng-repeat="employee in clients">
<td>{{$index + 1}}</td>
<td>{{employee.name}}</td>
<td>{{employee.designation}}</td>
<td>{{employee.company.name}}</td>
</tr>
</table>
</div>
<div>
<ul>
<li>
<h2>Select Company:</h2>
<select ng-model="selectedCompany">
<option ng-repeat="c in companyList" value="{{c.name}}">{{c.name}}</option>
</select>
<h3>You selected: {{selectedCompany}}</h3>
</li>
</ul>
<button ng-click="$ctrl.updateSearch()">Filter</button>
</div>
</body>
file.js
var controllers = angular.module('MyApp.controllers', [])
controllers.controller('MyController', function ($scope) {
$scope.clients = [{
name: 'Brett',
designation: 'Software Engineer',
company: {
name: 'Apple'
}
}, {
name: 'Steven',
designation: 'Database Administrator',
company: {
name: 'Google'
}
}, {
name: 'Jim',
designation: 'Designer',
company: {
name: 'Facebook'
}
}, {
name: 'Michael',
designation: 'Front-End Developer',
company: {
name: 'Apple'
}
}, {
name: 'Josh',
designation: 'Network Engineer',
company: {
name: 'Google'
}
}, {
name: 'Ellie',
designation: 'Internet Marketing Engineer',
company: {
name: 'Apple'
}
}];
$scope.companyList = [{
name: 'Apple',
slug: 'Apple'
}, {
name: 'Google',
slug: 'Google'
}, {
name: 'Microsoft',
slug: 'Microsoft'
}, {
name: 'Facebook',
slug: 'Facebook'
},
];
$scope.updateSearch = function() {
console.log($scope.selectedCompany);
}
});
There are few changes needs to be done on your view, Change your model variables to be different from the array names, such as colorn,sizen and brandn.
<div>
<label>Color:</label>
<select ng-model="colorn" ng-options="option.name for option in colorStatus track by option.slug"></select>
</div>
<div>
<label>Size</label>
<select ng-model="sizen" ng-options="option.name for option in size track by option.slug"></select>
</div>
<div>
<label>Brand</label>
<select ng-model="brandn" ng-options="option.name for option in $ctrl.brand track by option.slug"></select>
</div>
<button ng-click="updateSearch()">Save</button>
Also you can get the values using your $scope variable,
Controller
$scope.updateSearch = function(){
console.log($scope.colorn);
console.log($scope.sizen);
console.log($scope.sizen);
}
DEMO

ng-repeat filter to iterate only over elements with certain property value

I want to ng-repeat through an array, but filter the results so that only the elements that match a certain property value will be displayed. Is this possible, and how?
Here's an example of what I'm trying to do (and obviously failing):
HTML (View)
<ul>
<li ng-repeat="person in people | filter: person.gender == 'male'"></li>
</ul>
<ul>
<li ng-repeat="person in people | filter: person.gender == 'female'"></li>
</ul>
JS (Controller)
$scope.people = [
{name: "John", gender: "male"},
{name: "Sue", gender: "female"},
{name: "Maria", gender: "female"},
{name: "Bob", gender: "male"},
]
So the first list should just print the male names, and the second female, based on the property values.
Is this possible using ng-repeat's filter? Or if not is there another way?
Thanks in advance
try this.
if put :true after filter then filtering do exactly on match value.
function Main($scope) {
$scope.people = [
{name: "John", gender: "male"},
{name: "Sue", gender: "female"},
{name: "Maria", gender: "female"},
{name: "Bob", gender: "male"}
];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app>
<div ng-controller="Main">
<ul>
<li ng-repeat="person in people | filter: { gender: 'male' }:true">
{{person.name}}
</li>
</ul>
</div>
</div>

AngularJS scope variable for object in filter

I'm trying to change which property I'm filtering by assigning the property name to a variable, but it's not working. Is there a way to accomplish this without writing my own filter? codepen
<div ng-app="app" ng-controller="main as m">
<input ng-model="keyword"/>
<p>Property: {{m.property}}</p> <!-- resolves to 'name' -->
<!-- does not work-->
<div ng-repeat="o in m.objects | filter:{m.property:keyword}">
{{o.name}}
</div>
<hr/>
<!-- works-->
<div ng-repeat="o in m.objects | filter:{name:keyword}">
{{o.name}}
</div>
</div>
If I understand your question right, I think this is what you are looking for.
Relevant code:
HTML:
<select ng-model="property" ng-change="clearSearch()">
<option>name</option>
<option>age</option>
<option>city</option>
</select>
<input ng-model="search[property]" />
<div class="box">
<div class="item" ng-repeat="item in data | filter:search">
{{item.name}} | {{item.age}} | {{item.city}}
</div>
</div>
Javascript:
var app = angular.module("myapp", []);
app.controller("main", function($scope){
$scope.search = {};
$scope.clearSearch = function(){
$scope.search.name = "";
$scope.search.age = "";
$scope.search.city = "";
}
$scope.property = "name";
$scope.data = [
{
name: "Robert",
age: 23,
city: "Orem"
},
{
name: "Alice",
age: 44,
city: "Nephi"
},
{
name: "Susan",
age: 12,
city: "Odgen"
},
{
name: "Henry",
age: 63,
city: "South Jordan"
},
{
name: "Frank",
age: 35,
city: "Provo"
},
{
name: "Albert",
age: 32,
city: "Payson"
},
];
});
In short, <div ng-repeat="o in m.objects | filter:{m.property:keyword}"> {m.property:keyword} is not a correct expression
Have you tried filter without the "m." in "m.property"?
<div ng-repeat="o in m.objects | filter:{property:keyword}">

AngularJS filter nested ng-repeat based on repeated object properties

I have an array of restaurant objects and I want to list them by grouping their cities
My object is like;
restaurant = {
id: 'id',
name: 'name',
city: 'city'
}
This HTML Markup can give some info about what I want to do.
<div ng-repeat="restaurant in restaurant | filter: ???">
<div class="header">
<h1 ng-bind="restaurant.city"></h1>
<a>Select All</a>
</div>
<div class="clearfix" ng-repeat="???">
<input type="checkbox" id="restaurant.id" />
<label ng-bind="restaurant.name"></label>
</div>
</div>
Can I do it with one single array or do i need to create seperate city and restaurant arrays to do it?
If you want to group restaurants by city, you can use groupBy of angular.filter module.
Just add the JS file from here: http://www.cdnjs.com/libraries/angular-filter to your project and use following code.
var myApp = angular.module('myApp',['angular.filter']);
function MyCtrl($scope) {
$scope.restaurants = [
{id: 1, name: 'RestA', city: 'CityA'},
{id: 2, name: 'RestB', city: 'CityA'},
{id: 3, name: 'RestC', city: 'CityC'},
{id: 4, name: 'RestD', city: 'CityD'}
];
}
<div ng-controller="MyCtrl">
<ul ng-repeat="(key, value) in restaurants | groupBy: 'city'">
<b>{{ key }}</b>
<li ng-repeat="restaurant in value">
<i>restaurant: {{ restaurant.name }} </i>
</li>
</ul>
</div>
I've created JSFiddle for you with working example.

Resources