Add an extra Capital letter element only at the start of each new letter in ng-repeat - angularjs

I have an array sorted like so:
[aa,ab,ba,bb]
I want to render it like this:
A
aa
ab
B
ba
bb
how can I modify this forech to do this?
<div ng-repeat="item in array" >
{{item}} <br>
</div>

You can do it like this :
$scope.capitalize = function(array){
//group all elements by first letter using lodash
var items = _.groupBy(array,function(element){return element.charAt(0)});
//flatten object arrays to one array
return _.flatten(items,function(elements,letter){return [letter.toUpperCase(),elements] });
}
and on html you have
<div ng-repeat="item in capitalize(array)">
{{item}} <br/>
</div>
Working fiddle :
http://jsfiddle.net/qmw0qp6p/4/
I added also #sameer resolution, but it is not what you want.

I think you don't want to print the words and their first letters like you did in the question, but more like this:
A
- aa
- ab
B
- ba
- bb
To do so, I would aggregate the strings by their first letter using a custom groupBy filter (reusable), and then simply loop on the obtained object.
See this JSFiddle.
The cache system I implemented allows fast access to already computed results and avoids infinite digest loop (occurring because a new object is each time returned by Array.prototype.reduce).

Please try the below code
angular.module('module', []).
filter('capitalize', function() {
return function(input, all) {
return (!!input) ? input.replace(/([^\W_]+[^\s-]*) */g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();}) : '';
}
});
and In HTML
<div ng-repeat="item in array" >
{{item | capitalize}} <br>
</div>

Related

Infinite-scroll and limitTo doesn't display elements in ng-repeat

The elements in the ng-repeat is filtered by toggling bools on the individual elements.
<div class="message-list" infinite-scroll="loadMore()" infinite-scroll-distance="1" infinite-scroll-parent="true">
<div ng-repeat="powerplant in powerPlantFilter = (selectablePowerPlants | filter:searchString | limitTo: numberToDisplay) track by powerplant.ID">
<div class="message" ng-show="powerplant.IsSelected === false && powerplant.IsInSegment === false">
...
</div>
</div>
</div>
My problem is that, if I apply a certain filter, the first element that should be shown, is number 659 in the list.
If I haven't scrolled down so the numberToDisplay is higher than 659, no elements is shown in the list.
The numberToDisplay has a initial value of 35 and is incremented like this.
$scope.loadMore = function () {
if ($scope.numberToDisplay + 20 < $scope.selectablePowerPlants.length) {
$scope.numberToDisplay += 20;
} else {
$scope.numberToDisplay = $scope.selectablePowerPlants.length;
}
};
How do I work around this problem?
JsFiddle demonstrates the problem
I found your problem.
Here is a working jsfiddle : https://jsfiddle.net/3Lsu2ojz/
Your problem what that you were using ng-show instead of a filter..
ng-show can be understood as 'put display: none !important; on this element if condition'
Consequently, it will still be taken in account in the infinite-scroll directive because elements are really here and limitTo actually does its job.
You can use a custom filter, in your case :
$scope.searchString = {'ShowMe': true }
Does the trick.
Also consider using this syntax instead of yours :
powerplant in powerPlantsFilter = ( selectablePowerPlants |
filter:searchString |
limitTo: numberToDisplay) track by powerplant.ID"
Where powerPlantsFilter is here not a collection from the scope but a collection dynamically created by the spec of limitTo and filter.

Adding filter to ng-repeat

I'm currently making a front-end with Angular.
I have a JSON file like following:
{
"groups": [
group1: {
"part":1
},
group2: {
"part":2
}
]
}
And I have lists like following:
<li ng-class="{active: section >= {{group.number}}}" ng-bind="group.title" ng-repeat="group in groups" ></li>
Let's say there are 100 groups in my JSON file. If I want to only show groups with "part":1, how do I add this filter in ng-repeat?
You can pass an object to filter with the key/value you want to filter on:
ng-repeat="group in groups | filter:{part:1}"
try this
ng-repeat="group in groups | filter:{'part': 1}:true"
from official documentation
In HTML Template Binding
{{ filter_expression | filter : expression :
comparator}}
for comparator value if its true
true: A shorthand for function(actual, expected) { return
angular.equals(actual, expected)}. This is essentially strict
comparison of expected and actual.
this gives you the exact match
Consider also passing a function rather than Object into filter (which may work this time, but not all things are easily expressible in a readable fashion directly in the view):
ng-repeat="group in groups | filter:functionOnScope"
The | pipe operates on the thing to the left groups, so filter is a function whose first argument receives groups and whose subsequent arguments appear after the :. You could visualize a | b:c:d | e as e(b(a,c,d)) - once I realized that I used filters more for simple things.
So the second argument filter receives is a predicate (function that takes in something and returns true or false to operate on each element - like a SQL WHERE clause) inside groups. Filters are super useful - if you have quick logic or transformations you want to do in the view (and you don't need to test it) then they can make your controllers and directives more succinct. (So instead of ng-if="collection[collection.length - 1].length > 0" you could write ng-if="collection | last | some", which is much more readable.)
If you have complicated logic, it may be better to put in a controller or directive instead of the view (this is also easier to unit test that way if you care about it) - if it's in the view you need something like PhantomJS at a minimum to emulate the DOM. Assuming you bound some dynamicallySelectedPart on the $scope to 1, 2, etc. maybe as an ng-model on a <select /> so the user can select it, then you can just write this to keep it dynamically up-to-date.
$scope.functionOnScope = function (elementInGroups) {
// Maybe do a check like:
// if ($scope.dynamicallySelectedPart === elementInGroups.part) {
return true;
// }
// Some other logic...
return false;
};
Your JSON looks malformed in that you have an array with key-value pairs.
Below is some code that should work. I am using the Controller ViewAs syntax.
HTML
<div ng-app="MyApp">
<div ng-controller="MyController as me">
{{me.greeting}}
<ul>
<li ng-repeat="group in me.groups | filter:{'part': 1}:true">
{{group}}
</li>
</ul>
</div>
JS
var myApp = angular.module('MyApp',[]);
myApp.controller('MyController', function() {
this.greeting = 'Hola!';
this.groups = [ {id: 'group1', "part":1 }, {id: 'group2', "part":2 } ];
});
Code Pen Here

AngularJs FilterBy property a in array A, where a exists in array B

I am using angular-filter and I want to loop the collection A and only display items where A.a exists in array B.
A = [{a:'mouse', c:'Tom'}, {a:'cat', c:'Jerry'}];
B = ['cat', 'dog'];
Then, I want something like:
<div ng-repeat="item in A | filterBy: ['item.a'] : B">
{{item.c}}
</div>
Would return: <div>Jerry</div> because cat is in B. I imagine that I can achieve this with pick, but was wondering if I can do this with filterBy?
if using lodash will do for you and you are not married to the filter idea. here is a quick solution.
define on the scope a function that gets the selected ones and bind that to the ng-repeat:
$scope.commonItems = function(){
return _.filter(A, function(itemA){ return _.includes(B, itemA.a) })
}
and then:
<div ng-repeat="item in commonItems()">
{{item.c}}
</div>

calling a function from ng-repeat with the object from the current scope

I'm trying to call a function (from a non event element) from a ng-repeat to feed an array of data to an autocomplete element (using https://github.com/JustGoscha/allmighty-autocomplete).
It's to generate a kind of logic system :
type(listbox) | comparator (eg:>=) (listbox) | value(autocomplete)
And several of those object can be listed on a webpage to get some complex logic
type=value && type2>value3 || ...
Depending on type and comparator, values are different.
The code so far (simplified):
<div class="comparator" ng-repeat="comp in container.comparators">
<select ng-model="comp.type"><option ng-repeat="i in type_options" value="{{i.value}}" ng-selected="{{i.value==comp.type}}">{{i.label}}</option></select>
<select ng-model="comp.comparator"><option ng-repeat="i in comp_options|filter:typeMatch(comp)" value="{{i.value}}" ng-selected="{{i.value==comp.comparator}}">{{i.label}}</option></select>
<autocomplete class="autocomplete" data="" attr-placeholder="Entrez votre valeur" click-activation="true" on-type="**updateValue**" ng-model="comp.value"></autocomplete>
</div>
updateValue is the function to call, but i need to know the current object (comp from the ng-repeat) on which i am to send the right array of value.
I tryed to send an existing array to avoid "digest loop"
$scope.updateValue = function(crit){
for(var i=0;i
I also tryed to do a function that return a function that return the array :DDDDD :
$scope.updateValue = function(crit){
return function(value/*not used*/){
for(var i=0;i<$scope.comp_options.length;i++) {
if($scope.comp_options[i].value===crit.comparator){
$scope.value_elements=$scope.comp_options[i].info;
break;
}
}
return $scope.value_elements;
};
};
Replacing the autocomplete object with :
if I console.log(comp), I see that I can get my object, but I get a digest loop ...
Is there a way to know the object of the "line" I was called from ?
Thx (i'm a total newbie in angular, but so far, i've been unable to find how to retrieve that information ... is that even possible :) ?).
Access it using $index ? Example below. You can then use the index to access it
<tr ng-repeat="user in uc.users track by $index">
<td>{{user.id}}</td>
<td>{{user.first_name}}</td>
<td>{{user.last_name}}</td>
<td>{{user.email}}</td>
<td>{{user.department}}</td>
<button ng-click="uc.open(user.id, $index);">Open</button>
</tr>

How to apply animation conditionally?

In angularjs, inside a directive:
I have this array of animate.css animations:
['fadeIn','BounceInLeft'...]
And i have the following html:
<div ng-repeat="opt in quest.opts" ng-show="showBtns" class="animated" ng-class='getRandomClass()'>
1) How can i do something like this, so in every ng-repeat, a new animation from the list will be applied to that div?
2)Can i make them 1 after another when they animate?
Use $index to fetch the actual animation strings:
var animateArray = ['fadeIn', 'BounceInLeft', ... ]
<div ng-repeat="opt in quest.opts" ... class="animateArray[$index]" ...
This will apply each animation in order. If the array is say length 7 you can use a modulo to make it go back to the start:
var animateArray = ['fadeIn', 'BounceInLeft', ... ]
<div ng-repeat="opt in quest.opts" ... class="animateArray[$index % 7]" ... // repeats after 7th element
If you want to make it random then generate a random number up to the length of the array on every loop run:
var randomInt(max) {
return Math.floor(Math.random() * max);
}
var animateArray = ['fadeIn', 'BounceInLeft', ... ]
<div ng-repeat="opt in quest.opts" ... class="animateArray[randomInt(7)]" ... // repeats after 7th element

Resources