how to show the currently shown entries range in angular - angularjs

This is what I have used to achieve pagination:
<pagination total-items="reportCount" items-per-page="itemsPerPage" page="currentPage" ng-change="pageChanged()" ng-model="currentPage"></pagination>
How do I get it show the range of entries currently shown.. like.. 1-10 of 46 entries. 11-20 of 46 and so on..
I am able to get it using the value of currentPage and itemsPerPage by doing as follows:
<span id="page_info">Showing {{(currentPage-1) * itemsPerPage + 1}} - {{currentPage * itemsPerPage}} of {{reportCount}} entries</span>
But the issue is in the last page, where the last record is not just currentPage * itemsPerPage, like.. it shows 41-50 of 46 entries.
It should work with {{Math.min((currentPage * itemsPerPage), reportCount)}} but for some reason it isn't evaluating it here.
Any ideas how to get this fixed? or any other way?

Browser Object Model(BOM) will not be directly available when angular bindings are evaluated like Math, console, location, window, etc. You can call them inside a function but not directly on inside binding (Thought there are ways to do that by keep that BOM property on $scope, I'd not recommend to do that). To make it working create a javascript function for inside a $scope and call it on binding level.
<span id="page_info">
Showing {{(currentPage-1) * itemsPerPage + 1}} - {{endCount(currentPage,itemsPerPage, reportCount)}} of {{reportCount}} entries
</span>
Controller
$scope.endCount = function (currentPage, itemsPerPage, reportCount) {
return Math.min((currentPage * itemsPerPage), reportCount);
}

Related

dir-pagination-controls only showing first 10 items. Angularjs

<tr dir-paginate="plan in access |itemsPerPage: 10" total-items="planCount" current-page="current">
<td>{{plan._id}}</td>
<td>{{plan.name}}</td>
<td>{{plan.email}}</td>
<td>{{plan.contactNumber}}</td>
<td>{{plan.accessToken}}</td>
<td>{{plan.downloadSpeed | toMBPS}}</td>
<td>{{plan.uploadSpeed | toMBPS}}</td>
<td>{{plan.issueTime}}</td>
and this is the directive
<div class="text-center">
<dir-pagination-controls auto-hide="false" on-page-change="pageChanged(newPageNumber)"></dir-pagination-controls>
</div>
and this is the angular code
$scope.planCount = 0;
$scope.current = 1;
$scope.pageChanged = function(value) {
console.log("Going to page" + value);
}
The data is coming from the server, but that is working fine. I have logged the data, and I am receiving the complete data. Also, it is the registering the changed page number correctly.
Still, it only shows the first ten items, doesn't matter on what page number I am.
Note: Don't mind the incomplete html. That is the only relevant part to my situation. I can't post the whole code.
Also, I am using this in a different page, but it's working fine in it.
<tr dir-paginate="plan in access |itemsPerPage: 10" total-items="planCount" current-page="current">
From above line remove total-items="planCount". It'll work here too.

Strange bug with ng-repeat and filter

I'm using NodeJS, ANgularJS, and MongoDB with mongoose
Here is my model :
var PostSchema = new mongoose.Schema({
nomReseau : String,
corps : String,
etat : String,
section : String
});
I got a function that change the attribute etat:
$scope.passer = function(index){
var post = $scope.posts[index];
post.etat = "enCours";
Posts.update({id: post._id}, post);
$scope.editing[index] = false;
}
I'm using a ng-repeat for show object in my database :
<ul>
<li ng-repeat="post in posts ">
<p>
<a ng-show="!editing[$index]" href="#/{{post._id}}">{{post.corps}}</a>
</p>
<button ng-show="!editing[$index]" ng-click="passer($index)">Passer</button>
</li>
</ul>
I can see all post in my database and when I click on the button this works perfectly the attribute etat change and all is fine.
But when I add a filter in the ng-repeat like this :
<li ng-repeat="post in posts | filter:{ etat:'aTraiter'} ">
The filter works great I have all post with the attribute etat:'aTraiter'
But if I click on my previous button and change the attribute etat nothing change and I try with other functions they all work wihout the filter but when I put it nothing work.
The problem is that $index will change if less data is shown (because you're filtering). you could use directly post variable
ng-click="passer(post)"
and your function should be something like
$scope.passer = function(post){
post.etat = "enCours";
Posts.update({id: post._id}, post);
var index = $scope.posts.findIndex(function(p) { /* comparison to get original index */ }); /* keep in mind findIndex is not supported on IE, you might want to use filter or for loop instead) */
$scope.editing[index] = false;
}
you could handle editing in the post variable directly. So in your passer function you can do this
post.editing = false;
and in your view
ng-show="!post.editing"
this way you won't use $index and you will prevent all issues with being updated by filters
There are bugs in AngularJS v1.4 where in certain situations the ng-repeat breaks. I upgraded to v1.6 and it went away.
Do you have any controllers/services that access $scope.editing? If so, you might be setting the $scope.editing[$index] equal a previous state where it wasn't equal to false. You may also want to consider that you are assuming $scope.editing[$index] is going to be a boolean. if it has any other type such as string or number then it will evaluate to true.
Otherwise none of your results have the attribute etat equal to 'aTraiter' so they aren't showing. Have you verified that any of them actually do have etat equal to 'aTraiter'. You might be changing that value somewhere else. Possibly from the Passer function

Filter ng-repeat more times

I'm creating an application to manage restaurant orders.
I create the menu from $http so I've this list:
<div class="row vertical" style="background-image: url(/gest/images/etichette/ANTIPASTI.png);border-color: #0CF">
<div class="card piatti col s2" ng-repeat="anti in antis | filter:{tipo:'ANTIPASTI'}">
<div class="card-content"> <span class="card-title truncate red darken-3">{{anti.piatto}}</span> </div>
<div class="card-action"> {{n}}</div>
</div>
</div>
The div with class "row vertical" contain one time starters, then pasta, then beef ecc.
So I use ng-repeat each time, and filter by tipo.
My question is: is there any way to make ng-repeat only one time to show all menu (orderer before by starters, then pasta, beef ecc)?
I have this data (is a restaurant menu):
piatto: name of the the dish
tipo: category of the dish (like pasta, beef, fish, starters ecc)
I would show with only one repeat all the dishes ordered so:
starters, pasta, beef, fish, dessert etc.
And I would create each time a new row
From what I understand you already have all your date on the antis and you just want to filter it by type or do you want to OrderIt by a certain type?
This fiddle for example would order by name, but you can also provide an array with functions to retrieve each type in the way that you like, you can read about it here.
But basically you'd do
anti in antis | orderBy:'+tipo'
or
anti in antis | orderBy: [ function(){}, function(){} ]
EDIT:
As #yarons mentioned you can also chain strings to filter even further. I've updated the Fiddle so now the filter would be anti in antis | orderBy:['+tipo', '+piato']" which indicates that first the tipo would be alphabetically ordered ascending (+ indication) and after that the piato would also be alphabetically ascending.
If you'd want to define a different order than the alphabetical one I think you can use a sort of ENUM for the tipo as in:
var tipoENUM = {};
tipoENUM['ANIPASTI'] = 0;
tipoENUM['PASTA'] = 1;
tipoENUM['PIZZA'] = 2;
tipoENUM['BEEF'] = 3;
tipoENUM['DESERT'] = 4;
So that way you'd avoid using the string for the order, see following fiddle for the example.
EDIT 2:
Ok, so if you receive the data via the HTTP request it's better if you create a order function to help you, check this updated fiddle, like so:
// The enum would be defined as before but:
$scope.orderTipo = function (dish) {
return tipoENUM[dish.tipo];
}
On the HTMl you'll do:
ng-repeat="anti in antis | orderBy:[orderTipo, '+piato']"
Ok your example is perfect but I would repeat each time the "tipo" and then the relative "piato" in a list....something like this:
ANTIPASTI
- bruschetta
- suppli
- fritto
PRIMI
- caqrbonara
- amatriciana
etc.
Is it possible?

AngularJS: Show if X > Y and add class

I am building my first app. It is an ordering system where a customer can add items to the cart. Everything is working well. However, my client would like a way to alert the customer if they try to add a quantity to the cart that is greater than the current stock.
My client doesn't want to show stock levels, unless the customer adds something greater than the stock available.
I have a table with stock items in each row. I'd like to do three things, if the stock level is greater that available stock, I'd like to change:
• Class on the table row
• Add class disabled to the submit
• Show a div that has the available stock in.
To make matters a little more interesting, customers have to order by packs and not individual items.
Basically, I am trying to get the following code to work:
This is the general markup:
<tr ng-repeat="series_detail in productDetail | filter:filter">
<td>{{series_detail.sku}}</td>
<td>{{series_detail.size}}</td>
<td>{{series_detail.price</td>
<td>{{series_detail.pack}}</td>
<td ng-model="totalitems" ng-init="0">{{qty * series_detail.pack | number}}</td>
<td><span class="itemtotal">{{series_detail.price * qty | number:2}}</span></td>
<td class="form-inline" style="text-align:right;">
<input type="submit" class="add_to_cart_submit btn btn-danger btn-small" value="Add">
</td>
</tr>
I want to then show this div
<div ng-show="'{{totalitems}}' > '{{series_detail.stock}}'">Yo, no stock dude</div>
I have tried adding a model, 'totalitems' to a row and then using ngShow to pop it up. However, it seems that 'totalitems' is evaluating to nothing. I've experimented with a few other options, but nothing has worked (ngIF etc.).
Regarding the changing of class, I am guessing, that once I get this sorted, I can transfer the expression to ngClass? I have played with this, and again, nothing has worked so far.
Provided this line goes inside the ng-repeat:
<div ng-show="qty * series_detail.pack > series_detail.stock">Yo, no stock dude</div>
For the class indication, lets say on tr, you could use the same expression as:
<tr ng-class="{outOfStock: (qty * series_detail.pack > series_detail.stock)}" ng-repeat="series_detail in productDetail | filter:filter">
outOfStock is class in your CSS.
BTW,
<td ng-model="totalitems" ng-init="0">{{qty * series_detail.pack | number}}</td>
does not set totalitems to whatever {{qty * series_detail.pack | number}} evaluates to.
If you really need totalItems in your model a possible option is to have a method on the series_detail instance
objRef.totalItems = function(qty) {
return qty * this.pack;
}
and use it as:
<div ng-show="series_detail.totalItems(qty) > series_detail.stock">Yo, no stock dude</div>
<td>{{series_detail.totalItems(qty) | number}}</td>
I am not to sure to understand everything but something like this should works ?
<div ng-show="isStockAddedGreaterThanAvailable()">{{series_detail.stock}} Yo, no stock dude </div>
And in your controller
$scope.isStockAddedGreaterThanAvailable = function(){
....
}

How to use ng-repeat for dictionaries in AngularJs?

I know that we can easily use ng-repeat for json objects or arrays like:
<div ng-repeat="user in users"></div>
but how can we use the ng-repeat for dictionaries, for example:
var users = null;
users["182982"] = "{...json-object...}";
users["198784"] = "{...json-object...}";
users["119827"] = "{...json-object...}";
I want to use that with users dictionary:
<div ng-repeat="user in users"></div>
Is it possible?. If yes, how can I do it in AngularJs?
Example for my question:
In C# we define dictionaries like:
Dictionary<key,value> dict = new Dictionary<key,value>();
//and then we can search for values, without knowing the keys
foreach(var val in dict.Values)
{
}
Is there a build-in function that returns the values from a dictionary like in c#?
You can use
<li ng-repeat="(name, age) in items">{{name}}: {{age}}</li>
See ngRepeat documentation. Example: http://jsfiddle.net/WRtqV/1/
I would also like to mention a new functionality of AngularJS ng-repeat, namely, special repeat start and end points. That functionality was added in order to repeat a series of HTML elements instead of just a single parent HTML element.
In order to use repeater start and end points you have to define them by using ng-repeat-start and ng-repeat-end directives respectively.
The ng-repeat-start directive works very similar to ng-repeat directive. The difference is that is will repeat all the HTML elements (including the tag it's defined on) up to the ending HTML tag where ng-repeat-end is placed (including the tag with ng-repeat-end).
Sample code (from a controller):
// ...
$scope.users = {};
$scope.users["182982"] = {name:"John", age: 30};
$scope.users["198784"] = {name:"Antonio", age: 32};
$scope.users["119827"] = {name:"Stephan", age: 18};
// ...
Sample HTML template:
<div ng-repeat-start="(id, user) in users">
==== User details ====
</div>
<div>
<span>{{$index+1}}. </span>
<strong>{{id}} </strong>
<span class="name">{{user.name}} </span>
<span class="age">({{user.age}})</span>
</div>
<div ng-if="!$first">
<img src="/some_image.jpg" alt="some img" title="some img" />
</div>
<div ng-repeat-end>
======================
</div>
Output would look similar to the following (depending on HTML styling):
==== User details ====
1. 119827 Stephan (18)
======================
==== User details ====
2. 182982 John (30)
[sample image goes here]
======================
==== User details ====
3. 198784 Antonio (32)
[sample image goes here]
======================
As you can see, ng-repeat-start repeats all HTML elements (including the element with ng-repeat-start). All ng-repeat special properties (in this case $first and $index) also work as expected.
JavaScript developers tend to refer to the above data-structure as either an object or hash instead of a Dictionary.
Your syntax above is wrong as you are initializing the users object as null. I presume this is a typo, as the code should read:
// Initialize users as a new hash.
var users = {};
users["182982"] = "...";
To retrieve all the values from a hash, you need to iterate over it using a for loop:
function getValues (hash) {
var values = [];
for (var key in hash) {
// Ensure that the `key` is actually a member of the hash and not
// a member of the `prototype`.
// see: http://javascript.crockford.com/code.html#for%20statement
if (hash.hasOwnProperty(key)) {
values.push(key);
}
}
return values;
};
If you plan on doing a lot of work with data-structures in JavaScript then the underscore.js library is definitely worth a look. Underscore comes with a values method which will perform the above task for you:
var values = _.values(users);
I don't use Angular myself, but I'm pretty sure there will be a convenience method build in for iterating over a hash's values (ah, there we go, Artem Andreev provides the answer above :))
In Angular 7, the following simple example would work (assuming dictionary is in a variable called d):
my.component.ts:
keys: string[] = []; // declaration of class member 'keys'
// component code ...
this.keys = Object.keys(d);
my.component.html: (will display list of key:value pairs)
<ul *ngFor="let key of keys">
{{key}}: {{d[key]}}
</ul>

Resources