Filtering in angular - angularjs

Can someone help on how to re-write the below code in Angular. I am having problem in handling filters
ng-repeat="data in myController.data | filter:{filterFlag:'true'}"

AngularJS
Lets say you have an array of objects (in your case named data) in your myController i.e.
this.data = [
{id: 1, name: 'Oscar', age: 36},
{id: 2, name: 'Nina', age: 36},
{id: 3, name: 'Alex', age: 39},
]
And you want to filter out people with the age 36, you could iterate over it in the template like this:
<div ng-repeat="data in myController.data | filter:{age:36}">
{{data}}
</div>
Angular
In any case, filters are expensive. Thats why they are considered bad practice, thats why you are not recommended to use it in Angular. The style guide says, you ought to filter out the objects in the controller, rather than in the template. You might want to consider doing the same in AngularJS. You could write a method which does the job.
For more go to ... ng-repeat :filter by single field

Related

How to change the content of the same HTML element at every item in an ngFor loop (with delay)?

I'm developing an Angular 6 app (with Bootstrap) and I have created the following template:
<div class="news-container">
<div class="new" *ngFor="let n of news">
<div class="date">{{n.date}}</div>
<div class="text">{{n.text}}</div>
</div>
</div>
I would like to show only one news per time, so every item of the array in the *ngFor loop should replace the previous one, and if the loop is at the last item it should restarts from the first item again.
In addition, it would be nice to add a delay between an item and the next one.
Here is how the array looks like:
news: [
{id: 1, date: '01-01-2018', text: 'this is a news'},
{id: 2, date: '01-01-2018', text: 'this is another news'},
{id: 3, date: '01-01-2018', text: 'breaking news'},
{id: 4, date: '01-01-2018', text: 'foo bar'},
]
Do you know any solution to reach that?
You can use a setTimeout() to delay the news items that are displayed and then with a recursive function loop through all the news and start over again. Here is a stackblitz I created with the answer: https://stackblitz.com/edit/angular-bdpkbw
Sorry for answer, can't add comment
Why not use $interval to do that? At each interval show an element of the array.

Can you explain how the angular filter process works with this code?

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.

Filter collection by child

I have the following fictional object which I'm trying to filter:
{
"0":{
"boy":{
"age":"32",
"name":"Daniel Grey"
}
},
"1":{
"boy":{
"age":"23",
"name":"John Doe"
}
}
}
And then, the ng-repeat directive looks like this:
<ul>
<li ng-repeat="person in people">{{person.boy.name}}<li>
</ul>
My question is, how do I filter people by "name"? I've tried:
<input type="text" ng-model="name">
<ul>
<li ng-repeat="person in people | filter:name">{{person.boy.name}}<li>
</ul>
... but nothing happens [ ng-model seems disconnected from the view! ].
Any response is much appreciated!
Thank you!
Updated answer as per OP's updates
Looking at your fiddle, your $scope.people is essentially an array with one big JSON object, with multiple nested boy objects. This is hard to work with. If you have control over the construction of the JSON object, I will suggest converting into an array of multiple JSON objects, which may look something like:
$scope.people = [
{
"name":"Daniel Grey",
"age":"32",
"gender": "male"
},
{
"name":"John Doe",
"age":"23",
"gender": "male"
}
];
Notice how I converted the boy key into the gender attribute.
If you really have absolutely no control over the data structure, you may have to come up with a custom filter to parse through the nested structure.
Take a look at this fiddle. A few things to pay attention to:
I have to specify people[0] in ng-repeat to retrieve the one big JSON object in your array.
The custom nameFilter searches the .boy.name attribute only.
Original Answer
If you want your filter by just name, you will have to specify the specific attributes in your ng-model directive. So in your case, it will be
<input type="text" ng-model="search.boy.name">
<ul>
<li ng-repeat="person in people | filter:search">{{person.boy.name}}<li>
</ul>
But first you will need to fix your JSON object.
UPDATE:
Live demo on fiddle. I did notice that the search-by-name-only filter doesn't work with angularjs 1.2.1, but works with angularjs 1.2.2.

Binding ng-repeat and ng-model in controller

This is my first post on here so bear with me, I'm fairly new to AngularJS as well. I'm trying to build a form with ng-repeat and having trouble wrapping my head around the angular stuff.
JS in controller:
$scope.myCurrentAssets = {
cash_equiv: {name: 'Cash & Equivalents', value: 0, tbi: 41},
invest: {name: 'Short Term Investments', value: 0, tbi: 42},
notes_rec: {name: 'Notes Receivable', value: 0, tbi: 43},
account_rec: {name: 'Accounts Receivable', value: 0, tbi: 44},
inventory: {name: 'Inventory', value: 0, tbi: 45},
prepaid: {name: 'Prepaid Expenses', value: 0, tbi: 46},
other: {name: 'Other Current Assets', value: 0, tbi: 47}
};
HTML:
<div class="row" ng-repeat="(keyAssets, valueAssets) in myCurrentAssets">
<span>{{valueAssets.name}}</span>
<input data-name="myCurrentAssets.{{keyAssets}}"
data-ng-model=""
data-placeholder="{{valueAssets.value}}"
data-ng-change="compute()"
/>
</div>
The problems I'm having are:
trying to get the 'data-ng-model' set to something unique in each instance of the ng-repeat
how do I access the value of the input field from the compute() function?
trying to get the 'data-ng-model' set to something unique in each instance of the ng-repeat
You can use list[key][value] that will be different per item in ng-repeat
how do I access the value of the input field from the compute() function?
Generally you can use ng-model that automatically fetches input data.
<div class="row" ng-repeat="(keyAssets, valueAssets) in myCurrentAssets">
<span>{{valueAssets.name}}</span>
<input data-name="myCurrentAssets[keyAssets]['name']"
data-ng-model="myCurrentAssets[keyAssets]['value']"
data-placeholder="myCurrentAssets[keyAssets]['value']"
data-ng-change="compute(myCurrentAssets[keyAssets]['value'])"
/>
</div>
Demo Fiddle

Efficiently dealing with multiple HTML elements with AngularJS

Let's say I have a 4 div tags in my view:
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
And let's say that when the user selects clicks on one of them I want the rest to, say, turn red. Normally in a dirty jQuery style I'd use something like:
var tiles = $('.tile');
tiles.click(function()
{
tiles.css('background', 'red');
});
However, how would I do this in the world of AngularJS? Would I stick this code in the controller and have it relative to the $scope? Or would I create a directive and bind that to each tile element?
Assuming that you wouldn't just have 4 random tiles in your interface not bound to some kind of model, you could do something like this:
http://jsfiddle.net/V4YC9/1/
HTML
<div ng-app ng-controller="x">
<div ng-repeat="tile in tiles" ng-click="selectTile(tile)" ng-class="tile.class">{{tile.name}}</div>
</div>
JavaScript
function x($scope) {
$scope.selectedTileIndex = null;
$scope.tiles = [
{id: 1, name: 'tile 1'},
{id: 2, name: 'tile 2'},
{id: 3, name: 'tile 3'},
{id: 4, name: 'tile 4'}
];
// provide default class to all tiles
angular.forEach($scope.tiles, function (tile) {
tile.class = 'tile';
});
$scope.selectTile = function (clickedTile) {
angular.forEach($scope.tiles, function (tile) {
tile.class = 'tileNotSelected';
});
clickedTile.class = 'tileSelected';
}
}
Edit: There are probably 10 different ways to do it. If you don't want to muddy up your model, you could store a separate array in $scope and calculate the class real time by saying ng-class="calculateTileClass(tile)", similar to what I did in my initial response: http://jsfiddle.net/V4YC9/1/

Resources