I was wondering how to call a controller function from a keymaps in extjs 5?
The following code in the view is working to bind the keys to a an anonymous function, however not to a controller function. The function is also called by the button, and is working. How do I set the scope correctly that it is calling the controller function?
Ext.define("MyApp.view.users.List",{
extend: 'Ext.grid.Panel',
alias: 'widget.usersList',
controller: 'users-list',
listeners: {
scope: 'controller',
afterrender: function(window, options) {
this.keyNav = new Ext.util.KeyMap ({
target:window.el,
binding: [
{key:"s", ctrl:true, fn: function(){alert("hallo shortkey");}},
{key:"c", ctrl:true, fn: "newUserFn"},
],
scope:'controller'
});
}
},
tbar: [
{
itemId: 'users-list-btn-new',
iconCls: 'icon-add',
text: 'New User',
handler: 'newUserFn'
}
]
});
I had similar troubles with scope on key press events. I'm not using a KeyMap as you are but the event logic is still relevant.
The following assumes a controller with method "saveNewComponent" that you want to call. You must fire the view event "callSave" which is being listened to in the view to correctly forward to the controller.
Ext.define('teams.view.component.FormPanel', {
extend: 'Ext.form.Panel',
controller: "FormPanelController",
listeners: {
callSave: "saveNewComponent"
},
beforeShow: function(){
var me = this;
me.body.dom.addEventListener("keydown", Ext.bind(onKeyDown, this), false);
function onKeyDown(e) {
//Listen for Ctrl+S
if (e.ctrlKey && e.which === 83){
e.preventDefault();
me.fireEvent("callSave");
return false;
}
}
},
....
}
I tried many ways of achieving this, this this solution was the only one that had the correct context when actually inside the controller (ie this var was correct)
Related
A component definition:
Ext.define('Retroplanner.view.dimension.DimensionMapping', {
alias: 'widget.dimensionMapping',
extend: 'Ext.form.Panel',
...
items: [{
xtype: 'combo'
}, ...
]
A 'select' handler of the child item must create a widget and add this widget to the items array of its parent.
Inside of this child item, it its 'select' handler, I can find its parent by some search techniques. But I would like to avoid it if it is possible. I do not have a reference variable to the parent neither.
A better approach would be - to create function in the parent, and attach it somehow to the child item:
Ext.define('Retroplanner.view.dimension.DimensionMapping', {
...
onSiRemoteCombo: function(cmb, rec, idx) {
alert("select handler");
var newItem = Ext.widget('somexType');
this.items.add(newItem);
}
The question, how to attach onSiRemoteCombo?
I've found a similar solution here: How to create listener for child component's custom event
First, it does not work for me. I can give a full example that I tried to use.
2nd, I would like to create items via the most common way/in the common place, not via initComponent method. I would like to have something like:
Ext.define('Retroplanner.view.dimension.DimensionMapping', {
...
afterRender: function() {
var me = this;
//exception here
//Uncaught TypeError: Cannot read property 'on' of undefined
me.items[0].on('select', onSiRemoteCombo, this);
},
items: [{
xtype: 'combo'
}, ...
],
onSiRemoteCombo: function(cmb, rec, idx) {
alert("Ttt");
var dimensionMapping = Ext.widget('propGrid');
this.getParent().add(dimensionMapping);
}
But I get an exception:
//exception here
//Uncaught TypeError: Cannot read property 'on' of undefined
me.items[0].on('select', onSiRemoteCombo, this);
And also, attach a listener after each rendering, really is a bad idea.
Are there any best practices for such use cases? Ideally, if it will work in different versions of Ext JS, at least in 5.x and 6.x
Attach a handler in a child and access its parent? A child should not depend on its parent. Only parent should know, what to do.
One way to solve this is by wrapping the combo item component initialization into form's initComponent method. This way when setting a listener for the combo, you can use this.formMethod to reference a form method. Here is some code:
Ext.define('Fiddle.view.FirstForm', {
extend: 'Ext.form.Panel',
bodyPadding: 15,
initComponent: function () {
Ext.apply(this, {
items: [{
xtype: 'combo',
fieldLabel: 'First Combo',
store: ['first', 'second'],
listeners: {
'select': this.onComboSelect
}
}]
});
this.callParent();
},
onComboSelect: function () {
alert('I am a first form method');
}
});
The second approach by using a string listener on the combo, and by setting defaultListenerScope to true on the form. This way the listener function will be resolved to the form's method. Again, some code:
Ext.define('Fiddle.view.SecondForm', {
extend: 'Ext.form.Panel',
bodyPadding: 15,
defaultListenerScope: true,
items: [{
xtype: 'combo',
fieldLabel: 'Second Combo',
store: ['first', 'second'],
listeners: {
'select': 'onComboSelect'
}
}],
onComboSelect: function () {
alert('I am a second form method');
}
});
And here is a working fiddle with both approaches: https://fiddle.sencha.com/#view/editor&fiddle/27un
If you have two widget in a view. And you do something with the first widget and you want to update (call display_field) the second widget. How to have the identifier for the second widget?
For example in the extend definition of a widget:
local.FieldNewWidget = instance.web.form.AbstractField.extend({
init: function(parent, options) {
},
events: {
'click .oe_new_input_button': 'open_new_specific_form',
},
start: function() {
},
display_field: function() {
},
render_value: function() {
},
open_new_specific_form: function(event) {
var self = this;
var new_action = {
type: 'ir.actions.act_window',
name: $(event.target).data('name'),
res_model: $(event.target).data('data-model'),
res_id: $(event.target).data('res-id'),
view_mode: 'form',
view_type: 'form',
views: [[false, 'form']],
target: 'new',
context: {
},
flags: {'form': {'action_buttons': true}},
}
self.do_action(new_action, {
on_close: function() {
// I want to refresh (call display_field) the second widget here.
// What is the identifier for the second widget?
},
});
},
});
i think this will work but i don't know if it's the best solution. I think every widget knows witch view it's by using (this.view). why don't you use a special event to trigger it from one widget and listen for it in the other one.
For example Register an event listener on the widget to listen for property changing on the view:
//in first widget register the event listener:
this.view.on('property_name', this, this.your_method);
// in second widget trigger the event by setting the value
this.view.set('property_name', a_value);
i'm new to odoo javascript let me know if this works for you i think there is a better solution by using events triggering without changing properties at all.
I defined a Ext.grid.Panel called JobList that has an Ext button with an itemId called myButton. JobList has a controller. In the controller I have the following code:
Ext.define('App.controller.JobList', {
extend: 'Ext.app.Controller',
refs: [
{ref: 'jobList', selector: '#jobList'},
{ref: 'myButton', selector: '#myButton'}
],
init: function(){
this.control({
'jobList': {
select: this.selectJob
}
});
},
selectJob: function(){
this.getMyButton().enable();
}
});
I then create two instances of jobList using Ext.create they have an id of jobList1 and jobList2. The problem is when I select a job in the list on jobList2 it will enable the myButton on jobList1 not jobList2. How do I correctly enable the myButton on each instance of jobList?
Try to avoid referencing by itemId, and use aliases instead:
// in App.view.JobList.js you should have
Ext.define('App.view.JobList', {
extend: 'Ext.grid.Panel',
alias: 'widget.job-list',
// ...
dockedItems: [{
xtype: 'button',
name: 'myButton',
text: 'My button',
}]
});
// and the in the App.controller.JobList.js:
// ...
'job-list': {
selectionchange: function(model, selected) {
var button = model.view.up('job-list').down('button[name=myButton]');
button.setDisabled(Ext.isEmpty(selected));
}
}
Check the example: https://fiddle.sencha.com/#fiddle/tq1
You're using global controller, so it catches events from all views that matching the query. Look at MVVM pattern in extjs5. Sencha did a great job, in MVVM each instance of view has their own instance of ViewController, so this situation will never happen. If you want to stick with MVC pattern, then you need to manually control this. Forget about refs, you can't use them if you have more than one instance of your view class. Get other components only by query from your current component. Something like:
Ext.define('App.controller.JobList', {
extend: 'Ext.app.Controller',
init: function() {
this.control({
'jobList': {
select: this.selectJob
}
});
},
selectJob: function(selectionModel){
//first of all you need to get a grid. We have only selectionModel in this event that linked somehow with our grid
var grid = selectionModel.view.ownerCt; //or if you find more ellegant way to get a grid from selectionModel, use it
var button = grid.down('#myButton');
button.enable();
}
});
I'm using EXTJS with Node.JS and am having difficulty with handling events in the context of the EXTJS MVC framework.
I've been able to easily register click events when defining the Event Listener in the Class Definition of the view, but can't seem to move this code into the controller.
Here's a look at my current code:
//Icon.JS (VIEW)
Ext.define('GeekFlicks.view.Icon', {
extend: 'Ext.button.Button',
alias: 'widget.icon',
height: 48,
width: 48,
text: 'icon',
draggable: true
});
//Icon.JS (CONTROLLER)
Ext.define('GeekFlicks.controller.Icon', {
extend: 'Ext.app.Controller',
models: ['Icon'],
stores: ['Icons'],
views: ['Icon'],
init: function () {
this.control({
'listener': {
click: function(c) {
alert('working');
}
}
});
},
});
Any help or explanations around how EXTJS deals with these sort of events is will be extremely helpful and much appreciated! Thanks.
Change this.control to be something like this:
'icon': {
click: function(c) {
alert('working');
}
}
You basically need to let controller know which element is going to control. I also suggest reading about using refs: [] in the controllers to easier access visual elements and views.
I am extending GridPanel with Ext.define() (Ext v4).
I need to get the row data when a grid row is double clicked. At this point I cannot even get the event listener working:
Ext.define('Application.usersGrid', {
extend: 'Ext.grid.GridPanel',
alias: 'widget.usersgrid',
viewConfig: {
listeners: {
dblclick: function(dataview, index, item, e) {
alert('dblclick');
}
}
},
...
What is wrong here?
If anyone needs the answer- this is the right way:
Ext.define('Application.usersGrid', {
extend: 'Ext.grid.Panel',
alias: 'widget.usersgrid',
viewConfig: {
listeners: {
itemdblclick: function(dataview, record, item, index, e) {
alert('itemdblclick');
}
}
},
...
http://dev.sencha.com/new/ext-js/4-0/api/Ext.grid.GridView#event-itemdblclick
You don't need to put the listener in the viewconfig. Here is my working configuration:
listeners : {
itemdblclick: function(dv, record, item, index, e) {
alert('working');
}
},
Another thing is, you seems to have used Ext.grid.GridPanel in the extend property. But in documentation it's Ext.grid.Panel. But even with gridpanel, everything seems to work fine.
I would suggest to use the Ext JS 4 terms as it might cause to application breakage later in other 4.x versions.
Now, if you are using the new MVC architecture, you will want to move these actions to the controller rather than the view. You can refer to the MVC Architecture guide for details.
With the MVC approach in ExtJS 4 there's another smart way too to define such handlers. Some example code:
Ext.define('App.controller.Documents', {
extend: 'Ext.app.Controller',
stores: ['Documents'],
models: ['Document'],
views: [
'document.List',
'document.Edit',
'document.Preview'
],
init: function() {
this.control({
/*
* a cool way to select stuff in ExtJS 4
*/
'documentlist': {
itemdblclick: this.editDocument
},
/*
* simple access to components
*/
'documentedit button[action=save]': {
click: this.updateDocument
},
});
},
editDocument: function(grid, record) {
var view = Ext.widget('documentedit');
view.down('form').loadRecord(record);
},
updateDocument: function(button) {
var win = button.up('window'), // new selection API
form = win.down('form'), // in ExtJS 4
record = form.getRecord(),
values = form.getValues();
record.set(values);
win.close();
}
});
listeners: {
select: 'xxxx',
itemdblclick: function (dv, record, item, index, e) {
var myBtn = Ext.getCmp('btnEdit');
myBtn.onClick();
}
},