angular with kendo grid in templateUrl - angularjs

(sorry if this is duplicate, but what i've found does not answer my question:
Databinding is not working with kendo grid in angular JS directives
)
I am trying to create a directive with a templateUrl containing a kendo grid, and use this directive in a controller.
I can manage to bind some of the directive's attributes (e.g. my-grid-options, which is initialized in the controller) but not my-grid-id.
What am I missing? (full plunk here)
the directive:
Directives.myGrid = function() {
return {
scope: {
myGridId: "=",
myGridOptions: "="
},
restrict: "E",
transclude: true,
templateUrl: 'myGrid.html',
link: function(scope) {
//... some code using the myGridId
scope.myGridId.....
}
}
}
myGrid.html:
<div kendo-grid="myGridId" k-options="myGridOptions" id="myGridId">
</div>
how I want to use it:
<body ng-app='app' ng-controller='myCtrl'>
<my-grid my-grid-id="mainGrid" my-grid-options="mainGridOptions"></my-grid>
</body>
controller:
angular.module('app').controller('myCtrl',function($scope){
$scope.ds = [
{Category:"Toys", Name: "Doll", Code: "p1", Special: false},
....
{Category:"Stationary", Name: "Crayons", Code: "p4", Special: false}
];
$scope.mainGridOptions = {
columns: [
{
field: "Category",
title: "Category"
},
{
field: "Name",
title: "Name"
},
{
field: "Code",
title: "Code"
},
{
field: "Special",
title: "Special Offer"
},
],
dataSource: $scope.ds,
sortable: true,
selectable: true,
resizable: true,
pageable: true,
reorderable: true,
columnReorder: function (e) {
//do something trivial... for example sake, but a more complex event is used
$.each($scope.mainGrid.wrapper.find('tbody tr'), function () {
var model = $scope.mainGrid.dataItem(this);
if (model.Special === true) {
$(this).addClass('special-row');
}
});
}
};
});
Thanks for any advice.

Ok, so i got to see your plunk. I did a few changes and here is the result.
You still got some problems in there. Check my changes in your directive:
angular.module('app').directive('myGrid', function(){
return {
scope: {
gridId: "=",
gridOptions: "="
},
restrict: "E",
replace: true,
templateUrl: 'myGrid.html',
link: function(scope) {
console.log(gridId);
console.log(scope.gridId);
// var doMore = function() {
// $.each(scope.gridId.wrapper.find('tbody tr'), function () {
// var model = $scope.gridId.dataItem(this);
// if (model.Category === "Stationary") {
// $(this).addClass('stationary-row');
// }
// });
// };
// var extendReorder = function(baseReorder) {
// doMore();
// if (baseReorder)
// baseReorder();
// };
scope.gridOptions.columnReorder = extendReorder(scope.gridOptions.columnReorder);
}
};
});
I removed the tranclude:"true", as it caused a directive collision. Then there were errors about you gridId being "undefined". I don't know what its purpose is, so i just gave it a value in the controller (check the plunk). If it is not completely what you want yet, let me know, i look further into it.

Thanks to #ocket-san for taking the time to look at this.
Eventually I got what I wanted: to extend the kendo-grid inside a directive without affecting any controller implementations which use the kendo-grid.
I managed to do this by creatting a directive of Attribute type which extends the current definition (usage) of the kendo-grid, so wherever I wish to add my extensions I can simply add my directive as an attribute:
<div kendo-grid="mainGrid" k-options="mainGridOptions" id="mainGrid" my-grid >
Instead of:
<div kendo-grid="mainGrid" k-options="mainGridOptions" id="mainGrid">
(fyi: I wanted to set pagination buttons to both top and bottom for all the kendo-grids in my application, without having to duplicate the extension all over the place)
See plunker here.

Related

how to pass callback funtion to Angular JS dirctive

I am trying to create a footer directive that I can pass an array of button objects to.
here is my array...
$scope.buttons = [
{
btnLabel: "Close",
btnClass: "btn-p2 pull-left",
show: true,
disabled: false,
callback: function(){console.log('close...');},
role: ''
},
{
btnLabel: "Save",
btnClass: "btn-p1 pull-right",
show: true,
disabled: true,
callback: saveTest,
role: ''
}
];
I have most of it working the way I want but, having issue with passing the callback functions. I am seeing the buttons but when I click the callback functions are not getting called. Any ideas on how to pass the callback functions?
Thanks and regards,
dj
Because saveTest is not defined in your scope, directive doesn't have access to it. So either you have to defined them on the scope and use them there, or you can pass them as directives attributes in its own scope:
First way:
$scope.saveTest = function () {
}
And then you can use the parent scope in your directive:
app.directive('someDirective', function() {
return {
restrict: 'E'
templateUrl: "..."
}
})
By not defining the scope in directive, you are saying I want to use parent scope here.
Second way:
app.directive('someDirective', function() {
return {
restrict: 'EA',
scope: {
saveTest: '&',
close: '&'
},
templateUrl: "..."
}
})
Now that we have defined them in the directive we have to pass them from html like this:
<div some-directive save-test="saveTest" close="close"></div>

How to filter data based on the scope in AngularJS?

I have the following simplified plunker to demonstrate my issue:
html:
<my-directive ng-repeat="question in questions | filter:{show:true}" data-question="question"> </my-directive>
directive:
app.controller('MainCtrl', function($scope) {
$scope.questions = [
{qid:'1', show: true, text:'what is?'},
{qid:'2', show: false, text:'who is?'},
{qid:'3', show: true, text:'where is?'}
];
});
app.directive('myDirective', function() {
return {
link: function(scope){
scope.getShow = function(){
// some logic to determine show
// for simlicity , always return true so all questiosn show
return true;
};
},
restrict: "E",
scope: {
question: "="
},
template: '<h1>{{question.text}}</h1>'
};
});
Currently, the filter works based on the 'show' value that comes from the raw data model. but i am trying to clean it from raw data and make it work based on the getShow() logic that is defined at the question's scope level.
Generally, I cannot figure out a way to filter based on fields or functions on the scope, rather than on the data model, and could not find an example of how this could be done.
Within the ng-repeat just set an ng-show equal to the getShow() function and pass along the iterated question.
Get getShow() to check if show is true or false, and return that value.
app.js:
var app = angular.module('angularjs-starter', []);
app.controller('MainCtrl', function($scope) {
$scope.questions = [
{qid:'1', show: true, text:'what is?'},
{qid:'2', show: false, text:'who is?'},
{qid:'3', show: true, text:'where is?'}
];
});
app.directive('myDirective', function() {
return {
link: function(scope){
scope.getShow = function(question){
// some logic to determine show
// for simlicity , always return true so all questiosn show
return question.show
};
},
restrict: "E",
scope: {
question: "="
},
template: '<h1>{{question.text}}</h1>'
};
});
and index.html
<my-directive ng-repeat="question in questions" ng-show="getShow(question)" data-question="question">
And of course, the editable plunker to show.

AngularJS ES6 ui-grid directive scope, ng-click dont work

I have a chain directive with angularJS and ES6 and want to use ui-grid.
The grid is shown with the correct columns and data, thats fine.
But ng-click donĀ“t work in the cellTemplate. Nothing happens.
Also i try to check the grid object with console.log(grid) and grid is undefined.
Who can i use the cellTemplate to call the openDetail method?
export default function ChainsDirective() {
class ChainsDirective {
/*#ngInject*/
constructor(chainsService, $state) {
this.chainsServiceLoadChains = chainsService.loadChains.bind(chainsService);
this.gridOptions = {
enableColumnMenus: false,
columnDefs: [
{
name: 'id',
visible: false
},
{
name: 'name',
displayName: 'Kette',
cellTemplate: '<div class="ui-grid-cell-contents"><a onclick="console.log(grid)" ng-click="grid.appScope.openDetail(row.entity.id)">{{row.entity.name}}</a></div>'
}
]
};
this.$stateGo = $state.go.bind($state);
this.fetch(); // best practice initiales laden in einer Funktion zu kapseln
}
/**
* #param int chainId
*/
openDetail(chainId) {
this.$stateGo('chainDetail', {chainId})
}
fetch() {
return this.chainsServiceLoadChains().then(data => {
this.gridOptions.data = data;
})
}
}
return {
restrict: 'E',
template: '<div ui-grid="chains.gridOptions" external-scopes="$scope" class="grid"></div>',
scope: {},
bindToController: {},
controller: ChainsDirective,
controllerAs: 'chains'
}
}
I've never used ui-grid directive. But it seems that you need to access your controller by its name, since you have declared it with the "controller as" syntax.
So in your ng-click you need to reference the controller on the scope with its name chains:
ng-click="grid.appScope.chains.openDetail(row.entity.id)"

Using Angular template for Kendo UI Grid detail template

I am using the Kendo UI package for Angular JS. I would like to use an Angular template for the row detail, very similar to what is done here:
Kendo Grid Detail Template
Essentially I would like to fetch some data when details are expanded, and pass an angular model to the template. Is this possible?
What I have done (so far) with this same need is use the changed event on the Grid to populate a 'SelectedRow' object on the $scope in my controller. For the DetailTemplate, I have a div that contains a directive that loads the template either from the $templateCache or using $http and compiles it and links it to the $scope. One of the problems with templates is compiling and linking them to the $scope and the timing of when that takes place. (My problem was even worse as I needed a different detail template for each row)
$scope.vm.options.productGridOptions = {
dataSource: new kendo.data.DataSource({
data: $scope.vm.solution.Products,
pageSize: 10
}),
change: $scope.vm.events.productSelected,
columns: $scope.vm.columns.productColumns,
detailTemplate: '<div data-template-detail type="#= EntityTemplateSK #"></div>',
filterable: false,
groupable: false,
pageable: true,
reorderable: true,
resizable: true,
selectable: 'single',
sortable: true
};
myApp.directive('templateDetail', ['$compile', '$http', '$templateCache',
function ($compile, $http, $templateCache) {
var detailTemplateNumbers = ['21', '22', '23', '26', '45', '69'];
var getTemplate = function (templateNumber) {
var baseUrl = '/App/Product/Views/',
templateName = 'productdetail.html',
templateUrl = baseUrl + templateName;
if (detailTemplateNumbers.filter(function (element) { return element === templateNumber; })[0]) {
templateName = 'productTemplate' + templateNumber + '.html';
templateUrl = baseUrl + templateName;
}
return $http.get(templateUrl, { cache: $templateCache });
};
var linker = function ($scope, element, attrs) {
var loader = getTemplate(attrs.type.toString());
if (loader) {
loader.success(function (html) {
element.html(html);
}).then(function () {
element.replaceWith($compile(element.html())($scope.$parent));
});
}
};
return {
restrict: 'A',
scope: {
type: '='
},
link: linker
};
}]);

Class directive not working when using ng-class to load the directive

I am trying to load a 'class' directive using ng-class. but my directive is never loaded when i do that. The directive is a multipurpose directive, and I don't want to create an isolated scope on this. it will be loaded only when required, based on ng-class conditions hence not using attribute or element directive. has anyone tried doing this and succeeded?
this directive is called using <div ng-class="someClass {{tooltip: enabled}}"></div>
here enabled is a scope variable.
app.directive('tooltip', ['$timeout', '$location', '$rootScope', function (timer, $location, $rootScope) {
return {
restrict: 'C',
transclude: true,
link: function (scope, element) {
var printContent = function () {
/* uses the content of .tooltip-content if it is a complex html tooltip,
otherwise
you can use the title attribute for plaintext tooltips
*/
var tooltipContent = $(element).find('.tooltip-content').html();
if (!tooltipContent) {
tooltipContent = $(element).attr('title');
}
$(element).tooltip({
content: tooltipContent,
items: "img, a, span, button, div",
tooltipClass: "tooltip",
position: { my: "left+30 top", at: "right top", collision: "flipfit" },
show: { effect: "fadeIn", duration: "fast" },
hide: { effect: "fadeOut", duration: "fast" },
open: function (event, ui) { $rootScope.tooltipElement = event.target; }
});
};
timer(printContent, 0);
}
};
}]);
Interesting issue. It seems that you don't want to use the ng-class directive since that doesn't recompile the content after adding the class. You'll likely want to create your own dynamic-class directive that actually recompiles when the value is true:
app.directive('dynamicClass', function($compile) {
return {
scope: {
dynamicClassWhen: '=',
dynamicClass: '='
},
link: function(scope, elt, attrs) {
scope.$watch('dynamicClassWhen', function(val) {
if (val) {
console.log(val);
elt.addClass(scope.dynamicClass);
$compile(elt)(scope);
}
});
}
};
});
You may need to modify this for the ability to remove the class and depending on if the $compile is sufficient for you or if you need to further manipulate the html, but this seems to be the right track for you. I made a fiddle with this in action.
Hope this helps!

Resources