Skip to content

Commit

Permalink
Merge pull request angular-ui#1 from angular-ui/master
Browse files Browse the repository at this point in the history
Pull from upstream
  • Loading branch information
Umer Farooq committed Mar 23, 2015
2 parents f510609 + db65825 commit 7cbc6b7
Show file tree
Hide file tree
Showing 34 changed files with 1,362 additions and 643 deletions.
32 changes: 30 additions & 2 deletions misc/tutorial/103_filtering.ngdoc
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ for `filters: [{ term: 'xxx' }]`. See the "age" column below for an example.
The example also includes date filters. These work, however there isn't a date chooser in the filter widget - so you may need to implement a custom field
if you want to filter dates in this way.

### Dropdowns
Filtering supports dropdowns, in order to set a particular column to use a dropdown you should set:
`type: uiGridConstants.filter.SELECT`
and
`selectOptions: [ { value: 'x', label: 'decode of x' } , .... ]`

If you need to internationalize the labels you'll need to complete that before providing the selectOptions array.

@example
<example module="app">
<file name="app.js">
Expand All @@ -69,7 +77,12 @@ if you want to filter dates in this way.
// default
{ field: 'name' },
// pre-populated search field
{ field: 'gender', filter: { term: 'male' } },
{ field: 'gender', filter: {
term: '1',
type: uiGridConstants.filter.SELECT,
selectOptions: [ { value: '1', label: 'male' }, { value: '2', label: 'female' }, { value: '3', label: 'unknown'}, { value: '4', label: 'not stated' }, { value: '5', label: 'a really long value that extends things' } ]
},
cellFilter: 'mapGender' },
// no filter input
{ field: 'company', enableFiltering: false, filter: {
noTerm: true,
Expand Down Expand Up @@ -124,14 +137,29 @@ if you want to filter dates in this way.
data.forEach( function addDates( row, index ){
row.mixedDate = new Date();
row.mixedDate.setDate(today.getDate() + ( index % 14 ) );
row.gender = row.gender==='male' ? '1' : '2';
});
});

$scope.toggleFiltering = function(){
$scope.gridOptions.enableFiltering = !$scope.gridOptions.enableFiltering;
$scope.gridApi.core.notifyDataChange( uiGridConstants.dataChange.COLUMN );
};
}]);
}])
.filter('mapGender', function() {
var genderHash = {
1: 'male',
2: 'female'
};

return function(input) {
if (!input){
return '';
} else {
return genderHash[input];
}
};
});
</file>
<file name="index.html">
<div ng-controller="MainCtrl">
Expand Down
39 changes: 33 additions & 6 deletions misc/tutorial/209_grouping.ngdoc
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,28 @@ The group rowHeader by default is only visible when one or more columns are grou
to have no visual impact when grouping is turned on but unused. If you'd like the groupRowHeader permanently
present then set the `groupingRowHeaderAlwaysVisible: true` gridOption.

If you want to change the grouping programmatically after grid initialisation, you do this through calling the
provided methods:

- `groupColumn`: groups an individual column. Adds it to the end of the current grouping - so you need to remove
existing grouped columns first if you wanted this to be the only grouping. Adds a sort ASC if there isn't one
- `ungroupColumn`: ungroups an individual column
- `aggregateColumn`: sets aggregation on a column, including setting the aggregation off. Automatically removes
any sort first.
- `setGrouping`: sets all the grouping in one go, removing existing grouping
- `getGrouping`: gets the grouping config for the grid
- `clearGrouping`: clears all current grouping settings

Grouping is still alpha, and under development, however it is included in the distribution files
to allow people to start using it. Notable outstandings are:

- does not correctly handle columns that are based on functions or complex objects. The groupHeader rows create
a fake row.entity, and then set the appropriate fields in that entity. This doesn't work well with
complex column definitions at present
- notify data change capability is needed for when people programmatically change the grouping
- some more unit testing
- enhancement: allow a limit on number of columns grouped
- consideration of RTL - not sure whether the indent/outdent should get reversed?
- special formatting for header rows in exporter?
- add grouping options to saveState

Options to watch out for include:

Expand All @@ -53,7 +63,16 @@ Options to watch out for include:
visual indication of what sort of aggregation is going on. Refer the example below, the balance column with
an average
- `groupingShowCounts`: set to false if you don't like the counts against the groupHeaders


If you would like to suppress the data in a grouped column (so it only shows in the groupHeader rows) this can
be done by overriding the cellTemplate for any of the columns you allow grouping on as follows:

`cellTemplate: '<div ng-if="!col.grouping || col.grouping.groupPriority === undefined || col.grouping.groupPriority === null || ( row.groupHeader && col.grouping.groupPriority === row.groupLevel )" class="ui-grid-cell-contents" title="TOOLTIP">{{COL_FIELD CUSTOM_FILTERS}}</div>'`

In the example below this has been done on the state column only. This isn't included in the base code as it
could potentially interact with people's custom templates.


@example
In this example we group by the state column then the gender column, and we count the names (a proxy for
Expand All @@ -70,10 +89,10 @@ we can't easily see that it's an average.
enableFiltering: true,
columnDefs: [
{ name: 'name', width: '30%' },
{ name: 'gender', grouping: { groupPriority: 1 }, sort: { direction: 'asc' }, width: '20%' },
{ name: 'gender', grouping: { groupPriority: 1 }, sort: { priority: 1, direction: 'asc' }, width: '20%' },
{ name: 'age', grouping: { aggregation: uiGridGroupingConstants.aggregation.MAX }, width: '20%' },
{ name: 'company', width: '25%' },
{ name: 'state', grouping: { groupPriority: 0 }, sort: { direction: 'desc' }, width: '35%' },
{ name: 'state', grouping: { groupPriority: 0 }, sort: { priority: 0, direction: 'desc' }, width: '35%', cellTemplate: '<div><div ng-if="!col.grouping || col.grouping.groupPriority === undefined || col.grouping.groupPriority === null || ( row.groupHeader && col.grouping.groupPriority === row.groupLevel )" class="ui-grid-cell-contents" title="TOOLTIP">{{COL_FIELD CUSTOM_FILTERS}}</div></div>' },
{ name: 'balance', width: '25%', cellFilter: 'currency', groupingSuppressAggregationText: true, grouping: { aggregation: uiGridGroupingConstants.aggregation.AVG } }
],
onRegisterApi: function( gridApi ) {
Expand All @@ -87,6 +106,7 @@ we can't easily see that it's an average.
data[i].state = data[i].address.state;
data[i].balance = Number( data[i].balance.slice(1).replace(/,/,'') );
}
delete data[2].age;
$scope.gridOptions.data = data;
});

Expand All @@ -96,16 +116,23 @@ we can't easily see that it's an average.

$scope.toggleRow = function( rowNum ){
$scope.gridApi.grouping.toggleRowGroupingState($scope.gridApi.grid.renderContainers.body.visibleRowCache[rowNum]);
}
};

$scope.changeGrouping = function() {
$scope.gridApi.grouping.clearGrouping();
$scope.gridApi.grouping.groupColumn('age');
$scope.gridApi.grouping.aggregateColumn('state', uiGridGroupingConstants.aggregation.COUNT);
};
}]);
</file>

<file name="index.html">
<div ng-controller="MainCtrl">
<div id="grid1" ui-grid="gridOptions" ui-grid-grouping ui-grid-pinning class="grid"></div>
<button id="expandAll" type="button" class="btn btn-success" ng-click="expandAll()">Expand All</button>
<button id="toggleFirstRow" type="button" class="btn btn-success" ng-click="toggleRow(0)">Toggle First Row</button>
<button id="toggleSecondRow" type="button" class="btn btn-success" ng-click="toggleRow(1)">Toggle Second Row</button>
<button id="changeGrouping" type="button" class="btn btn-success" ng-click="changeGrouping()">Change Grouping</button>
<div id="grid1" ui-grid="gridOptions" ui-grid-grouping ui-grid-pinning class="grid"></div>
</div>
</file>

Expand Down
24 changes: 23 additions & 1 deletion misc/tutorial/210_selection.ngdoc
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ The selectAll box can be disabled by setting `enableSelectAll` to false.

You can set the selection row header column width by setting 'selectionRowHeaderWidth' option.

You can use an `isRowSelectable` function to determine which rows are selectable. If you set this function in the options
after grid initialisation you need to call `gridApi.core.notifyDataChange(uiGridConstants.dataChange.OPTIONS)` to enable
the option. In the grid below pressing the button to "set selectable" will set any rows that have an age > 30 to not be
selectable, and also set the age of the first row to 31.

@example
Two examples are provided, the first with rowHeaderSelection and multi-select, the second without. The first example
auto-selects the first row once the data is loaded.
Expand All @@ -44,7 +49,7 @@ auto-selects the first row once the data is loaded.
<file name="app.js">
var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.selection']);

app.controller('MainCtrl', ['$scope', '$http', '$log', '$timeout', function ($scope, $http, $log, $timeout) {
app.controller('MainCtrl', ['$scope', '$http', '$log', '$timeout', 'uiGridConstants', function ($scope, $http, $log, $timeout, uiGridConstants) {
$scope.gridOptions = {
enableRowSelection: true,
enableSelectAll: true,
Expand Down Expand Up @@ -93,6 +98,22 @@ auto-selects the first row once the data is loaded.
$scope.toggleRow1 = function() {
$scope.gridApi.selection.toggleRowSelection($scope.gridOptions.data[0]);
};

$scope.setSelectable = function() {
$scope.gridApi.selection.clearSelectedRows();

$scope.gridOptions.isRowSelectable = function(row){
if(row.entity.age > 30){
return false;
} else {
return true;
}
};
$scope.gridApi.core.notifyDataChange(uiGridConstants.dataChange.OPTIONS);

$scope.gridOptions.data[0].age = 31;
$scope.gridApi.core.notifyDataChange(uiGridConstants.dataChange.EDIT);
};

$scope.gridOptions.onRegisterApi = function(gridApi){
//set gridApi on scope
Expand Down Expand Up @@ -152,6 +173,7 @@ auto-selects the first row once the data is loaded.
<br/>
<button type="button" class="btn btn-success" ng-disabled="!gridApi.grid.options.multiSelect" ng-click="selectAll()">Select All</button>
<button type="button" class="btn btn-success" ng-click="clearAll()">Clear All</button>
<button type="button" class="btn btn-success" ng-click="setSelectable()">Set Selectable</button>
<br/>

<div ui-grid="gridOptions" ui-grid-selection class="grid"></div>
Expand Down
143 changes: 81 additions & 62 deletions misc/tutorial/212_infinite_scroll.ngdoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,85 +2,104 @@
@name Tutorial: 212 Infinite scroll
@description

The infinite scroll feature allows the user to lazy load their data to gridOptions.data
The infinite scroll feature allows the user to lazy load their data to gridOptions.data.

Specify percentage when lazy load should trigger:
<pre>
$scope.gridOptions.infiniteScroll = 20;
</pre>
Once you reach the top (or bottom) of your real data set, you can notify that no more pages exist
up (or down), and infinite scroll will stop triggering events in that direction. You can also
optionally tell us up-front that there are no more pages up through `infiniteScrollUp = true` or down through
`infiniteScrollDown = true`, and we will never trigger
pages in that direction. By default we assume you have pages down but not up.

You can specify the percentage of the grid at which the infinite scroll will trigger a request for
more data `infiniteScrollPercentage = 20`. By default we trigger when you are 20% away from the end of
the grid (in either direction).

We will raise a `needMoreData` or `needMoreDataTop` event, which you must listen to and respond to if
you have told us that you have more data available. Once you have retrieved the data and added it to your
data array (at the top if the event was `needMoreDataTop`), you need to call `dataLoaded` to tell us
that you have loaded your data. Optionally, you can tell us that there is no more data, and we won't trigger
further requests for more data in that direction.

When you have loaded your data we will attempt to adjust the grid scroll to give the appearance of continuous
scrolling. This is a little jumpy at present, largely because we work of percentages instead of a number of
rows from the end. We basically assume that your user will have reached the end of the scroll (upwards or downwards)
by the time the data comes back, and scroll the user to the beginning of the newly added data to reflect that. If
your user has already scrolled a lot of pages, then they may not be at the end of the data (20% can be a long way).
Ideally the API would change to a number of rows.

Finally, we suppress the normal grid behaviour of propagating the scroll to the parent container when you reach the end
if infinite scroll is enabled and there is still data in that direction.


@example
In this example we have a data set that starts at page 2 of a 5 page data set. Each page is 100 records, so we start at
record 200, and we can scroll up 2 pages, and scroll down 2 pages. You should see smooth scrolling as you move up, when
you hit record zero a touchpad scroll should propagate to the parent page. You should also see smooth scrolling as you
move down, and when you hit record 499 a touchpad scroll should propagate to the parent page.

<example module="app">
<file name="app.js">
var app = angular.module('app', ['ngTouch', 'ui.grid', 'ui.grid.infiniteScroll']);

app.controller('MainCtrl', ['$scope', '$http', '$log', function ($scope, $http, $log) {
$scope.gridOptions = {};

/**
* @ngdoc property
* @name infiniteScrollPercentage
* @propertyOf ui.grid.class:GridOptions
* @description This setting controls at what percentage of the scroll more data
* is requested by the infinite scroll
*/
$scope.gridOptions.infiniteScrollPercentage = 15;

$scope.gridOptions.columnDefs = [
{ name:'id'},
{ name:'name' },
{ name:'age' }
];
var page = 0;
var pageUp = 0;
var getData = function(data, page) {
var res = [];
for (var i = (page * 100); i < (page + 1) * 100 && i < data.length; ++i) {
res.push(data[i]);
app.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.gridOptions = {
infiniteScrollPercentage: 15,
infiniteScrollUp: true,
infiniteScrollDown: true,
columnDefs: [
{ name:'id'},
{ name:'name' },
{ name:'age' }
],
data: 'data',
onRegisterApi: function(gridApi){
gridApi.infiniteScroll.on.needLoadMoreData($scope, $scope.getDataDown);
gridApi.infiniteScroll.on.needLoadMoreDataTop($scope, $scope.getDataUp);
$scope.gridApi = gridApi;
}
return res;
};

var getDataUp = function(data, page) {
var res = [];
for (var i = data.length - (page * 100) - 1; (data.length - i) < ((page + 1) * 100) && (data.length - i) > 0; --i) {
data[i].id = -(data.length - data[i].id)
res.push(data[i]);
}
return res;
$scope.data = [];

var firstPage = 2;
var lastPage = 1;

$scope.getDataDown = function() {
$http.get('/data/10000_complex.json')
.success(function(data) {
lastPage++;
var newData = $scope.getPage(data, lastPage);
$scope.data = $scope.data.concat(newData);
$scope.gridApi.infiniteScroll.dataLoaded(null, lastPage === 4);
})
.error(function(error) {
$scope.gridApi.infiniteScroll.dataLoaded();
});
};

$http.get('/data/10000_complex.json')
$scope.getDataUp = function() {
$http.get('/data/10000_complex.json')
.success(function(data) {
$scope.gridOptions.data = getData(data, page);
++page;
firstPage--;
var newData = $scope.getPage(data, firstPage);
$scope.data = newData.concat($scope.data);
$scope.gridApi.infiniteScroll.dataLoaded(firstPage === 0, null);
})
.error(function(error) {
$scope.gridApi.infiniteScroll.dataLoaded();
});
};

$scope.gridOptions.onRegisterApi = function(gridApi){
gridApi.infiniteScroll.on.needLoadMoreData($scope,function(){
$http.get('/data/10000_complex.json')
.success(function(data) {
$scope.gridOptions.data = $scope.gridOptions.data.concat(getData(data, page));
++page;
gridApi.infiniteScroll.dataLoaded();
})
.error(function() {
gridApi.infiniteScroll.dataLoaded();
});
});
gridApi.infiniteScroll.on.needLoadMoreDataTop($scope,function(){
$http.get('/data/10000_complex.json')
.success(function(data) {
$scope.gridOptions.data = getDataUp(data, pageUp).reverse().concat($scope.gridOptions.data);
++pageUp;
gridApi.infiniteScroll.dataLoaded();
})
.error(function() {
gridApi.infiniteScroll.dataLoaded();
});
});

$scope.getPage = function(data, page) {
var res = [];
for (var i = (page * 100); i < (page + 1) * 100 && i < data.length; ++i) {
res.push(data[i]);
}
return res;
};

$scope.getDataDown();
}]);
</file>
<file name="index.html">
Expand Down
1 change: 1 addition & 0 deletions misc/tutorial/304_grid_menu.ngdoc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use i18n on this through the `gridMenuTitleFilter` setting)
- `context`: by default, the `action`, `shown` and `active`'s' contexts will have a reference to the grid added as the
property `grid` (accessible through `this.grid`. You can pass in your own context by supplying
the `context` property to your menu item. It will be accessible through `this.context`.
- `leaveOpen`: by default false, if set to true the menu will be left open after the action

The exporter feature also adds menu items to this menu. The `exporterMenuCsv` option is set
to false, which suppresses csv export. The 'export selected rows' option is only available
Expand Down
Loading

0 comments on commit 7cbc6b7

Please sign in to comment.