Check if next item exists inside an ng-repeat item - javascript

I'm using ng-repeat with a limitTo filter and a button to raise the limit when clicked. Is there any way to check if the next item in the ng-repeat iteration exists/count how many more items there are so that i can hide the 'load more' button/show how many more items there are.
below is sort of an example of what I am trying to do:
<div ng-repeat="comment in collection.data | limitTo:commentLimit">
{{comment.text}}
<div ng-show="filteredItems[$index + 1]" ng-click="increaseLimit()">load more (3 more replies)</div>
</div>

You can do something similar to this codepen:
http://codepen.io/anon/pen/waxOZL
<div ng-repeat="comment in collection.data | limitTo:commentLimit">
{{comment.text}}
</div>
<div ng-show="collection.data.length > commentLimit" ng-click="increaseLimit()">load more (3 more replies)</div>
Also, you should put the load more link outside the ng-repeat to show it only once.

Ideally, I think what you want to do is set an increment value in your scope, and add a new function called nextIncrementAmount which will help you display the number of new replies the button will add when clicked.
$scope.commentLimit = 3;
$scope.incrementStep = 3;
//use this function to increase the filter limit
$scope.increaseLimit = function() {
var newLimit = $scope.commentLimit + $scope.incrementStep;
$scope.commentLimit = (newLimit < $scope.collection.data.length) ? newLimit : $scope.collection.data.length;
}
//use this function to show the number of replies the increment button will increment by.
$scope.nextIncrementAmount = function() {
var newLimit = $scope.commentLimit + $scope.incrementStep;
return (newLimit < $scope.collection.data.length) ? $scope.incrementStep : $scope.collection.data.length - $scope.commentLimit;
}
Then in your view you'll want to do something like this:
<div ng-repeat="comment in collection.data | limitTo:commentLimit">
{{comment.text}}
</div>
<div ng-if="collection.data.length != commentLimit"
ng-click="increaseLimit()">
load more (<ng-pluralize count="nextIncrementAmount()"
when="{
'1': '{} more reply',
'other': '{} more replies',
}"> </ng-pluralize>)
</div>

Related

How to filter through a table using ng-repeat checkboxes with Angularjs

Once upon a time this was working but somehow it's broken. I want to be able to produce checkboxes using ng-repeat to get as many checkboxes as required based on stored data and use these to filter through a table produced.
Additionally I don't want identical values for the checkboxes to be repeated.
I have made a plnkr with the code.
<div class="row">
<label data-ng-repeat="x in projects">
<input
type="checkbox"
data-ng-true-value="{{x.b}}"
data-ng-false-value=''
ng-model="quer[queryBy]" />
{{x.b}}
</label>
</div>
http://plnkr.co/edit/RBjSNweUskAtLUH3Ss6r?p=preview
So in summary.
Checkboxes to filter Ref.
Checkboxes to be unique.
Checkboxes to be made based off ng-repeat using Ref.
Okay, here's how to do it.
First, let's add a couple of lines of CSS in your to make sure all the checkboxes are visible:
<style>
.row { margin-left: 0px }
input[type=checkbox] { margin-left: 30px; }
</style>
Next, add the following lines to your controller:
app.filter('unique', function() {
return function (arr, field) {
var o = {}, i, l = arr.length, r = [];
for(i=0; i<l;i+=1) {
o[arr[i][field]] = arr[i];
}
for(i in o) {
r.push(o[i]);
}
return r;
};
})
app.controller("maincontroller",function($scope){
$scope.query = {};
$scope.quer = {};
$scope.queryBy = '$';
$scope.isCollapsed = true;
$scope.selectedRefs = [];
$scope.myFilter = function (item) {
var idx = $scope.selectedRefs.indexOf(item.b);
return idx != -1;
};
$scope.toggleSelection = function toggleSelection(id) {
var idx = $scope.selectedRefs.indexOf(id);
if (idx > -1) {
$scope.selectedRefs.splice(idx, 1);
}
else {
$scope.selectedRefs.push(id);
}
};
Phew.
For some reason, your Plunkr's version of AngularJS didn't recognise the unique attribute, so I added one to your controller.
Finally, change your html to this:
<div class="row">
<label data-ng-repeat="x in projects | unique:'b' | orderBy:'b'" >
<input
id="x.b"
type="checkbox"
ng-click="toggleSelection(x.b)"
ng-init="selectedRefs.push(x.b)"
ng-checked="selectedRefs.indexOf(x.b) > -1" />
{{x.b}}
</label>
</div>
... and your ng-repeat to this...
<tr ng-click="isCollapsed = !isCollapsed" ng-repeat-start="x in projects | filter:myFilter | orderBy:orderProp">
If you're interested in knowing how this works, add these lines:
<div style="margin:10px 10px 30px 10px">
<pre>{{ selectedRefs }} </pre>
</div>
I love this trick: you can see the exact contents of our "selectedRefs" array, and see it change as we tick/untick our checkboxes. This really helps when developing/testing our bindings!
As you can see, these changes use the new unique function to get your list of distinct values from your project array, and when the page first loads, we push all of the values into our new "selectedRefs" array.
["123","321","456","654","789","987"]
Then, as you tick/untick the checkboxes, we add/remove that item from this list.
Finally, we use that filter in the ng-repeat.
ng-repeat-start="x in projects | filter:myFilter | orderBy:orderProp"
Job done !
Update
If you wanted to start off with all checkboxes unticked, then it's a simple change. Just remove this line...
ng-init="selectedRefs.push(x.b)"
..and change the myFilter function to show all items initially..
$scope.myFilter = function (item) {
if ($scope.selectedRefs.length == 0)
return true;
var idx = $scope.selectedRefs.indexOf(item.b);
return idx != -1;
};
And to add a "Clear all" button, simply add a button to your form which calls a function in your AngularJS controller like this..
$scope.clearAll = function () {
$scope.selectedRefs = [];
};
(I haven't tested these suggestions though.)
ng-false-value directive needs a value set. Try ng-false-value='false' or ng-false-value='null' (in fact you can skip this one entirely if it has to just be a falsy value and not something concrete, like a string or certain number).
As you've pointed out in the comments, after selecting and then clearing the checkboxes, all rows are filtered out. It happens because unchecking the checkbox will set its value to false, and this does not agree with your entities' values (as you probably know, just stating it for others).
Therefore you do need to set this value to empty string in the end. That'd be the way:
$scope.$watch('quer.$', function () {
if ($scope.quer.$ === false) {
$scope.quer.$ = '';
}
});

How to attach function to second element of ng-repeat

I just started learning angular
and I have a question related to ng-repeater
I have an ng-repeater like:
<div ng-if="!promo.promotion.useHTML"
class="{{promo.promotion.monetateId}}"
ng-repeat="promo in promotions track by promo.promotion.slotId">
<div ng-if="!promo.useHTML">
<img ng-src="{{promo.promotion.imageURL}}"
ng-click="promoOnClick(promo.promotion.promotionURL)"/>
</div>
I want to have a different ng-click function on second element of repeater.
How would I get this?
You can try using $index variable which contains the repeater array offset index. You can use it to build conditional statements in your repeater.
<div ng-if="!promo.promotion.useHTML" class="{{promo.promotion.monetateId}}" ng-repeat="promo in promotions track by promo.promotion.slotId">
<div ng-if="!promo.useHTML && $index !== 2">
<img ng-src="{{promo.promotion.imageURL}}" ng-click="promoOnClick(promo.promotion.promotionURL)"/>
</div>
<div ng-if="!promo.useHTML && $index == 2">
<img ng-src="{{promo.promotion.imageURL}}" ng-click="promoOnClickAnotherFunction(promo.promotion.promotionURL)"/>
</div>
</div>
Or as suggested by comment below
<div ng-if="!promo.promotion.useHTML" class="{{promo.promotion.monetateId}}" ng-repeat="promo in promotions track by promo.promotion.slotId">
<div ng-if="!promo.useHTML>
<img ng-src="{{promo.promotion.imageURL}}" ng-click="($index==1) ? function1() : function2()"/>
</div>
</div>
or as a third option, you can pass the index into the callback function as a second parameter and move your logic into your controller.
and in your callback, check the index and ... based on the index call your
function1, or function 2. Its a good idea to move logic away from your templates/views.
even better option would be creating/setting your promote() function function in your controller. E.g when you load your promotions array/objects, loop over them and set their promote function based on ... whatever your requirements are.
var i;
var yourPromoteFunctionForSecondElement = function( promo_object ) {
/*do your promo specific stuff here*/
}
for (i = 0; i < promotions.length; i++) {
var promotion = promotions[i];
if ( i == 1 ) {promotion.promote = yourPromoteFunctionForSecondElement(promotion);}
else if () {promotion.promote = someOtherPromoteFunction(promotion);}
else {/*etc*/}
}

Filter variable not updating in controller angularjs

Hi Im attempting to build functionality around the length of a filter in angularjs, and although its working as it should in the view, in the controller the variable seems to stay outdated...
When I click on the div below it filters a list and calls the filterby function. The output of the length of the newly filtered list updates in the view correctly. However in the function itself I have a log set and it is still showing the old length when I click on the div.
<div ng-repeat="filter in filters" ng-click="filterby(filter.filter_type)">{{filter.filter_type}}</div>
<ul>
<li ng-repeat="event in filtered = (events | filter:query) | orderBy:'-event_date' ">
<span >{{event.event_date}},{{event.event_name}}, {{event.event_venue}}, {{event.event_description}} </span>
</li>
</ul>
<br />Length of filtered items {{filtered.length}}
And my view....
$scope.filterby = function(filterby) {
if (filterby == 'ALL') {
$scope.query = '';
}
else {
$scope.query = filterby;
}
console.log($scope.filtered.length);
};
My filter data:
$scope.filters = [
{'filter_type' : 'ALL'},
{'filter_type' : 'Macnass'}
];
EDIT: Ok its not that it nots working at all, its just showing the previous value, as if its one click behind all the time, so its something to do with the fact that the variable in the view is updated after the list is made. but Im not sure how to go about insuring the variable in the controller is the latest value.
Plunker: http://plnkr.co/edit/u7KpqYx8gDwaaXEvGeMn?p=preview
check out the plunker
added below
$scope.filtered = $filter('filter')($scope.events, $scope.query)
in $scope.filterby function

Using angular to print out all the ids in an array one at a time along with a next button

I'm using Angular to repeat all these ids in an array but limit it to showing one at time like this:
<div ng-repeat="id in ids | limitTo:1">
{{array.id}}
</div>
I then want to have a div that when clicked will show the next id in the array, so basically increases the $index by one. Maybe something like...
<div ng-repeat="id in ids | limitTo:1">
{{array.id}}<br />
<div ng-click="$index + 1"></div>
</div>
The code above doesn't work so I can only surmise that I am going about this the wrong way. What's the right way to do this in Angular?
If you only want to show a single element at a time, there's no need to use an ng-repeat. You can just do something like this in your controller:
$scope.index = 0;
$scope.arr = ['your', 'array'];
$scope.increment = function() {
$scope.index = ($scope.index + 1) % $scope.arr.length;
};
And then in your view:
<div>
{{arr[$index].id}}<br />
<div ng-click="increment()"></div>
</div>
Well I think we cannot do that by increment $index as limitTo 1 says index is always zero
<button ng-click="onClick()">click here</button>
and onClick
$scope.onClick = function(){
//$index + 1
$scope.ids.shift();
}
Here is the plunker
http://plnkr.co/edit/A1VrbUoIPLhuA78CF4DM?p=preview
Demo FIDDLE
You only need to use ng-click and ng-init if you want to go through your ID array one by one:
In your view:
<div ng-controller="MyCtrl">
<button ng-click="index = index + 1" ng-init="index=0">
Next ID
</button>
ID: {{ids[index]}}
</div>
In your script file:
var myApp = angular.module('myApp',[]);
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
function MyCtrl($scope) {
$scope.ids = [11, 21, 31, 41, 51]; //test array
}
Edit: you should also either disable the button when index >= arrayLength or reset the value of index to 0.

jQuery find and replace second one

I was wondering how I would go about finding and replacing some text in a div, but i want to find and replace the second occurrence of that text. For example:"You just added a item, please remove this item" so I would like to find the second "item" and replace it with whatever text I choose.
JS:
var compareCount = $('.compareWidget').find('.compareItem').length;
if (compareCount >= 2) {
$('.message').find('.count').text(compareCount);
$('message').html().replace('item', 'items');
}
$('.message').slideDown("Fast");
setTimeout(function () {
$('.message').slideUp("Fast");
}, 5000);
HTML:
<div id="alertMessage">
<div class="message">
<span>You just added a item to compare, you currently have <span class="count">1</span> item to compare</span>
</div>
</div>
"you currently have 1 item to compare"
You want to turn item to items?
You can do it with regular expressions, or you can wrap it into an element and grab that.
<span class="count">1</span> <span class="type">item</span> to compare</span>
and
$('.message').find('.type').text("items");
Using regular expressions you can
function replaceMatch(originalString, searchFor , replaceWith, matchNumber)
{
var match = 0;
return originalString.replace(searchFor, function(found){
match++;
return (match===matchNumber)?replaceWith:found;
},'g');
}
and call it like
var msg = $('.message');
msg.html( replaceMatch( msg.html(), 'item', 'items', 2) );
demo http://jsfiddle.net/gaby/crhvA/

Categories

Resources