I have a question regarding ExtJS controllers. My code:
Ext.define('app.controller.Clients.Clients', {
extend: 'Ext.app.Controller',
stores: ['Clients.Clients'],
models: ['Clients.Clients'],
views: ['Clients.Clients'],
init: function() {
this.control({
'gridClients button[action=deleteClient]': {
click: this.onButtonClickDelete
},
'gridClients button[action=refreshClients]': {
click: this.onButtonClickRefresh
},
'gridClients button[action=printClients]': {
click: this.onButtonClickPrint
}
})
},
onButtonClickDelete: function(button, e, options) {
alert('DELETE?');
},
onButtonClickRefresh: function(button, e, options) {
alert('REFRESH?');
},
onButtonClickPrint: function(button, e, options) {
alert('PRINT?');
}
});
I'm going to refer to a grid named 'gridClients', and I'd like to know if there is any way to create a variable inside the driver file...
I'm going to refer to a grid named 'gridClients', and I would like to know if there is any way to create a variable inside the driver file, to refer to that grid.
Example, I would like something similar to:
Var Grid = Ext.ComponentQuery.query (#gridClients) [0];
And use it like this:
OnButtonClickRefresh: function (button, e, options) {
Grid.getStore (). Load ();
}
I really do not know where to declare that var...
In a controller, you are expected to work with the refs. Example:
Ext.define('app.controller.Clients.Clients', {
extend: 'Ext.app.Controller',
stores: ['Clients.Clients'],
models: ['Clients.Clients'],
views: ['Clients.Clients'],
init: function() {
...
},
refs:[{
ref:'clientsGridExample',
selector: '#gridClients'
}],
OnButtonClickRefresh: function (button, e, options) {
this // inside a controller, these functions are scoped to controller
.getClientsGridExample() // refs are automatically converted to getter methods
.getStore().load(); // Do whatever you want to do
}
});
It's pretty clear, if you check the Ext.app.Controller documentation.
You can set refs in your controller and use generated getter to get the grid you need. For example, if you have ref with value clientsGrid, getter getClientsGrid() will be created by ExtJS.
`
Ext.define('app.controller.Clients.Clients', {
extend: 'Ext.app.Controller',
stores: ['Clients.Clients'],
models: ['Clients.Clients'],
views: ['Clients.Clients'],
refs: [
{ ref: 'grid', selector: '#gridClients' }
],
init: function() {
this.control({
'gridClients button[action=deleteClient]': {
click: this.onButtonClickDelete
},
'gridClients button[action=refreshClients]': {
click: this.onButtonClickRefresh
},
'gridClients button[action=printClients]': {
click: this.onButtonClickPrint
}
})
},
onButtonClickDelete: function(button, e, options) {
this.getGrid().doSomething();
},
onButtonClickRefresh: function(button, e, options) {
alert('REFRESH?');
},
onButtonClickPrint: function(button, e, options) {
alert('PRINT?');
}
});
`
Inside the OnButtonClickRefresh listener you can get the grid like this:
var grid = button.up("grid");
Link to the fiddle
Related
I have created a component that needs to have a reference to the object for which the component was created. I didn't make to work and all my trials have failed. Below, I try to describe the intention.
The component definition would maybe look like this:
angular
.module('myModule')
.component('myComponent', {
templateUrl: "template.html",
controller: [
MyController
],
bindings: {
myObject: '='
}
});
function MyController(myObject) {
var vm = this;
vm.myObject = myObject;
}
In a service I would like to create my object like this:
function createMyObject(args) {
var myObject = {some: data};
myObject.ref = "<my-component myObject='{{myObject}}'></my-component>";
return myObject;
}
Question
How can I pass data to angular component tag? Do I have to switch back to a component directive to make it work?
Any ideas are greatly appreciated. Thank you.
Solution 1
In your template:
<my-component key='$ctrl.myObject'></my-component>
In code:
angular
.module('myModule')
.component('myComponent', {
templateUrl: "template.html",
controller: [
'objectService'
MyController
],
bindings: {
key: '=' // or key: '<' it depends on what binding you need
}
});
function MyController(myObject, objectService) {
var vm = this;
vm.myObject.whatever(); // myObject is assigned to 'this' automatically
}
Solution 2 - via Component Bindings
Component:
angular
.module('myModule')
.component('myComponent', {
templateUrl: "template.html",
controller: [
'objectService'
MyController
],
bindings: {
key: '#'
}
});
function MyController(myObject, objectService) {
var vm = this;
vm.myObject = objectService.find(vm.key);
}
Usage:
function createMyObject(args) {
var myObject = {key: ..., some: data};
myObject.ref = "<my-component key='" + myObject.key + "'></my-component>";
return myObject;
}
(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.
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)"
everyone ! I've this on my directive template...
<div class="priceSlider" ui-slider="slider.options" min="{{min}}" max="{{max}}"
step="0.01" use-decimals ng-model="sliderVal"><div>{{currency}} {{sliderVal[0]}} -
{{currency}} {{sliderVal[1]}}</div>
..and I've this on my JS for the directive
angular
.module('app.directives.categoryHead', [])
.directive('categoryHead', function() {
return {
restrict : 'E',
controller: function($scope){
$scope.sliderVal = [$scope.min , $scope.max];
$scope.slider = {
'options': {
range: true,
start: function (event, ui) { console.log('Event: Slider start - set with slider options', event); },
stop: function (event, ui) { console.log('Event: Slider stop - set with slider options', event); }
}
}
},
scope: {
language : "=",
currency : "=",
breadcrumb : "=",
min : "=",
max : "="
},
templateUrl: "templates/directives/categoryHead.html"
}
});
...and on my route template, I've this...
<category-head breadcrumb="breadCrumb" min="categoryList.minPrice"
max="categoryList.maxPrice" language="webshop.language"
currency="webshop.culture.currency"></category-head>
So, basically I've a slider...that's fires the events starts and stop - And this works really fine.
But I'd like to handle the event not inside the directive, but on the controller of the route template.
How can I "transfer" the event from the directive to the template controller ? I just need to fire a "something changed" and send a notification of the new values.
ty !
There are probably lots of different ways to do this. One option is to make your directive take event handlers that you have defined in your controller, like this:
<your-directive on-start="startHandler()" on-stop="stopHandler()></your-directive>
Then, in your directive config:
scope: {
onStart: '&',
onStop: '&'
}
Then, add something like this to your start/stop methods within the directive.
$scope.slider = {
'options': {
range: true,
start: function (event, ui) { if (onStart) onStart(event); /* other stuff */ },
stop: function (event, ui) { if (onStop) onStop(event); /* other stuff */ }
}
}
The controller that controls an event using the recommended this.control: construct :
Ext.define('Mb.controller.Sav_vpc', {
extend: 'Ext.app.Controller',
init: function() {
console.log('controller.init called');
this.control({
'#storeMenu menuitem': {
click: this.onStoreMenuClicked
}
});
}
});
The function onStoreMenuClicked gets called twice, because the init method of the controller gets called twice, therefore it listens twice to the event.
But when is the controller.init() called ? And why is it called twice ?
Here is my application.launch function:
Ext.define('Mb.Application', {
extend: 'Ext.app.Application',
launch: function() {
console.log('launching app');
var controller = Mb.app.getController('Name');
console.log('end launching app');
});
...
This will give this output in the console:
controller.init called
launching app
controller.init called
end launching app
When calling getController inside application.launch, the init method of the controller gets called again, even the controller was already initialized.
I don't know if this is by design or if it is kind a bug, but I found a solution based on the recommendations of #AlexTokarev 'Inter-controller communication'.
Controller:
Ext.define('Mb.controller.Sav', {
extend: 'Ext.app.Controller',
init: function(){
this.listen({
controller: {
'*': {
savOnLaunch: this.onUserLoaded
}
}
})
},
Application launch:
Ext.define('Mb.Application', {
extend: 'Ext.app.Application',
launch: function() {
this.fireEvent('savOnLaunch');
}