Creating a kendo-grid with reusable options using AngularJS - javascript

How to create a kendo-grid with reusable options using AngularJS?
Besides the default settings, the grid must include a checkbox column dynamically with the option to select all rows . Methods to treat the selections should be part of the directive and, somehow, I should be able to access the rows selected in controller.
Another important behavior is to keep a reference to the grid :
// In the controller : $scope.grid
<div kendo-grid="grid" k-options="gridOptions"></div>
Below an initial path that I imagined, but it is not 100% working because AngularJS not compile information from checkbox column, so do not call the methods of the controller directive. At the same time I'm not sure where force $compile in this code.
myApp.directive('myApp', ['$compile', function ($compile) {
var directive = {
restrict: 'A',
replace: true,
template: '<div></div>',
scope: {
gridConfiguration: '='
},
controller: function ($scope) {
$scope.gridIds = [];
$scope.gridIdsSelected = [];
var updateSelected = function (action, id) {
if (action === 'add' && $scope.gridIdsSelected.indexOf(id) === -1) {
$scope.gridIdsSelected.push(id);
}
if (action === 'remove' && $scope.gridIdsSelected.indexOf(id) !== -1) {
$scope.gridIdsSelected.splice($scope.gridIdsSelected.indexOf(id), 1);
}
};
$scope.updateSelection = function ($event, id) {
var checkbox = $event.target;
var action = (checkbox.checked ? 'add' : 'remove');
updateSelected(action, id);
};
$scope.isSelected = function (id) {
return $scope.gridIdsSelected.indexOf(id) >= 0;
};
$scope.selectAll = function ($event) {
var checkbox = $event.target;
var action = (checkbox.checked ? 'add' : 'remove');
for (var i = 0; i < $scope.gridIds.length; i++) {
var id = $scope.gridIds[i];
updateSelected(action, id);
}
};
},
link: function ($scope, $element, $attrs) {
var baseColumns = [
{
headerTemplate: '<input type="checkbox" id="selectAll" ng-click="selectAll($event)" ng-checked="isSelectedAll()">',
template: '<input type="checkbox" name="selected" ng-checked="isSelected(#=Id#)" ng-click="updateSelection($event, #=Id#)">',
width: 28
}
];
for (var i = 0; i < $scope.gridConfiguration.columns.length; i++) {
var column = $scope.gridConfiguration.columns[i];
baseColumns.push(column);
}
var gridOptions = {...};
var grid = $element.kendoGrid(gridOptions).data("kendoGrid");;
$scope.$parent[$attrs[directive.name]] = grid;
}
};
return directive;
}]);

I've put an example directive here: http://embed.plnkr.co/fQhNUGHJ3iAYiWTGI9mn/preview
It activates on the my-grid attribute and inserts a checkbox column. The checkbox is bound to the selected property of each item (note that it's an Angular template and it uses dataItem to refer to the current item). To figure out the selected items you can do something like:
var selection = $scope.grid.dataSource.data().filter(function(item){
return item.selected;
});
The checkbox that is added in the header will toggle the selection.
HTH.

#rGiosa is right
I've tried to do that :
var options = angular.extend({}, $scope.$eval($attrs.kOptions));
options['resizable']= true;
Seems to add the attribute in options object but the grid is still not resizable why?
http://plnkr.co/edit/Lc9vGKPfD8EkDem1IP9V?p=preview
EDIT:
Apparently,Options of the Grid cannot be changed dynamically. You need to re-create the whole Grid with different options in order to disable/enable them dynamically?!
Cheers

Related

Lazy loading on scrolling drop down options in angularjs

I am working on MEAN stack application in which I am defining a drop down using following customize directive. This drop down shows available variables from an array(around 70K options).
.directive('inputDropdown', function($parse) {
var template =
'<input class="form-control" ng-model="ngModel" ng-disabled="disabled" ng-focus="setDirectiveList()" ng-blur="removeDirectiveList()">' +
'<div class="dropdown dropdown1" input-dropdown="increaseLimit()" ng-init="limit=20;" ng-click="setDirectiveList()">' +
'<div class="form-control" ng-repeat="value in selectedList | filter:ngModel | limitTo:limit">' +
'<div ng-mousedown="select($event, value)">{{value}}</div>' +
'</div>' +
'</div>';
return {
restrict: 'EA',
require: '^form',
scope: {
ngModel: '=',
list: '=',
onSelect: '&',
disabled:'=ngDisabled'
},
template: template,
link: function(scope, element, attrs,mapController) {
element.addClass('input-dropdown');
var handler = $parse(attrs.inputDropdown);
element.scroll(function (evt) {
var scrollTop = element[0].scrollTop,
scrollHeight = element[0].scrollHeight,
offsetHeight = element[0].offsetHeight;
if (scrollTop === (scrollHeight - offsetHeight)) {
$scope.$apply(function () {
handler($scope);
});
}
});
if(scope.$parent.setDirty)
{
scope.makeFormDirty = mapController.$setDirty();
}
scope.select = function(e, value) {
scope.ngModel = value;
// scope.onSelect({$event: e, value: value});
scope.makeFormDirty = mapController.$setDirty();
};
scope.setDirectiveList = function() {
// debugger;
scope.selectedList = scope.list;//scope.$parent.variables;
}
scope.removeDirectiveList = function() {
scope.selectedList = [];
}
}
};
})
What I am trying to do is using limitTo option, increasing the the display variables count by some value when the scroll bar of drop down hits bottom. The increaseLimit function is defined in my controller as:
$scope.increaseLimit = function () {
if ($scope.limit < $scope.variables.length) {
$scope.limit += 20;
}
};
where $scope.variables contains 70K entries. I am not sure whether the I am adding increaseLimit to correct div or scrolling function is wrong.
I want to achieve this type of loading in my drop down. How to add this in my customize directive input-dropdown. I tried but no success.
Please Help.

ng-bind-html not working

I'm trying to insert HTML into my div (bottom of code). I've dealt with an issue like this before so I added a filter. However, when the div is made visible through a toggle function the HTML doesn't display from the service. I have verified that the service is returning the proper HTML code.
The div is unhidden but no html is displayed.
Angular Code:
var myApp = angular.module('myApp', []);
angular.module('myApp').filter('unsafe', function ($sce) {
return function (val) {
if ((typeof val == 'string' || val instanceof String)) {
return $sce.trustAsHtml(val);
}
};
});
myApp.controller('myAppController', function ($scope, $http) {
...
SERVICE CODE
...
$scope.toggleHTMLResults();
$scope.HTMLjson = obj[0].HTML;
HTML Code:
<div id="returnedHTML" ng-bind-html="HTMLjson | unsafe " ng-hide="HTMLResults">NOT HIDDEN</div>
I'm not sure why this isn't working.
Here is my Plunker
There were multiple things wrong with your example.
Main Javascript file declared twice, first in header and second before close on body tag
You call a function as HTMLAPI() instead of $scope.HTMLAPI()
Your $scope.HTMLAPI() function was also being called before it was initialised
Fixed controller code:
app.controller('myAppCTRL', ['$scope', '$http', function ($scope, $http) {
var API = this;
$scope.HTMLInput = true;
$scope.HTMLResults = true;
$scope.toggleHTMLInput = function () {
$scope.HTMLInput = $scope.HTMLInput === false ? true : false;
}
$scope.toggleHTMLResults = function () {
$scope.HTMLResults = $scope.HTMLResults === false ? true : false;
}
$scope.HTMLAPI = function (HTML) {
var newJSON = ["[{\"ConditionId\":1111,\"ConditionDescription\":\"<i>DATA GOES HERE</i>\",\"ErrorId\":0,\"DisplayId\":0,\"DisplayName\":\"\",\"ErrorValue\":\"\"}]"];
var obj = JSON.parse(newJSON);
$scope.HTMLjson = obj[0].ConditionDescription;
$scope.toggleHTMLResults();
console.log($scope.HTMLjson);
}
$scope.HTMLAPI();
}]);
Working Example

Dynamically Add/Remove Attribute Directive based on state

I would like to build a directive that adds and remove a second directive based on a boolean flag.
So, when boolFlag = true, the div in example.html should recompile to include my-dir as an attribute. And it should have additional attributes required by my-dir in the form of "test=1".
Here is the basics of what I have so far:
example.html ----
<div add-remove when={{boolFlag}} dir-name="my-dir" dir-attrs="test, 1"></div>
add-remove-directive.js ----
function($compile, $timeout) {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
var attrArray = attrs.dirAttrs.split(',');
for (a in attrArray) {
attrArray[a] = attrArray[a].trim();
}
attrs.$observe('when', function() {
// flagged when the directive should be attached to the element
var isWhen = attrs.when === 'true';
if (isWhen) {
for (a = 0; a < attrArray.length; a+=2) {
elem.attr(attrArray[a], attrArray[a+1]);
}
newScope = scope.$new();
cElem = $compile(elem)(newScope);
elem.replaceWith(cElem);
$timeout(function() {
scope.$destroy();
});
}
// if the flag is not set, remove the dynamic directive from the element
// but only if the element already has the given directive
else {
normDirName = attrs.$normalize(attrs.dirName);
console.log(normDirName);
console.log(r, 'elsed', attrs);
if (!attrs.hasOwnProperty(normDirName)) return;
elem.removeAttr(scope.dirName);
for (a = 0; a < attrArray.length; a+=2) {
elem.removeAttr(attrArray[a]);
}
newScope = scope.$new();
cElem = $compile(elem)(newScope);
elem.replaceWith(cElem);
$timeout(function() {
scope.$destroy();
});
}
}
}
---EDIT---
Sorry, that was an error with me copying it over from my project. It is functional up to how I described in the original post.
Basically where it's at now is I can dynamically "my-dir" directive correctly with the corresponding required attributes "test=1".
But the problems I'm running into are:
that there are two scopes active the original one without "my-dir" and another scope WITH "my-dir".
my else statement doesn't properly remove "my-dir" from the div when boolFlag is set to false.

angularjs textarea - how to keep it in sync with angularjs dropdowns selected values

I have a couple of drop downs and based on selection I updated the textarea content, but when I am trying to update the text the function, I presume gets triggered, and does not let me update.
Here is my html :
<textarea ng-model="desc" ng-change="des"></textarea>
and angular
somehow the code got deleted.. please visit plunker: http://plnkr.co/edit/pVSiNrnAOY0A5v0iTmYQ?p=preview
It is better to use watch functions, especially if values might change in the controller, as this ensures that they stay in sync. This solution also seems easier to see what is going on:
plunkr solution
Just using a watch function to watch the selected values:
$scope.$watch('selectedId', function(newValue){
$scope.d();
});
I am not sure if you want the user to be able to change the value in the textarea or not. If you don't, like in your example, then I suggest that you add the attribute ng-disabled="true" to your text area.
you also need
$scope.des = function() {
return $scope.d()
}
Not sure what your trying todo, but if have just plunked this
// Code goes here
app = angular.module('myapp',[]);
app.controller('main', function($scope) {
$scope.desc = "";
$scope.stat = "test";
$scope.d = function() {
for (var i = 0, len = $scope.stat.length; i < len; i++) {
if ($scope.stat[i].Id == $scope.selectedId && $scope.statDate == $scope.stat[i].StatDate) {
$scope.desc = $scope.stat[i].D;
return $scope.stat[i].D;
}
}
return "";
};
$scope.des = function() {
return $scope.d()
}
});
And I get your issue, if I comment out
// $scope.desc = $scope.stat[i].D;
it works, but I presume that bit you need :)
What are you trying todo? I think you are trying to change model as the view is changed. You might need a directive for this.
This is part of something I did for datetime stuff
.directive('formatteddate', function ($filter) {
return {
link: function (scope, element, attrs, ctrl) {
ctrl.$parsers.unshift(function (viewValue) {
This is the plunk of your code/html.
http://plnkr.co/edit/3GjP7YVsKFIYAAJQwmOK?p=preview
okay,so what about if you just update the ng-model value of textarea to the value of your select dropdown.
Here's the plunker
http://plnkr.co/edit/mXQTcBu5rOJaQJKEFKpm?p=preview
change the model name to some:
<textarea ng-model="textarea" ng-change="desc()"></textarea>
and then update in, in your script where your code logic is:
$scope.d = function() {
for (var i = 0, len = $scope.stat.length; i < len; i++) {
console.log(i);
if ($scope.stat[i].Id == $scope.selectedId && $scope.statDate == $scope.stat[i].StatDate) {
$scope.desc = $scope.stat[i].D;
**$scope.textarea=$scope.desc;**
return $scope.stat[i].D;
}
}
return "";
};

kendoui angular grid selection event

I am trying to handle a selection event from a KendoUI Grid in AngularJS.
I have got my code working as per below. However it feels like a really nasty way of having to get the data for the selected row. Especially using _data. Is there a better way of doing this? Have I got the wrong approach?
<div kendo-grid k-data-source="recipes" k-selectable="true" k-sortable="true" k-pageable="{'refresh': true, 'pageSizes': true}"
k-columns='[{field: "name", title: "Name", filterable: false, sortable: true},
{field: "style", title: "Style", filterable: true, sortable: true}]' k-on-change="onSelection(kendoEvent)">
</div>
$scope.onSelection = function(e) {
console.log(e.sender._data[0].id);
}
please try the following:
$scope.onSelection = function(kendoEvent) {
var grid = kendoEvent.sender;
var selectedData = grid.dataItem(grid.select());
console.log(selectedData.id);
}
Joining the party rather late, there is a direct way to do it without reaching for the grid object:
on the markup:
k-on-change="onSelection(data)"
in the code:
$scope.onSelection = function(data) {
// no need to reach the for the sender
}
note that you may still send selected, dataItem, kendoEvent or columns if needed.
consult this link for more details.
Directive for two-way binding to selected row. Should be put on the same element
as kendo-grid directive.
Typescript version:
interface KendoGridSelectedRowsScope extends ng.IScope {
row: any[];
}
// Directive is registered as gridSelectedRow
export function kendoGridSelectedRowsDirective(): ng.IDirective {
return {
link($scope: KendoGridSelectedRowsScope, element: ng.IAugmentedJQuery) {
var unregister = $scope.$parent.$on("kendoWidgetCreated", (event, grid) => {
if (unregister)
unregister();
// Set selected rows on selection
grid.bind("change", function (e) {
var selectedRows = this.select();
var selectedDataItems = [];
for (var i = 0; i < selectedRows.length; i++) {
var dataItem = this.dataItem(selectedRows[i]);
selectedDataItems.push(dataItem);
}
if ($scope.row != selectedDataItems[0]) {
$scope.row = selectedDataItems[0];
$scope.$root.$$phase || $scope.$root.$digest();
}
});
// Reset selection on page change
grid.bind("dataBound", () => {
$scope.row = null;
$scope.$root.$$phase || $scope.$root.$digest();
});
$scope.$watch(
() => $scope.row,
(newValue, oldValue) => {
if (newValue !== undefined && newValue != oldValue) {
if (newValue == null)
grid.clearSelection();
else {
var index = grid.dataSource.indexOf(newValue);
if (index >= 0)
grid.select(grid.element.find("tr:eq(" + (index + 1) + ")"));
else
grid.clearSelection();
}
}
});
});
},
scope: {
row: "=gridSelectedRow"
}
};
}
Javascript version
function kendoGridSelectedRowsDirective() {
return {
link: function ($scope, element) {
var unregister = $scope.$parent.$on("kendoWidgetCreated", function (event, grid) {
if (unregister)
unregister();
// Set selected rows on selection
grid.bind("change", function (e) {
var selectedRows = this.select();
var selectedDataItems = [];
for (var i = 0; i < selectedRows.length; i++) {
var dataItem = this.dataItem(selectedRows[i]);
selectedDataItems.push(dataItem);
}
if ($scope.row != selectedDataItems[0]) {
$scope.row = selectedDataItems[0];
$scope.$root.$$phase || $scope.$root.$digest();
}
});
// Reset selection on page change
grid.bind("dataBound", function () {
$scope.row = null;
$scope.$root.$$phase || $scope.$root.$digest();
});
$scope.$watch(function () { return $scope.row; }, function (newValue, oldValue) {
if (newValue !== undefined && newValue != oldValue) {
if (newValue == null)
grid.clearSelection();
else {
var index = grid.dataSource.indexOf(newValue);
if (index >= 0)
grid.select(grid.element.find("tr:eq(" + (index + 1) + ")"));
else
grid.clearSelection();
}
}
});
});
},
scope: {
row: "=gridSelectedRow"
}
};
}
A quick example of how to do this with an angular directive.
Note here that I'm getting the reference to the underlying kendo grid through the click event and the DOM handle.
//this is a custom directive to bind a kendo grid's row selection to a model
var lgSelectedRow = MainController.directive('lgSelectedRow', function () {
return {
scope: {
//optional isolate scope aka one way binding
rowData: "=?"
},
link: function (scope, element, attributes) {
//binds the click event and the row data of the selected grid to our isolate scope
element.bind("click", function(e) {
scope.$apply(function () {
//get the grid from the click handler in the DOM
var grid = $(e.target).closest("div").parent().data("kendoGrid");
var selectedData = grid.dataItem(grid.select());
scope.rowData = selectedData;
});
});
}
};
});
I would suggest to use like this, I was also getting undefined when I upgraded my application from angular 7 to 15. Now I get event details like this
public selectedRowChangeAction(event:any): void {
console.log(event.selectedRows[0].dataItem.Id); }
event has selected Row at its 0 index and you can have dataItem as first object and then you can have all object details whatever you have for example Id, Name,Product details whatever you want to select, Something like you can see in picture

Categories

Resources