I've created an application in angular-JS for creating table with dynamic columns from json
For example the JSON structure returning from a service is in the structure where the others field of the main JSON contains another JSON array which is the additional columns,
so all together there will be four additional dynamic columns i.e File 1, File 2, File 3, File 4 each object has value for the corresponding File field, sometime present sometime not present.
$scope.getColumns = function()
{
//console.log( $scope.datas[0].others[0]);
$scope.datas.resultsOrder = new Array();
for ( var i = 0; i < $scope.datas.length; i++)
{
for ( var j = 0; j < $scope.datas[i].others.length; j++)
{
if (countInstances($scope.datas.resultsOrder, $scope.datas[i].others[j].id) < countInstances(
$scope.datas[i].others, $scope.datas[i].others[j].id)){
$scope.datas.resultsOrder.push($scope.datas[i].others[j].id);
}
}
}
$scope.datas.resultsOrder.sort(function(a, b){
return a.localeCompare(b);
});
return $scope.datas.resultsOrder;
}
I've shown the tables with the dynamic columns perfectly using javascript help, but can anyone please tell me some other way for creating the above dynamic table through angular js in a simple way, since in my code I've used javascript complex logic for the creation of dynamic columns which is as shown below
My JS-Fiddle is given below
Demo
This wll create an object called columns where the properties are the names of the dynamic columns ('File 1', 'File 2' etc.)
Controller:
$scope.columns = {};
angular.forEach( $scope.datas, function(data){
angular.forEach( data.others, function(other){
// Set the 'File x' property for each item in the others array
data[other.id] = other.value;
// Add the dyanmic column to the columns object
$scope.columns[other.id] = null;
});
});
View:
<!-- table header -->
<tr>
<th ng-repeat="(column,val) in columns">
<a ng-click="sort_by()"><i>{{column}}</i></a>
</th>
....
</tr>
<!-- data rows -->
<td ng-repeat="(column,v) in columns">{{val[column]}}</td>
Fiddle
Related
I have a datatable whose data I am populating as follows. I need to add column chooser to the below function. Can somebody tell me where to place the columns array in the below code.
function(jsonResponse)
{
$("#example").dataTable().fnClearTable();
var data = "jsonResponse."+"controlKpiList";
$.each(eval(data), function(id1, value) {
$("#example").dataTable().fnAddData([
value.ASP_NAME,
value.TIERING_2,
]);
});
}
Can anyone assist me in inserting a row into a DGRID? The way I am doing it now is cloning a row, add it to the collection with the use of directives and then try to apply it to the grid. Below is the code I am using but the new row ends up getting added to the bottom instead of being inserted.
// Clone a row
theTable = tmxdijit.registry.byId(tableName);
firstRow = theTable.collection.data[theTable.collection.data.length-1];
firstRowDom = theTable.row(firstRow.id);
var cloneRow = json.stringify(firstRow);
cloneRow = json.parse(cloneRow);
// Get the row I want to add before
var theSelected = Object.keys(theTable.selection)[0];
if(theSelected.length > 0) {
var theRowID = theSelected[0];
}
theTable.collection.add(cloneRow, {beforeId: theRowID});
theTable.renderArray([cloneRow]);
There are two general ways to handle data insertion. One is to manually add data to an array, ensure it's properly sorted, and then tell the grid to render the array. A better way is to use an OnDemandGrid with a trackable store.
For dgrid/dstore to support simple dynamic insertion of rows, make sure the store is trackable, and that data items have some unique id property:
var StoreClass = Memory.createSubclass(Trackable);
var store = new StoreClass({ data: whatever });
var grid = new OnDemandGrid({
columns: { /* columns */ },
collection: store
});
By default dstore assumes the id property is "id", but you can specify something else:
var store = new StoreClass({ idProperty: "name", data: whatever });
If you want the data to be sorted, a simple solution is to set a sort on the grid (the grid will sort rows in ascending order using the given property name):
grid.set('sort', 'name');
To add or remove data, use the store methods put and remove.
var collection = grid.get('collection');
collection.put(/* a new data item */);
collection.remove(/* a data item id */);
The grid will be notified of the store update and will insert or remove the rows.
The dgrid Using Grids and Stores tutorial has more information and examples.
Instead of this, why don't you add the data directly to the grid store? See if this helps
https://dojotoolkit.org/reference-guide/1.10/dojox/grid/example_Adding_and_deleting_data.html
Adding and Deleting data
If you want to add (remove) data programmatically, you just have to add (remove) it from the underlying data store. Since DataGrid is “DataStoreAware”, changes made to the store will be reflected automatically in the DataGrid.
dojo.require("dojox.grid.DataGrid");
dojo.require("dojo.data.ItemFileWriteStore");
dojo.require("dijit.form.Button");
.
<div>
This example shows, how to add/remove rows
</div>
<table data-dojo-type="dojox.grid.DataGrid"
data-dojo-id="grid5"
data-dojo-props="store:store3,
query:{ name: '*' },
rowsPerPage:20,
clientSort:true,
rowSelector:'20px'
style="width: 400px; height: 200px;">
<thead>
<tr>
<th width="200px"
field="name">Country/Continent Name</th>
<th width="auto"
field="type"
cellType="dojox.grid.cells.Select"
options="country,city,continent"
editable="true">Type</th>
</tr>
</thead>
</table>
<div data-dojo-type="dijit.form.Button">
Add Row
<script type="dojo/method" data-dojo-event="onClick" data-dojo-args="evt">
// set the properties for the new item:
var myNewItem = {type: "country", name: "Fill this country name"};
// Insert the new item into the store:
// (we use store3 from the example above in this example)
store3.newItem(myNewItem);
</script>
</div>
<div data-dojo-type="dijit.form.Button">
Remove Selected Rows
<script type="dojo/method" data-dojo-event="onClick" data-dojo-args="evt">
// Get all selected items from the Grid:
var items = grid5.selection.getSelected();
if(items.length){
// Iterate through the list of selected items.
// The current item is available in the variable
// "selectedItem" within the following function:
dojo.forEach(items, function(selectedItem){
if(selectedItem !== null){
// Delete the item from the data store:
store3.deleteItem(selectedItem);
} // end if
}); // end forEach
} // end if
</script>
</div>
.
#import "{{ baseUrl }}dijit/themes/nihilo/nihilo.css";
#import "{{ baseUrl }}dojox/grid/resources/nihiloGrid.css";
I am using Angular Kendo and building one list.
<kendo-mobile-list-view id="myList" class="item-list" k-template="templates.myListTemp" k-data-source="myService.myDataSource">
</kendo-mobile-list-view>
I am using Kendo DataSource and ObservableArray for generating data for my list in my service.
this.myDataSource = new kendo.data.DataSource({ data:this.myObservableArray });
this.myObservableArray.push({ key: "test", id:"test" });
Every is working as expected.
Now I want to display a message when their are no records to display, in the place I am displaying the list, like "NO RECORDS TO DISPLAY, Please Refresh".
How can I achieve this using angular Kendo.
I saw few posts for Kendo JQuery but no solution for Angular Kendo.
Define the grid
$('#grid').kendoGrid({
dataSource: employeeDataSource,
dataBound: function () {
DisplayNoResultsFound($('#grid'));
},
The javascript function 'DisplayNoResultsFound' is as follows
function DisplayNoResultsFound(grid) {
// Get the number of Columns in the grid
var dataSource = grid.data("kendoGrid").dataSource;
var colCount = grid.find('.k-grid-header colgroup > col').length;
// If there are no results place an indicator row
if (dataSource._view.length == 0) {
grid.find('.k-grid-content tbody')
.append('<tr class="kendo-data-row"><td colspan="' + colCount + '" style="text-align:center"><b>No Results Found!</b></td></tr>');
}
// Get visible row count
var rowCount = grid.find('.k-grid-content tbody tr').length;
// If the row count is less that the page size add in the number of missing rows
if (rowCount < dataSource._take) {
var addRows = dataSource._take - rowCount;
for (var i = 0; i < addRows; i++) {
grid.find('.k-grid-content tbody').append('<tr class="kendo-data-row"><td> </td></tr>');
}
}
}
First, you should add a name to your kendo instance(myList):
<kendo-mobile-list-view="myList" id="myList" class="item-list" k-template="templates.myListTemp" k-data-source="myService.myDataSource">
</kendo-mobile-list-view>
Then, in your controller:
$scope.myList.bind('dataBound',DisplayNoResultsFound)
Also you could specify some k-options in the html and read those options(including the dataBound) from the angular controller, this link explains more about it
I have a table with ng-grid, and the problem is that i'm not sure how to collect the selected row(s) id or variable to pass into my delete function.
here is a quick mockup of what i'm trying to do
http://plnkr.co/edit/zy653RrqHmBiRJ7xDHlV?p=preview
the following code is from my html, a clickable delete button that takes in 2 parameters, the array of checkbox ids and the index at the corresponding table. This delete method was obtained from this tutorial : http://alexpotrykus.com/blog/2013/12/07/angularjs-with-rails-4-part-1/
<div class="btn-group">
<button class="my-btn btn-default button-row-provider-medical-services" ng-click="deleteProviderMedicalService([], $index)">Delete</button>
</button>
</div>
<div class="gridStyle ngGridTable" ng-grid="gridOptions">
</div>
The following code grabs the json data from a url, queries it and returns it. It also contains the delete function that gets called from the controller in the html page.
app.factory('ProviderMedicalService', ['$resource', function($resource) {
function ProviderMedicalService() {
this.service = $resource('/api/provider_medical_services/:providerMedicalServiceId', {providerMedicalServiceId: '#id'});
};
ProviderMedicalService.prototype.all = function() {
return this.service.query();
};
ProviderMedicalService.prototype.delete = function(providerId) {
this.service.remove({providerMedicalServiceId: providerId});
};
return new ProviderMedicalService;
}]);
The following is my controller(not everything, just the most important bits). $scope.provider_medical_services gets the json data and puts it into the ng-grid gridOptions.
After reading the ng-grid docs, i must somehow pass the checkbox ids from the selectedItems array and pass it into html doc to the delete function. Or, i'm just doing this completely wrong, as i hacked this together. Solutions and suggestions are greatly appreciated
(function() {
app.controller('ModalDemoCtrl', ['$scope', 'ProviderMedicalService', '$resource', '$modal', function($scope, ProviderMedicalService, $resource, $modal) {
var checkBoxCellTemplate = '<div class="ngSelectionCell"><input tabindex="-1" class="ngSelectionCheckbox" type="checkbox" ng-checked="row.selected" /></div>';
$scope.provider_medical_services = ProviderMedicalService.all();
$scope.deleteProviderMedicalService = function(ids,idx) {
$scope.provider_medical_services.splice(idx, 1);
return ProviderMedicalService.delete(ids);
};
$scope.gridOptions = {
columnDefs: [
{
cellTemplate: checkBoxCellTemplate,
showSelectionCheckbox: true
},{
field: 'name',
displayName: 'CPT Code/Description'
},{
field: 'cash_price',
displayName: 'Cash Price'
},{
field: 'average_price',
displayName: 'Average Price'
},
],
data: 'provider_medical_services',
selectedItems: []
};
i think the easiest option is pass an (array index) as data-id to your dom, which u can pick it from there.
{{$index}} is a variable you can use in ng-repeat
======= ignore what i said above, since i normaly writes my own custom stuff ======
I just had a look at ng-grid, i took their example. i've added a delete all selected function, as well as someone elses delete current row function ( these is pure angular way ) to see the code, hover over the top right corner < edit in jsbin >
http://jsbin.com/huyodove/1/
Honestsly i don't like it this way, you would be better off use something like lodash to manage your arrays and do your own custom grid. Using foreach to find the row index isn't good performance.
In their doc, it says you can change the row template, and which you should, so you can add the {{index}} to that row, and filter your data through that index rather which is a little bit better. anyway beware of deleting cells after you have filter your table.
I don't quite get much your question, but you can access to selectedItems of ng-grid as following: $scope.gridOptions.$gridScope.selectedItems (see ng-grid API for more information, but technically this array holds the list of selected items in multiple mode - or only one item in single mode)
For your case, the deleteAll() function could be someething like this:
$scope.deleteAll = function() {
$scope.myData = [];
}
The delete() function which delete selected items can be:
$scope.delete = function() {
$.each($scope.gridOptions.$gridScope.selectedItems, function(index, selectedItem) {
//remove the selected item from 'myData' - it is 2-ways binding to any modification to myData will be reflected in ng-grid table
//you could check by either name or unique id of item
});
}
I am trying to dynamically build the structure of a kendo-angular grid. My problem is that the grid options are not known when the k-options attribute is evaluated, so the grid is binding to ALL of the columns on the datasource.
Here is the HTML:
<div kendo-grid k-options="{{gridModel.options}}"
k-data-source="gridModel.myDataSource">
</div>
And here is the javascript in the controller:
// this is called after the api call has successfully returned with data
function getSucceeded(){
...
$scope.gridModel.options = function(){
// function that properly builds options object with columns, etc.
}
// this is just shown for example... the data is properly loading
$scope.gridModel.myDataSource.data(ds.data());
}
The data is properly loading, but because gridModel.options was evaluated in the HTML prior to being set by the success method, it is essentially ignored and all of the columns from the datasource are being rendered.
This works like a champ when gridModel.options is static.
How can I defer the evaluation of k-options and/or force a reevaluation after they've been set by the controller?
I was able to figure it out. I had to do four things:
Update my version of angularjs (I was on 1.08 which does not have the ng-if directive). I updated to 1.2.0rc3.
Wrap my kendo-grid div in an ng-if div
Invoke my function! I was just setting $scope.gridModel.options to a function - I needed to actually invoke the function so I'd be setting the variable to the value returned from the function.
I had to update my angular.module declaration to include ngRoute (based on it being separated into it's own module in 1.2.x).
Here's the updated HTML:
<div data-ng-if="contentAvailable">
<div kendo-grid k-options="{{gridModel.options}}"
k-data-source="gridModel.myDataSource">
</div>
</div>
And here's the updated controller (not shown: I set $scope.contentAvailable=false; at the beginning of the controller):
// this is called after the api call has successfully returned with data
function getSucceeded(){
...
$scope.gridModel.options = function(){
// function that dynamically builds options object with columns, etc.
}(); // <----- NEED to invoke function!!
// this is just shown for example... the data is properly loading
$scope.gridModel.myDataSource.data(ds.data());
$scope.contentAvailable=true; // trigger the ng-if
}
I actually moved the function into a config file so I'm not polluting the controller with too much configuration code. Very happy to have figured this out.
Here is a sample using 'Controller As' syntax, dynamic columns and paging.
var app = angular.module("app", ["kendo.directives"]);
function MyCtrl() {
var colsList = [{
name: "col1"
}, {
name: "col2"
}, {
name: "col3"
}, {
name: "col4"
}];
var gridCols = [];
var iteration = 1;
var vm = this;
vm.gridOptions = {
columns: gridCols,
dataSource: new kendo.data.DataSource({
pageSize: 10
}),
pageable: true
};
vm.buildGrid = function() {
var data = {};
vm.gridOptions.columns = [];
for (var x = 0; x < colsList.length; x++) {
if (iteration % 2 === 0 && x === colsList.length - 1) continue;
var col = {};
col.field = colsList[x].name;
col.title = colsList[x].name;
data[col.field] = "it " + iteration + " " + (1111 * (x + 1));
vm.gridOptions.columns.push(col);
}
// add one row to the table
vm.gridOptions.dataSource.add(data);
iteration++;
};
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link rel="stylesheet" href="http://cdn.kendostatic.com/2015.1.318/styles/kendo.common.min.css" />
<link rel="stylesheet" href="http://cdn.kendostatic.com/2015.1.318/styles/kendo.default.min.css" />
<script src="http://cdn.kendostatic.com/2015.1.318/js/kendo.all.min.js"></script>
<body ng-app="app">
<div ng-controller="MyCtrl as vm">
<button ng-click="vm.buildGrid()">Build Grid</button>
<div kendo-grid="grid" k-options="vm.gridOptions" k-rebind="vm.gridOptions"></div>
</div>
</body>
We can use the k-rebind directive for this. From the docs:
Widget Update upon Option Changes
You can update a widget from controller. Use the special k-rebind attribute to create a widget which automatically updates when some scope variable changes. This option will destroy the original widget and will recreate it using the changed options.
Apart from setting the array of columns in the GridOptions as we normally do, we have to hold a reference to it:
vm.gridOptions = { ... };
vm.gridColumns = [{...}, ... ,{...}];
vm.gridOptions.columns = vm.gridColumns;
and then pass that variable to the k-rebind directive:
<div kendo-grid="vm.grid" options="vm.gridOptions" k-rebind="vm.gridColumns">
</div>
And that's it when you are binding the grid to remote data (OData in my case). Now you can add or remove elements to/from the array of columns. The grid is going to query for the data again after it is recreated.
When binding the Grid to local data (local array of objects), we have to somehow postpone the binding of the data until the widget is recreated. What worked for me (maybe there is a cleaner solution to this) is to use the $timeout service:
vm.gridColumns.push({ ... });
vm.$timeout(function () {
vm.gridOptions.dataSource.data(vm.myArrayOfObjects);
}, 0);
This has been tested using AngularJS v1.5.0 and Kendo UI v2016.1.226.