I am trying to groupby an array of objects w.r.t to one property of the object. What is the best way to acheive it?
sample:
{
name: "India",
capital: "New Delhi",
cities:[{
name: "city1",
state:"state1"
},
{
name:"city3",
state:"state2"
}
....
{
name:"city56",
state:"state1"
}]
}
What's the best way to display it grouped by state? Should I use pipes or group the array using typescipt? Is there grouping pipe available in angular4?
There are several ready to use pipe collections for Angular2+ which include groupBy pipes. Two possible examples are:
ng-pipes
<div *ngFor="let item of items | groupBy: 'state'">
angular-pipes
<div>{{ arrayObject | groupBy: 'state' }}</div>
You can use lodash like this:
_.groupBy(myCityList, 'state')
Note that myCityList is the internal list that has the state property, like so:
const myCityList = [
{
name: "city1",
state:"state1"
},
{
name:"city3",
state:"state2"
},
{
name:"city56",
state:"state1"
}];
Related
I don't understand why the .name is happening in the model instead of the filter. I don't get what is happening behind the scenes when I create nameText.name and bind it to my data. How is my filter actually working?
<input type="text" data-ng-model="nameText.name" />
<input type="text" data-ng-model="nameText.city" />
<li data-ng-repeat="customer in customers | filter:nameText>
<script>
function FilteringController($scope) {
$scope.customers = [
{ name: 'Dave Jones', city: 'Phoenix' },
{ name: 'Jamie Riley', city: 'Phoenix' },
{ name: 'Heedy Wahlin', city: 'Chandler' },
{ name: 'Thomas Winter', city: 'Seattle' }
];
</script>
nameText is an object with the properties name and city in this case. These properties are filled by the input fields. You're filtering your list using an object. What Angular does in this case, is filter the objects in the list using the properties with the matching names. So, for example, if nameText.city is Phoenix, the items in the list are filtered so that only the items with Phoenix for the city property are left. This works the same for name and both can be combined.
Update to answer question in comments: For the exact implementation, I'd suggest looking through the Angular source code. The specific case for a filter using an object is here. What this roughly does is get all the properties of the object passed in as the filter (nameText in your case). It then goes through the list of objects to filter and select all the objects that have properties with values that match the properties that you are searching for. In the source code I referred, you can also see how the other types of search filters you may pass would be handled.
Suppose that I have an Angular view that allows a user to check books out of a library. My data model consists of two arrays of Book entities which each have a unique ID field plus a title field. The first array contains an entity for every book in the library and the second array contains an entity for every book that the user has checked out.
libraryBooks = [{
id: 0,
title: "The Adventure of Tom Sawyer"}, {
id: 1,
title: "Moby Dick" }, {
id: 2,
title: "To Kill a Mockingbird" }, {
id: 3,
title: "The Three Little Pigs" }];
checkedOutBooks = [{
id: 0,
title: "The Adventure of Tom Sawyer"}, {
id: 3,
title: "The Three Little Pigs" }];
In short, the library has four books and the user has checked out two. If I want to list the books from both arrays, I can write this:
<h1>Library Books</h1>
<div ng-repeat="book in libraryBooks">
{{ book.title }}
</div>
<h1>Checked out Books</h1>
<div ng-repeat="book in checkedOutBooks">
{{ book.title }}
</div>
Suppose I want to display a third list: the subset of library books that the user has not checked out.
I have seen examples where the Angular "filter" is used to specify one particular value that should not be matched in order to narrow down a list, but in this case, I want to exclude multiple values, so how do I go about doing this?
I have seen examples where a custom filter is added to an Angular module, but I think that in this case, any custom filter should be scoped to this controller.
I've got this figured out. The solution is to write a filter function and attach it to $scope like so:
function filter_notCheckedOut(book) {
var i;
for (i = 0; i < that.libraryBooks.length; i += 1) {
if (that.libraryBooks[i].id === page.id) {
return false;
}
}
return true;
}
In the view, it can then be referenced like this:
<h1>Books not checked out</h1>
<div ng-repeat="book in libraryBooks | filter:filter_notCheckedOut">
{{ book.title }}
</div>
<ul ng-repeat="cate in restaurant.categories"><li>{{cate}}</li>
<li ng-repeat="menuItem in restaurant.menuItems" ng-show="menuItem.category == cate">{{menuItem.name}}</li></ul>
I want one ng-repeat loop inside another and to show the menu only if the menuItem is in the category. I only have items in the first category loop, and empty for all the other categories.
Categories and menuItem are 2 different arrays. If the menuItem's category is under the current category it should be added to the page.
menuItems = {{name: dish1, category:soup},
{name: dish2, category:beef}}
categories = {beef, soup}
#show-me-the-code : Bill Bi has two different array. So the best option to achieve this is by filter in inside loop as stated in my comment.
Here is the final code with filter for inside loop. I am including fiddler for quick reference.
<div ng-app ng-controller="testCtrl">
<ul ng-repeat="cate in categories">
<li>{{cate}}</li>
<li ng-repeat="menuItem in menuItems | filter:{category: cate}">{{menuItem.name}}</li>
</ul>
</div>
function testCtrl($scope) {
$scope.menuItems = [{name: 'dish1', category:'soup'},
{name: 'dish2', category:'beef'}];
$scope.categories = ['beef', 'soup']
}
Fiddle : JSFiddle
I would change my data representation to match what you are actually trying to display like so:
$scope.restaurant = {
categories: [{
name: "beef",
menuItems: [{
name: "dish1",
"price": "$10"
}, {
name: "dish2",
"price": "$15"
}]
}, {
name: "soup",
menuItems: [{
name: "dish1",
"price": "$20"
}, {
name: "dish2",
"price": "$25"
}]
}]
};
This way you could easily match your two nested loops like this:
<div ng-app ng-controller="testCtrl">
<ul ng-repeat="cate in restaurant.categories">
<li>{{cate.name}}</li>
<li ng-repeat="menuItem in cate.menuItems">{{menuItem.name}} - {{menuItem.price}}</li>
</ul>
</div>
Check out this fiddle if you would like to see it in action.
If you need to stick to your JSON data, you will have to do filtering to pull the contents you want to display.
Iam Learning AngularJs ...
Example : -
My Json Having an array with some values as types :-
Lets Say A Restaurant would be Mexican or Italian Etc
My example
{
name:'res 123',
description:'Italian Rest'
types:['Mexican','Indian']
}
<input type="checkbox" data-ng-model="Mexican"/> // Iam Using Textbox Oncheck Filter Need to Filter all the Objects with types:['Mexican']
Filter Code :-
<div class="col-xs-12" data-ng-repeat="obj in objs| filter : objs.types[1]: Mexican" > <!-- Filter applied Like this -->
Realted looping
</div>
How can i Apply filter by taking the types:['Mexican'] value as Input for Filter On check ?
A built-in filter in Angular accepts a hash that specifies by what properties to match against each element in an array.
So, if you have an array of restaurants:
var restaurants = [
{ name: "foo", types: ["Mexican", "Indian"] },
{ name: "bar", types: ["Mexican"] },
{ name: "baz", types: ["Italian"] }
];
then if you need to filter by name, the input to filter would be {name: 'b'} - which would give you "bar" and "baz".
Likewise, if you need to filter by types - even though it is an array - a similar approach would work: {types: "Mexican"}.
And so, you just need to construct that object - let's call it filterBy.
<input type="checkbox" ng-model="filterBy.types"
ng-true-value="'Mexican'"
ng-false-value="undefined"> Mexican
<div ng-repeat="r in restaurants | filter: filterBy>
{{r.name}}
</div>
Demo
I'm trying to filter within an ng-repeat like this:
<li ng-repeat="file in files | filter: { values.filetype: 'Form' }">
If I change values.filetype: 'Form' to, say, id: 1, the filter works correctly. So how do I get it to work with the first property?
Edit: the structure of the data is like this:
{
"id": "3",
"values":
"title: "sldkfjsd",
"filetype": "Form"
}
This is solved with the following syntax:
filter: { values: { filetype: 'Form'} }