EXTJS, Unable to bind event handler to controller - javascript

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.

Related

Javascript identifier for widget in Odoo

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.

How can I make my controller call the correct view's component in extjs?

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();
}
});

ExtJS5 How to let keymap call viewController function?

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)

ExtJS renderTo element not found

I have an MVC architecture, but when I try to make another TabPanel insite an existing one, I get this in the browser:
el is null
el = el.dom || Ext.getDom(el); ext-all-debug.js (line 12807)
From what I understand, it seems that the new TabPanel can't find the needed div for it to render. Anyway, here is the controller:
Ext.define('FI.controller.MainController', {
extend: 'Ext.app.Controller',
id: 'mainController',
views: ['MainTabPanel', 'UnitsTabPanel', 'SummariesTabPanel'],
mainTabPanel : {},
unitsTabPanel : {},
summariesTabPanel : {},
init: function(){
console.log("main controller is init");
console.log(this);
this.control({
'mainTabPanel':{
afterrender: this.onCreate
}
});
this.mainTabPanel = Ext.widget('mainTabPanel');
},
onCreate: function(){
console.log("main tab panel is created");
console.log(this);
this.unitsTabPanel = Ext.widget('unitsTabPanel');
this.summariesTabPanel = Ext.widget('summariesTabPanel');
}
});
This is the MainTabPanel:
Ext.define("FI.view.MainTabPanel", {
extend: 'Ext.tab.Panel',
renderTo:'container',
alias: 'widget.mainTabPanel',
enableTabScroll: true,
items:[{
title:'Units',
html: "<div id='units'></div>",
closable: false
},
{title: 'Summaries',
html: "<div id='summaries'></div>",
closable:false
}
]
});
And this is the SummariesTabPanel(the one with problems):
Ext.define("FI.view.SummariesTabPanel", {
extend: 'Ext.tab.Panel',
renderTo: 'summaries',
alias: 'widget.summariesTabPanel',
enableTabScroll: true
});
The problem is with the SummariesTabPanel. If I don't create it, the UnitsTabPanel gets rendered. For some reason, it can't find the summaries div.
Can you please tell me what is wrong?
The SummariesTabPanel renders to the "units" div according to your last snippet of code, is that correct? If not, replace renderTo: 'units' with renderTo: 'summaries'.
Edit
Since it was not the case, you may take a look ath this piece of Ext 4 Panel documentation (here: http://docs.sencha.com/ext-js/4-0/#!/api/Ext.panel.Panel-cfg-html ) that says that the html content isn't added until the component is completely rendered. So, you have to wait for the afterrender event of the tab (not the tabpanel, as you do now) before you can actually get the DOM element.
If you instantiate this Panel
{title: 'Summaries',
html: "<div id='summaries'></div>",
closable:false
}
and store the pointer to it into a separate variable, you could listen to its afterrender event and try again.
A workaround to this could be using an existing element of the page (that is, a static html fragment) instead of adding it via the Panel's html config option.
Why are you doing this that way? If you want to have a nested panels - just define them inside one another. Don't use renderTo
Ext.define("FI.view.SummariesTabPanel", {
extend: 'Ext.tab.Panel',
alias: 'widget.summariesTabPanel'
});
Ext.define("FI.view.MainTabPanel", {
extend: 'Ext.tab.Panel',
alias: 'widget.mainTabPanel',
enableTabScroll: true,
items:[{
xtype: 'summariesTabPanel'
title:'Units',
closable: false
}
]
});

How to add row double click event listener when extending grid panel with Ext.define()?

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();
}
},

Categories