How to bind listeners in ExtJs? - extjs

I am use extjs 6.5.3 modern toolkit and a am puzzled by the following question: how to bind listeners from viewModel to view?
example fiddle: https://fiddle.sencha.com/#view/editor&fiddle/30en
code:
Ext.application({
name: 'Fiddle',
launch: function () {
let container1 = Ext.create("Ext.panel.Panel", {
width: 640,
height: 480,
html: 'hello world!',
viewModel: {
data: {
// not works
listeners: {
onPlay: function () {
Ext.Msg.alert('onPlay', 'onPlay!');
}
},
title: 'test'
}
},
// works
//listeners: {
// onPlay: function () {
// Ext.Msg.alert('onPlay', 'onPlay!');
// }
//},
bind: {
listeners: '{listeners}',
title: '{title}'
},
controller: {
init: function () {
this.getView().fireEvent('onPlay', this.getView());
}
}
});
Ext.Viewport.add({
xtype: 'container',
padding: 10,
items: [container1]
});
}
});

Your code correctly binds the onPlay listener but does not work because the binding happens after your controller initialized. If you fire the onPlay event later e.g. using a timer, the alert will be shown. Check https://fiddle.sencha.com/#view/editor&fiddle/30et

Related

How to determine when a toolbar has been clicked in ExtJS 7.0.0

I want to detect clicks on my toolbar, alternatively focus of toolbar.
The use-case has been extracted from a LiveSearchGrid which has a toolbar, the one seen in the code. The code provided renders fine, but no detect of click, focus, or anything else. Just nothing.
See below:
<div id="toolbar"></div>
<script type="text/javascript">
Ext.create('Ext.toolbar.Toolbar', {
renderTo: 'toolbar',
name: 'searchBar',
focusEl: 'toolbar',
listeners: {
focusenter: function () {
console.log('focusenter')
},
focus: function () {
console.log('focus')
}
},
items: [
{
xtype: 'tbtext',
html: 'Search',
listeners: {
focusenter: function () {
console.log('focusenter')
}
}
},
'Case Sensitive'
]
})
</script>
The following is plain JavaScript which solves my problem.
document.getElementById('toolbar').onclick = function () {
console.log('hello world');
}
What am I doing wrong?
You can set a DOM listener on the underlying Ext.Element using the element property of the listener config
Ext.create('Ext.toolbar.Toolbar', {
renderTo: 'toolbar',
name: 'searchBar',
focusEl: 'toolbar',
listeners: {
click: {
element: 'element', // bind to the underlying element
fn: function() {
console.log('Toolbar element was clicked!');
}
},
focusenter: {
element: 'element', // bind to the underlying element
fn: function() {
console.log('Toolbar element was focused!');
}
}
},
items: []
});
That property can be set to element or bodyElement

Tooltip not showing when enabling a button

After upgrading from Ext5 to 7.2 it is no longer possible to see a tooltip after programatically enabling a button.
Ext.define('X', {
extend: 'Ext.panel.Panel',
initComponent: function() {
this.tbar = [{
text: 'Foo',
disabled: true,
itemId: 'fooBtn',
tooltip: 'FooTip',
handler: function(btn){
this.setHtml('Test')
},
scope: this
},
{
text: 'Bar',
tooltip: 'BarTip',
handler: function(btn) {
this.down('#fooBtn').enable();
},
scope: this
}];
this.callParent();
}
});
Ext.application({
name: 'Fiddle',
launch: function() {
new X({
renderTo: document.body,
title: 'Foo',
width: 200,
height: 200
});
}
});
https://fiddle.sencha.com/#view/editor&fiddle/37o5
Strange bug. You can use the following override to fix it:
Ext.define('overrides.button.Button', {
override: 'Ext.button.Button',
setTooltip: function(tooltip, initial) {
var me = this,
targetEl = me.el;
if (me.rendered) {
if (!initial || !tooltip) {
me.clearTip();
}
if (tooltip) {
if (Ext.quickTipsActive && Ext.isObject(tooltip)) {
Ext.tip.QuickTipManager.register(Ext.apply({
target: targetEl.id
}, tooltip));
me.tooltip = tooltip;
}
else {
targetEl.dom.setAttribute(me.getTipAttr(), tooltip);
}
me.currentTooltipEl = targetEl;
}
}
else {
me.tooltip = tooltip;
}
return me;
}
});
You may try to add one line after enabling:
handler: function(btn) {
this.down('#fooBtn').enable();
******this.down('#fooBtn').setTooltip("FooTip");*****
},
Maybe a bad solution but less code is required.

TabPanel not Render or Show tabs

I have a simple app presentation with a set of windows with sencha components. When a event of move previous window or move next window the main controller take the view, clean it and add a new component to view...
Ext.define('jsclient.view.main.MainVC', {
extend: 'Ext.app.ViewController',
alias: 'controller.main-view',
config: {
listen: {
global: {
eventNewWindow: 'eventNewWindow'
}
}
},
eventNewWindow: function (callback) {
this.view.removeAll();
this.view.add(callback());
}
});
The problem occurs when i put a panel component that contains a tabpanel, the components paint all window, paints the tabs, but no paint the components that contain each tab. If i exam the components that window create, its was created but not render or showing.
Ext.define('jsclient.view.articleCheck.ArticleCheckV', {
extend: 'Fwk.Panel',
alias: 'widget.article-check',
controller: 'article-check',
viewModel: 'article-check',
requires: [
'Fwk.Panel',
'Ext.TabPanel',
'jsclient.view.articleCheck.ArticleCheckVM',
'jsclient.view.articleCheck.ArticleCheckVC',
'jsclient.view.articleCheck.articlePending.ArticlePendingV',
'jsclient.view.articleCheck.articleChecked.ArticleCheckedV'
],
cls: 'article-check',
title: 'Mi ventana**',
titleAlign: 'center',
layout: {
type: 'vbox',
align: 'fit'
},
items: [{
xtype: 'tabpanel',
flex: 1,
deferredRender: true,
items: [{
title: 'Pendientes',
reference: 'pending',
xtype: 'article-pending',
width: "50%"
}, {
title: 'Chequeados',
reference: 'checked',
xtype: 'article-checked',
width: "50%",
}]
}],
tools: [{
type: 'left',
docked: 'left',
listeners: {
click: {
element: 'element',
fn: 'goPrevious'
}
}
}, {
type: 'plus',
docked: 'right',
margin: '0 20 0 0',
listeners: {
click: {
element: 'element',
fn: 'goNewArticle'
}
}
}],
listeners: {
click: {
element: 'element',
fn: 'prueba'
}
},
constructor: function (config) {
this.callParent([config]);
}
});
Any code have two file more that helps viewmodel component, i will saw you a example above.
The View:
Ext.define('jsclient.view.main.MainV', {
extend: 'Fwk.Panel',
alias: 'widget.main-view',
id: 'main-view',
requires: [
'Fwk.Panel',
'jsclient.view.main.MainVM',
'jsclient.view.main.MainVC',
'jsclient.view.blockCheck.BlockCheckV',
'jsclient.view.centerList.CenterListV',
'jsclient.view.articleCheck.ArticleCheckV',
'jsclient.view.articleCheck.articlePending.ArticlePendingV',
'jsclient.view.articleCheck.articleChecked.ArticleCheckedV'
],
viewModel: 'main-view',
controller: 'main-view',
layout: {
type: 'vbox',
align: 'fit'
},
margin: 'auto',
items: [{
xtype: 'center-list',
flex: 1
}],
constructor: function (config) {
this.callParent([config]);
//Read url params and restore context if needed
var urlParams = location.search;
if (urlParams !== '') {
Fwk.Context.restore(urlParams);
}
}
});
The Controller:
Ext.define('jsclient.view.main.MainVM', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.main-view',
data: {},
stores: {}
});
Well, to my problem i doesn't find a solution in the way i'm trying solved... But using a different point of view i can solved.
My oldest way, create items on a component:
This solution might be correct but... for tabpanel doesn't work. I create a component in viewport (main component) and in this component when a event happend i create a new component.
-> Viewport
|
-> MainComponent
|
-> AnyComponent (event)
Using this piece of code i try modified the view main with a callback that return the
constructor of new component in main view:
/*
* Callback in other view
*/
callback: function(options){
return new jsclient.view.mycomponent.MyComponentV(options);
}
/*-----------------------------*/
eventNewWindow: function (callback) {
this.view.removeAll();
this.view.add(callback());
}
My new way create items on viewport:
The new solution is similar but use Viewport instead main component, We need have some
things clear. Viewport is a set (Array) of views that compete for main view, if not are
on main view, the components is on second plane and they not are visible but are init.
So solution left like that, instead use main component we use viewport:
We create N controller for N view, and when a other view send a global event, the controller catch the event and itself create here on viewport.
Ext.define('jsclient.controller.main.MainController', {
extend: 'Ext.app.Controller',
requires: [
'jsclient.view.main.i18n.Main_en_EN',
'jsclient.view.main.i18n.Main_es_ES',
'jsclient.view.main.MainV',
],
config: {
listen: {
global: {
eventNewMain: 'eventNewMain'
}
}
},
eventNewMain : function(options) {
Ext.Viewport.setActiveItem('main-view');
}
});
In the case we need pass argument to component we can do this piece of code:
Ext.define('jsclient.controller.articleCheck.ArticleCheckController', {
extend: 'Ext.app.Controller',
requires: [
'jsclient.view.main.i18n.Main_en_EN',
'jsclient.view.main.i18n.Main_es_ES',
'jsclient.view.articleCheck.ArticleCheckV',
],
config: {
listen: {
global: {
eventNewArticleCheck: 'eventNewArticleCheck'
}
}
},
eventNewArticleCheck: function (options) {
if(options != undefined){
Ext.Viewport.removeAll();
}
Ext.Viewport.add({
xtype: 'article-check',
options: { block: options }
});
Ext.Viewport.setActiveItem('article-check');
}
});

How to change "data" value in viewmodel from store listener?

I binded a placeHolder in 'selectfield' like this:
{
xtype : 'selectfield',
bind : {
store : '{chapters}',
placeHolder : '{chapterPlaceHolder}'
}
}
Now i want to change the data of 'chapterPlaceHolder' in the ViewModel from store listener:
Ext.define('SomeViewModel', {
extend : 'Ext.app.ViewModel',
data : {
chapterPlaceHolder : null
},
stores : {
chapters : {
model : 'model.SiteChapter',
listeners: {
datachanged: function() { how to change the 'chapterPlaceHolder' in data? }
}
}
}
});
Hope i was clear enoght...
Define the event handler on a view controller. View controllers provide a method, getViewModel, to access the view model. The controller should be configured on the same class as the view model. This example assumes that is the select field.
Ext.define('Fiddle.app.ViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.FiddleViewModel',
data: {
chapterPlaceHolder: null
},
stores : {
chapters: {
listeners: {
datachanged: 'dataChangedHandler'
}
}
}
});
Ext.define('Fiddle.app.ViewController', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.FiddleViewController',
dataChangedHandler: function(store, eOpts) {
this.getViewModel.set('chapterPlaceHolder', ...);
}
});
{
xtype: 'selectfield',
bind: {
store : '{chapters}',
placeHolder : '{chapterPlaceHolder}'
},
controller: 'FiddleViewController',
viewModel: {
type: 'FiddleViewModel'
}
}
You need to get viewmodel inside of datachanged event. After getting viewmodel you can use get or set to change value of any field inside of view-model.
In this FIDDLE , I have created a demo using your code and put my efforts in same code. I hope this will help/guide you to achieve your requirement.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
Ext.define('SomeViewModel', {
extend: 'Ext.app.ViewModel',
alias: "viewmodel.demoVM",
data: {
chapterPlaceHolder: null
},
stores: {
chapters: {
listeners: {
datachanged: function () {
var vm = Ext.ComponentQuery.query('#myform')[0].getViewModel();
vm.set('chapterPlaceHolder', 'data changed event called......');
//how to change the 'chapterPlaceHolder' in data ?
}
}
}
}
});
Ext.create('Ext.form.Panel', {
itemId: 'myform',
fullscreen: true,
viewModel: {
type: 'demoVM'
},
defaults: {
margin: 20
},
items: [{
xtype: 'fieldset',
items: [{
xtype: 'selectfield',
autoSelect: false,
bind: {
store: '{chapters}',
placeHolder: '{chapterPlaceHolder}'
}
}]
}, {
xtype: 'button',
text: 'Load Data In store ',
handler: function (btn) {
var vm = btn.up('formpanel').getViewModel();
vm.get('chapters').loadData([{
text: 'First Option',
value: 'first'
}, {
text: 'Second Option',
value: 'second'
}, {
text: 'Third Option',
value: 'third'
}]);
//You can also set like below
//vm.set('chapterPlaceHolder', 'Data loaded on button click......');
}
}]
});
}
});

Ext.getCmp is not working in ExtJS4

I am trying to create a component and access it inside controller. But while accessing the component by id, it is not returning the component. It always returns undefined. Please find below the code.
enter code here
//Component creation in view layer as below
Ext.define('MyApp.view.performance.grid.IFrameGridCmp', {
extend: 'Ext.panel.Panel',
alias: 'widget.crMainPanel',
id:'mainPanelId',
layout: {
align: 'stretch',
type: 'vbox'
},
border:0,
resizable: false,
forceFit: true,
autoWidth: true,
initComponent: function() {
Ext.apply(this, {
items: [
{
xtype:'panel',
flex:.02,
border:0
},
{
xtype:'crHeaderPanel',
flex:.05
},
{
xtype: 'crUpperPanel',
flex: 0.93
},
Ext.create('Ext.Component', {
autoEl: {
tag: 'iframe',
cls: 'x-hidden',
src: Ext.SSL_SECURE_URL
},
id:'FileDownloader',
height:0,
listeners: {
afterrender: function () {
this.getEl().on('load', function () {
console.log('loaded download frame');
});
}
},
load: function(config){
var e = this.getEl();
e.dom.src = config.url + (config.params ? '?' + Ext.urlEncode(config.params) : '');
e.dom.onload = function() {
Ext.getBody().unmask();
if(e.dom.contentDocument.body.childNodes[0].wholeText == '404') {
Ext.Msg.show({
title: 'Attachment missing',
msg: 'The document you are after can not be found on the server.',
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.ERROR
});
}
};
}
})
]
});
this.callParent(arguments);
}
});
========================================
enter code here
//Accessing the controller as below in controller
views: ['performance.grid.IFrameGridCmp'],
//The below line gives error
var downloader = Ext.getCmp('FileDownloader');
downloader.load({
url: '/APXUI/data/json/xls?exportData='+Ext.JSON.encode(records)
});
Well, the view is not created at the time you are calling Ext.getCmp()
Note that views: ['performance.grid.IFrameGridCmp'], is only a sort of binding that view to the controller, which means the controller will create a getter for you, nothing more. You still need to instantiate the view by calling .create(); or Ext.widget('crMainPanel')
In you controller use control for example to handle it:
me.control({
'crMainPanel #FileDownloader': {
afterrender: me.addDownloader
}
});
Don't use Ext.getCmp() it is really slow and you will have many issues with that.
Don't use id - better use itemId.
Why you need to call this from controller?

Resources