Search in angularjs not working properly with angular bootstrap ui - angularjs

i am using angular-ui bootstrap for pagination of a table and i have separate search input tag, the search input only searches the first set data from the paginated list, it does not search the subsequent paginated pages of the table, how do i search from the input for all the data.
HTML
<div ng-controller="IndexCtrl" >
<input class="form-control formcustom" id="exampleInputEmail2" ng-model="custquery" placeholder="Search for Tripsheets" autofocus>
<table class="table table-striped table-bordered table-condensed table-hover">
<tr ng-repeat="customer in customers | orderBy:'id':true | filter: paginate | filter: custquery">
<td>{{customer.id}}</td>
<td>
<span>{{customer.name}}</span>
</td>
<td>
<span>{{customer.address}}</span>
</td>
<td>
<span>{{customer.phone1}}</span>
</td>
<td>
<span >{{customer.phone2}}</span>
</td>
<td>
<span >{{customer.phone3}}</span>
</td>
<td>
<span>{{customer.phone4}}</span>
</td>
<td>
<span >{{customer.email}}</span>
</td>
</tr>
</table>
<pagination total-items="totalItems" ng-model="currentPage"
max-size="5" boundary-links="true"
items-per-page="numPerPage" class="pagination-sm">
</pagination>
</div>
JS
app.controller('IndexCtrl', function ($scope, customerFactory, tripsheetFactory, driverFactory, notificationFactory) {
$scope.customers = [];
$scope.addMode = false;
customerFactory.getCustomers().then(function(data){
$scope.customers = data.data;
$scope.totalItems = $scope.customers.length;
$scope.currentPage = 1;
$scope.numPerPage = 20;
$scope.paginate = function(value)
{
var begin, end, index;
begin = ($scope.currentPage - 1) * $scope.numPerPage;
end = begin + $scope.numPerPage;
index = $scope.customers.indexOf(value);
return (begin <= index && index < end);
};
});
});
customerFactory is the factory i created to fetch json data

The position of the customer in $scope.customers doesn't change so the paginate function will always filter out all but the first page of the full customers array. What you need is an intermediate result (another array) that holds the customers that pass the $scope.custquery filter. The paginate function needs to operate on that second, filtered array.
I couldn't see a way to do that declaratively so I injected filterFilter into the controller and added a watch on $scope.custquery to execute it.
I put together a plunk that shows the result.

Related

AngularJS table stop sorting when in edit mode

I have AngularJS table with CRUD operations and sortable header. When I add the new row to table the lines are jumping and the table is getting sorted while in edit mode.
I want to stop sorting while in the edit mode and should sort only after saving the new row. I searched online for fixing this issue but nothing helped yet.
Here is the HTML file:
<thead>
<tr>
<td><input type="text" ng-model="main.search.Data1" id="myInput" placeholder="search for Data1..."/></td>
<td><input type="text" ng-model="main.search.Data2" id="myInput" placeholder="search for Data2..."/></td>
</tr>
<tr class="table_header" style="background-color: blue;">
<th><a href="#" ng-click="orderByField='data1'; reverseSort = !reverseSort"> Data1 <span ng-show ="!reverseSort">^</span><span ng-show="reverseSort">v</span></th>
<th><a href="#" ng-click="orderByField='data2'; reverseSort = !reverseSort"> Data2</th>
</tr>
</thead>
<tbody>
<tr ng-repeat=" code in main.Table | orderBy: Predicate | orderByField:reverseSort | filter:main.search"></tr>
<script type="text/ng-template" id="dispay">
<td>{{code.data1}}</td>
<td>{{code.data2}}</td>
</script>
<script type="text/ng-template" id="edit">
<td><input type="text" ng-model="code.data1" class"form-control input-sm"/></td>
<td><input type="text" ng-model="code.data2" class"form-control input-sm"/></td>
</script>
</tbody>
Here is the JS code:
//add new row
$scope.addNew = function(data) {
$scope.Table.unshift({
data1: "",
data2: ""
});
console.log($scope.table);
};
//Edit the row
$scope.edit = function(data){
$scope.selected = angular.copy(data);
$scope.backuplist = angular.copy($scope.table);
};
The behaviour is correct because on addNew you add 1 empty record in apply cycle which then will reorder again the list.
You have 2 ways to go :
1) When Adding new Item, create sperate object and upon submit add it in the list:
$scope.addNew = function(data) {
$scope.newItem ={
data1: "",
data2: ""
};
};
$scope.save = function() {
$scope.table.push($scope.newItem);
};
Like this there is speration of concerns and not to mingle the main list.
Or if you still want to add it in main list directly which i dont recommend you can implement your custom filter which keeps always the empty data at the top - In your predicate Method.
<tr class="table_header" style="background-color: blue;">
<th><a href="#" ng-click="orderByField='data1'; reverseSort = !reverseSort" ng-disabled="setTrueFalse"> Data1 <span ng-show ="!reverseSort">^</span><span ng-show="reverseSort">v</span></th>
<th><a href="#" ng-click="orderByField='data2'; reverseSort = !reverseSort" ng-disabled="setTrueFalse"> Data2</th>
</tr>
$scope.setTrueFalse = true/false
MAke use of ng-disabled.. Set it to true when you do not want to sort the values and vice versa

Count clicks and add to input

First of all I am very new in Angular JS.
I have a list of items and by clicking on each one, it should be added to the table. The items are stored in a json file.
If the click event repeated several times the counter input which is located on the table must increases.
<ul class="list-inline" >
<li ng-repeat="food in foods" class="food_list">
<img class="img-box" src="images/{{ food.food_photo }}" ng-click = 'addRow(food)'><br/><span>{{food.food_name}}</span>
</li>
</ul>
<table class="table" id="table-right">
<tr>
<th>Item Name</th>
<th>Quantity</th>
<th>Price</th>
<th class="hidden-print">Delete</th>
</tr>
<tr ng-repeat="row in rows">
<td>{{row.food_name}}</td>
<td><input type="number" class="form-control" ng-model="row.food_count"></td>
<td>{{row.food_cost}}</td>
<td class="hidden-print"><button class="btn btn-info hidden-print" data-ng-click="removeRow($index)">Remove</button></td>
</tr>
app = angular.module('app',[]);
app.controller('MyCtrl', ['$scope','$http', function($scope, $http){
$scope.rows = [];
$scope.addRow = function(obj) {
$scope.foodname = obj.id;
$scope.foodprice = obj.price;
$scope.rows.push(obj);
$scope.counter++;
}
}]);
Could you please help me? Thank You.
First you have to understand that food_count property of a row object is the variable that should be updated on repetitive clicks. Updating any other $scope variables won't change row specific data because your view is bound to $scope.rows object.
Your addRow function should look like this.
$scope.addRow = function(obj) {
if($scope.rows.indexOf(obj) >= 0){ // if this obj already exist
$scope.rows[$scope.rows.indexOf(obj)].food_count++;
}
else
$scope.rows.push(obj);
}
Then the objects of $scope.foods should have a property called food_count to display.
$scope.foods = [
{food_name:'Jani',food_cost:'10', food_count:0},
{food_name:'Hege',food_cost:'8',food_count:0},
{food_name:'Kai',food_cost:'5',food_count:0}]
solution

how can I keep some values in a ngshow and ng hide variable so that $digest does not initialize them again and again in angularjs?

I am displaying some data in a web app that I am getting from a SQL database using a http service. I want to be able to modify the information of that data on the same table where the data is shown. I am using angularjs and I am using the directives ng-show and ng-hide on the table. Here I show the part of the code I am talking about.
<table>
<tr>
<td><font size = 4>Servicio: </font> </td>
<td> </td>
<td>
<select class="col-sm-12" name="repeatSelect" id="repeatSelect" ng-model="currentItem.ServicioId">
<option ng-repeat="option in items.Servicio" value="{{option.Id}}"> {{option.Nombre}}</option>
</select>
</td>
</tr>
</table>
<h4>Cliente: {{getNameC(currentItem.ServicioId)}}</h4>
<br />
<button class="btn btn-primary" ng-click="editOrCreate()">Nuevo</button>
<button class="btn btn-primary" ng-click="list()">Actualizar</button>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Cantidad</th>
<th>Tipo Concepto</th>
<th>Descripción</th>
<th>Precio Unitario</th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in itemsSC">
<td>
<div ng-hide="editingData[item.Id]">{{item.Cantidad}}</div>
<div ng-show="editingData[item.Id]"><input ng-model="currentItem.Cantidad" /></div>
</td>
<td>
<div ng-hide="editingData[item.Id]">{{getName(item.ServicioConceptoTipoId)}}</div>
<div ng-show="editingData[item.Id]">
<select name="repeatSelect" id="repeatSelect" ng-model="currentItem.ServicioConceptoTipoId">
<option ng-repeat="option in items.ServicioConceptoTipo" value="{{option.Id}}"> {{option.Nombre}}</option>
</select>
</div>
</td>
<td>
<div ng-hide="editingData[item.Id]">{{item.Descripcion}}</div>
<div ng-show="editingData[item.Id]"><input type="text" ng-model="currentItem.Descripcion" /></div>
</td>
<td>
<div ng-hide="editingData[item.Id]">{{item.PrecioUnitario}}</div>
<div ng-show="editingData[item.Id]"><input ng-model="currentItem.PrecioUnitario" /></div>
</td>
<td>
<button class="btn btn-xs btn-primary" ng-hide="editingData[item.Id]" ng-click="editOrCreate(item)">Modificar</button>
<button class="btn btn-xs btn-primary" ng-show="editingData[item.Id]" ng-click="saveEdit(currentItem,0)">Actualizar</button>
<button class="btn btn-xs btn-primary" ng-hide="viewField" ng-click="delete(item)">Eliminar</button>
</td>
</tr>
</tbody>
<tfoot id="total">
<tr>
<td colspan="3" class="text-right">Total:</td>
<td class="text-right">
{{total(currentItem.ServicioId) | currency}}
</td>
</tr>
</tfoot>
</table>
On my controller I am using object arrays to get the information from the databases and I am using a mirror array to keep the boolean values of the data shown on the table, so depending on the boolean value the tables shows the data or get an input for the user to modify the data.
I get the mirror array once I know the service and client related to the data I want to show and which is possible to be modified.
However, when I click on the button to modify the status of the ng-hide or ng-show object named editingData, the controllers modifies it, but the $digest run all the other functions related to the bindings of the view and returns the bool object array to its inital values.
I haven´t been able to find away to go around this normal working way of the $digest and $watches so my $editingData object is not modified to its initial values. Here I show the code of the controller related to this.
angular.module("App")
.controller("ConceptoCtrl", function ($scope, $http, $resource, serviciosConceptoFactory, serviciosConceptoTipoFactory, serviciosFactory, clientesFactory) {
$scope.list = function () {
$scope.items = serviciosConceptoFactory.query();
$scope.itemsT = serviciosConceptoTipoFactory.query();
$scope.items.ServicioConceptoTipo = $scope.itemsT;
$scope.itemsS = serviciosFactory.query();
$scope.items.Servicio = $scope.itemsS;
$scope.itemsC = clientesFactory.query();
$scope.itemsS.Cliente = $scope.itemsC;
}
//some other functions
$scope.editingData = {};
$scope.getitemsSC = function (item) {
$scope.itemsSC = [];
for (var j = 0; j < $scope.items.length; j++) {
if ($scope.items[j].ServicioId == item) {
newitem = $scope.items[j];
$scope.itemsSC.push(newitem);
}
}
for (var i = 0; i < $scope.itemsSC.length; i++) {
$scope.editingData[$scope.itemsSC[i].Id] = false;
}
}
$scope.editOrCreate = function (item) {
$scope.currentItem = item;
$scope.editingData[item.Id] = true;
}
$scope.list();
});
The {{getNameC(currentItem.ServicioId}} function shown on the html file is the one that calls the $scope.getItemsSC(item) function once it knows the services and client related to the data that will be shown and it is this function the one that initializes the boolean values for the $scope.editingData mirror array depending on the Id of the item.
The $scope.editOrCreate(item) function is the one that changes the boolean object of the specified item so that the view shows the input element for the user instead of the data. However, $digest re-runs the $scope.getItemsSC(item) function because the $watches were modified, and that´s what I want to avoid, because in this case the input elements are never shown.
I thank in advance any help provided
Instead of using the HTML to call functions when data is a available, use the $promise property attached to the resources.
$scope.list = function () {
$scope.items = serviciosConceptoFactory.query();
$scope.itemsT = serviciosConceptoTipoFactory.query();
$scope.items.ServicioConceptoTipo = $scope.itemsT;
$scope.itemsS = serviciosFactory.query();
$scope.items.Servicio = $scope.itemsS;
$scope.itemsC = clientesFactory.query();
$scope.itemsS.Cliente = $scope.itemsC;
var promiseArray = [$scope.items.$promise,
$scope.itemsT.$promise,
$scope.itemsS.$promise,
$scope.itemsC.$promise
];
$q.all(promiseArray).then(function(resultsArray) {
var items = resultsArray[0];
var itemsT = resultsArray[1];
var itemsS = resultsArray[2];
var itemsC = resultsAttay[3];
//create mirror array here
//create editingData array here
});
};
By using the .then method of the promises, the processing of the data can be delayed until it arrives from the server. This way there is no need for the HTML to call functions.

AngularJS - Not update table-pagination after http-get success's event

i have a problem. I'm using AngularJs with WebService-Rest, and can't update some table after the call HTTP-GET to WebService. I did tested everything but i can't get it.
Next, i attach the code. Thanks!
HTML:
...
<div class="row" ng-app="SIGA" ng-controller="CreateTable">
<div class="container-fluid">
<table class="table table-striped">
<tbody>
<tr>
<td>Buscar</td>
<td><input type="text" ng-model="search.nombre" /></td>
</tr>
<tr ng-repeat="e in estaciones | filter:paginate| filter:search" ng-class-odd="'odd'">
<td>
<button class="btn">
Detalle
</button>
</td>
<td>{{e.nombre}}</td>
</tr>
</tbody>
</table>
<pagination total-items="totalItems" ng-model="currentPage"
max-size="5" boundary-links="true"
items-per-page="numPerPage" class="pagination-sm">
</pagination>
</div>
</div>
...
JS: ...
app.controller('RestEstacion', function ($rootScope, $http) {
$http.get('http://localhost:8080/sigarest/webresources/entity.estaciones').
success(function(data) {
$rootScope.estaciones = data; UpdateTable($rootScope);
}).
error(function(status) {
alert('error:'+status);
});
});
app.controller('CreateTable', function ($scope,$rootScope) {
$rootScope.predicate = 'nombre';
$rootScope.reverse = true;
$rootScope.currentPage = 1;
$rootScope.order = function (predicate) {
$rootScope.reverse = ($rootScope.predicate === predicate) ? !$rootScope.reverse : false;
$rootScope.predicate = predicate;
};
$rootScope.estaciones = [];
$rootScope.totalItems = $rootScope.estaciones.length;
$rootScope.numPerPage = 5;
$rootScope.paginate = function (value) {
var begin, end, index;
begin = ($rootScope.currentPage - 1) * $rootScope.numPerPage;
end = begin + $rootScope.numPerPage;
index = $rootScope.estaciones.indexOf(value);
return (begin <= index && index < end);
};
});
JS (Update Function):
function UpdateTable($rootScope){
$rootScope.totalItems = $rootScope.estaciones.length;}
** Original Answer (what comments refer to) **
I think you are assigning the get response object rather than the data inside it. Try this:
success(function(response) {
$rootScope.estaciones = response.data;
UpdateTable($rootScope);
}).
** EDIT **
Now that we have established that you are returning data from the API, the real issue appears to be the double controller using $rootScope as a bridge, which can work but is a bit of an anti-pattern in Angular.
The first controller in your app is trying to act like a service, and so really needs to be converted into one. Here is some SAMPLE PSUEDO CODE to give the idea. I do not fully understand your code, like the pagination directive. There should be a click handler in the pagination directive that would call the service method changePagination and pass in the new page number. There should be no need for $rootScope anywhere in this.
JS
app.service('RestEstacionService', function ($http) {
var RestEstacionService = this;
this.apiData = null;
this.tableData = null;
this.currentPage = 1;
this.numPerPage = 5;
this.url = 'http://localhost:8080/sigarest/webresources/entity.estaciones';
this.getData = function (url) {
return $http.get(url).then(function(response) {
RestEstacionService.apiData = response.data;
// do success stuff here
// figure out which page the view should display
// assign a portion of the api data to the tableData variable
})
};
this.changePagination = function (newPage) {
// do your your pagination work here
};
});
app.controller('RestEstacionController', ['$scope', 'RestEstacionService', function ($scope, RestEstacionService) {
$scope.service = RestEstacionService;
RestEstacionService.getData(RestEstacionService.url);
}]);
HTML
<div class="row" ng-app="SIGA" ng-controller="RestEstacionController">
<div class="container-fluid">
<table class="table table-striped">
<tbody>
<tr>
<td>Buscar</td>
<td><input type="text" ng-model="search.nombre" /></td>
</tr>
<tr ng-repeat="row in services.tableData | filter:paginate| filter:search" ng-class-odd="'odd'">
<td>
<button class="btn">
Detalle
</button>
</td>
<td>{{row.nombre}}</td>
</tr>
</tbody>
</table>
<pagination total-items="services.apiData.length" ng-model="services.currentPage"
max-size="5" boundary-links="true"
items-per-page="services.numPerPage" class="pagination-sm">
</pagination>
</div>

Restricting checkbox selection to a subset w/out using functions in ng-repeat

I want to restrict the number of records that may be selected in a list to a subset of the total records by disabling the remaining records once the max is reached. The list may be 1000s of records in length so performance is an issue. I'm worried my current solution (below/fiddle) will not scale. I've read several articles that warn against using functions (maxSelected() in this case) in ng-repeat for performance reasons, but not sure how I can accomplish this without them? Any suggestions would be greatly appreciated!
Here's the fiddle... http://jsfiddle.net/ALPEP/
HTML:
<div ng-controller="recordsCollectionController">
<table>
<tbody>
<tr
ng-repeat="record in records"
ng-class="{info:selected[record.id], warning:!selected[record.id] && maxSelected()}">
<td>
<input
type="checkbox"
ng-model="selected[record.id]"
ng-disabled="!selected[record.id] && maxSelected()"
id="{{record.id}}"/>
</td>
<td>
<label for="{{record.id}}">{{record.name}}</label>
</td>
</tr>
</tbody>
</table>
</div>
JS:
angular
.module('App',[])
.controller('recordsCollectionController',function($scope){
$scope.selected = {"1":true,"2":true,"3":true};
$scope.records = [
{"id":1,"name":"Homer"},
{"id":2,"name":"Marge"},
{"id":3,"name":"Bart"},
{"id":4,"name":"Lisa"},
{"id":5,"name":"Maggie"}
];
$scope.maxSelected = function(){
var count = 0;
for(x in $scope.selected){
if($scope.selected[x]) count++;
}
return (count===3) ? true : false;
};
});
Here's one option. Your original code had 2*N^2 compares per $digest. This has N compares per selection change. The basic change is to track the selected count and update it via ng-change, rather than counting it again every time it's needed.
<div ng-controller="recordsCollectionController">
<pre>selected = {{selected}}</pre>
<table class="table table-bordered table-striped">
<colgroup>
<col style="width:20px"/>
<col/>
</colgroup>
<tbody>
<tr
ng-repeat="record in records"
ng-class="{info:selected[record.id], warning:!selected[record.id] && selMax}">
<td>
<input
type="checkbox"
ng-model="selected[record.id]"
ng-disabled="!selected[record.id] && selMax"
ng-change="updateSelected()"
id="{{record.id}}"/>
</td>
<td>
<label for="{{record.id}}">
{{record.name}}
</label>
</td>
</tr>
</tbody>
</table>
</div>
angular
.module('App',[])
.controller('recordsCollectionController',function($scope){
$scope.selected = {"1":true,"2":true,"3":true};
$scope.selMax = true;
$scope.records = [
{"id":1,"name":"Homer"},
{"id":2,"name":"Marge"},
{"id":3,"name":"Bart"},
{"id":4,"name":"Lisa"},
{"id":5,"name":"Maggie"}
];
$scope.updateSelected = function(){
console.log("Ping!");
var count = 0;
for(x in $scope.selected){
if($scope.selected[x]) count++;
}
$scope.selMax = (count >= 3);
};
});

Resources