The recommended way to declare instance scope custom properties in a component - extjs

Given the below definition of a panel derived extjs component, how do I declare additional instance scope properties that I can set, get and add change events for?
My attempt to just add them inline in the config (startIndex and endIndex), results in them being null, when referenced in onContactsLoaded. I am using the extjs beta 5.0 which allows viewmodels. And while at it, is there a better way to refer to this.getViewModel().getData().groupData.Id, maybe something like this.getViewModel().get('groupData.Id') ?
Ext.define('MyApp.view.ContactCarouselView', {
extend: 'Ext.panel.Panel',
xtype: 'contactcarousel',
requires: ['Ext.container.Container', 'Ext.button.Button', 'Ext.Img', 'MyApp.store.ContactStore'],
height: 71,
width: 12 * 68,
title: '',
cls: 'carousel',
bodyStyle: {},
layout: {
type: 'hbox',
align: 'stretch'
},
startIndex: 0,
endIndex: 7,
viewModel: {},
listeners: {
afterrender: function (panel) {
var me = this;
},
refresh: function () {
}
},
onContactsLoaded: function (contactStore) {
var carousel = this;
var imageHolder = carousel.down('#imageHolder');
var index = 0;
//debugger;
carousel.startIndex = 0;
carousel.endIndex = 7;
Ext.each(contactStore.data.map[contactStore.currentPage].value, function (rec) {
//contactStore.each(function (rec) {
imageHolder.add({
xtype: 'image',
cls: 'contact-picture',
viewModel: { data: rec.data },
width: 68, height: 68,
bind: { src: '{PhotoUrl}' }
});
});
},
items:
[
{
xtype: 'container',
flex: 1,
layout: {
type: 'hbox',
align: 'stretch'
},
items: [{
xtype: 'button',
width: 30,
cls: 'left-button',
text: 'MyButton',
listeners: {
click: function () {
//put one more pic to the left and remove one from the right
var ih = this.up().down('#imageHolder');
var carousel = ih.up();
carousel.startIndex--;
carousel.endIndex--;
ih.scrollBy(-68, 0, true);
}
}
}, {
xtype: 'panel', cls: 'images-area', layout: 'hbox', flex: 1, itemId: 'imageHolder'
}, {
xtype: 'button',
cls: 'right-button',
width: 30,
text: 'MyButton', listeners: {
click: function () {
//put one more pic to the right and remove one from the left
debugger;
var ih = this.up().down('#imageHolder');
var carousel = ih.up();
carousel.startIndex++;
carousel.endIndex++;
ih.scrollBy(68, 0, true);
}
}
}]
}, {
xtype: 'container'
}],
initComponent: function () {
var me = this;
me.callParent(arguments);
var imageStyle = {};
debugger;
var store = Ext.create('MyApp.store.ContactStore', {
pageSize: 8, viewSize: 8, leadingBufferZone: 8,
trailingBufferZone: 8,
});
this.store = store;
store.on('load', this.onContactsLoaded, this, {
//single: true
});
store.loadPage(1,
{
params: { groupId: this.getViewModel().getData().groupData.Id }
});
}
});

It would be helpful to see a Sencha fiddle of this issue?
Regarding config object/values that you add to a custom class, I would no doubt do it in a config (especially if you want the setter and getters created for you). From the ExtJS 5 documentation:
Ext.define('My.sample.Person', {
config: {
name: 'Mr. Unknown',
age: 0,
gender: 'Male'
},
constructor: function(config) {
this.initConfig(config);
return this;
}
// ...
});
If you want to have a quick bind to your ViewModel I suggest adding a new config in your component such as the one above and bind it in your component:
config: {
groupDataId:null
},
bind: {
dataId: '{data.groupDataId.id}' // or '{groupDataId.id}'
}
Then you can access the value by using:
this.getGroupDataId()

Related

Extjs how to get the cursor position in a textareafield

I'm new to Extjs, I need to know how to get te position of the cursor in a textareafield.
I've been googleing an I found these links:
EXTJS 5: Get the current cursor position in a textfield or lookupfield
and
In ExtJs, how to insert a fixed string at caret position in a TextArea?
From there I got this:
Ext.application({
name: 'Fiddle',
launch: function() {
Ext.define({
xtype: 'container',
renderTo: Ext.getBody(),
layout: 'vbox',
padding: 20,
defaults: {
xtype: 'button',
margin: '0 0 12 0'
},
items: [
{
xtype: 'textareafield',
grow: false,
width: 545,
height: 120,
name: 'message',
fieldLabel: '',
id: 'mytextarea',
anchor: '100%'
},
{
xtype: 'button',
text: 'Go',
scale: 'medium',
id: 'mybutton',
listeners: {
click: function() {
var zone = Ext.getCmp('mytextarea');
var text = zone.getValue();
var posic = zone.el.dom.selectionStart;
console.log(posic); // undefined
}
}
}
]
});
}
});
this fiddle
Oh, and I'm using Ext 6.x, Linux Mint, Firefox and Chromium.
But always posic will return undefined... How can I solve this?
You may try with the following approach:
Ext.application({
name : 'Fiddle',
launch : function() {
Ext.define('Trnd.TestWindow', {
extend: 'Ext.window.Window',
closeAction: 'destroy',
border: false,
width: 400,
height: 500,
modal: true,
closable: true,
resizable: true,
layout: 'fit',
title: 'Close window to see the position',
getCaretPos: function() {
var me = this;
var el = me.myTextArea.inputEl.dom;
if (typeof(el.selectionStart) === "number") {
return el.selectionStart;
} else if (document.selection && el.createTextRange){
var range = document.selection.createRange();
range.collapse(true);
range.moveStart("character", -el.value.length);
return range.text.length;
} else {
throw 'getCaretPosition() not supported';
}
},
initComponent: function() {
var me = this;
me.callParent(arguments);
me.myTextArea = Ext.create('Ext.form.field.TextArea', {
width: 500,
height: 500,
editable: true,
selectOnFocus: false,
listeners: {
afterrender: function() {
this.focus(true);
var cursorPos = this.getValue().length;
this.selectText(cursorPos, cursorPos);
}
}
});
me.panel = Ext.create('Ext.panel.Panel', {
items: [
me.myTextArea
]
});
me.add(me.panel);
},
listeners: {
'close': function() {
var me = this;
alert(me.getCaretPos());
}
}
});
var win = new Trnd.TestWindow({
});
win.show();
}
});
Test example with this fiddle.
Use Ext.getDOM() instead of Ext.getCmp() like this:
var myTextArea = Ext.getDom('mytextarea');
var textInArea = myTextArea.value;
var caretPosition = myTextArea.selectionStart;
console.log(caretPosition);
EDIT:
Also xtype of the field must be changed to textarea. In this case your initial example should work too.

Routing Extjs deeper navigation

I'm writing a Extjs app in the 6.2.0 version, I’ve got a routing situation.
My problem is when we enter on the NavigateDeep if I enter the Url ok it catches but it doesn’t render.
I define the routes on the main Controller like:
Ext.define('App.view.main.MainController', {
extend: 'Ext.app.ViewController',
alias: 'controller.main',
listen : {
controller : {
'*' : {
unmatchedroute : 'onRouteChange1',
changeroute: 'changeRoute'
}
}
},
routes: {
':node': 'onNavigate',
':node/:id' : 'onNavigateDeep',
':node/:id/:tabid' : 'onNavigateDeepTab'
},
lastView: null,
onRouteChange1: function(){
console.log("hier unmatched route");
},
setCurrentView: function(hashTag) {
hashTag = (hashTag || '').toLowerCase();
console.log("hash:" + hashTag);
var me = this,
refs = me.getReferences(),
mainCard = refs.mainCardPanel,
mainLayout = mainCard.getLayout(),
navigationList = refs.navigationTreeList,
store = navigationList.getStore(),
node = store.findNode('routeId', hashTag) ||
store.findNode('viewType', hashTag),
view = (node && node.get('viewType')) || 'page404',
lastView = me.lastView,
existingItem = mainCard.child('component[routeId=' + hashTag + ']'),
newView;
// Kill any previously routed window
if (lastView && lastView.isWindow) {
lastView.destroy();
}
lastView = mainLayout.getActiveItem();
if (!existingItem) {
newView = Ext.create({
xtype: view,
routeId: hashTag, // for existingItem search later
hideMode: 'offsets'
});
}
if (!newView || !newView.isWindow) {
// !newView means we have an existing view, but if the newView isWindow
// we don't add it to the card layout.
if (existingItem) {
// We don't have a newView, so activate the existing view.
if (existingItem !== lastView) {
mainLayout.setActiveItem(existingItem);
}
newView = existingItem;
}
else {
// newView is set (did not exist already), so add it and make it the
// activeItem.
Ext.suspendLayouts();
mainLayout.setActiveItem(mainCard.add(newView));
Ext.resumeLayouts(true);
}
}
navigationList.setSelection(node);
if (newView.isFocusable(true)) {
newView.focus();
}
me.lastView = newView;
},
onNavigationTreeSelectionChange: function (tree, node) {
var to = node && (node.get('routeId') || node.get('viewType'));
if (to) {
console.log("to;:" + to);
this.redirectTo(to);
}
},
onToggleNavigationSize: function () {
var me = this,
refs = me.getReferences(),
navigationList = refs.navigationTreeList,
wrapContainer = refs.mainContainerWrap,
collapsing = !navigationList.getMicro(),
new_width = collapsing ? 64 : 250;
if (Ext.isIE9m || !Ext.os.is.Desktop) {
Ext.suspendLayouts();
refs.logo.setWidth(new_width);
navigationList.setWidth(new_width);
navigationList.setMicro(collapsing);
Ext.resumeLayouts(); // do not flush the layout here...
// No animation for IE9 or lower...
wrapContainer.layout.animatePolicy = wrapContainer.layout.animate = null;
wrapContainer.updateLayout(); // ... since this will flush them
}
else {
if (!collapsing) {
// If we are leaving micro mode (expanding), we do that first so that the
// text of the items in the navlist will be revealed by the animation.
navigationList.setMicro(false);
}
// Start this layout first since it does not require a layout
refs.logo.animate({dynamic: true, to: {width: new_width}});
// Directly adjust the width config and then run the main wrap container layout
// as the root layout (it and its chidren). This will cause the adjusted size to
// be flushed to the element and animate to that new size.
navigationList.width = new_width;
wrapContainer.updateLayout({isRoot: true});
navigationList.el.addCls('nav-tree-animating');
// We need to switch to micro mode on the navlist *after* the animation (this
// allows the "sweep" to leave the item text in place until it is no longer
// visible.
if (collapsing) {
navigationList.on({
afterlayoutanimation: function () {
navigationList.setMicro(true);
navigationList.el.removeCls('nav-tree-animating');
},
single: true
});
}
}
},
onMainViewRender:function() {
if (!window.location.hash) {
this.redirectTo("dashboard");
}
},
changeRoute: function(controller,route){
this.redirectTo(route,true);
console.log("change route fired");
},
onClickLogoutButton: function () {
// Remove the localStorage key/value
localStorage.removeItem('LoggedIn');
// Remove Main View
this.getView().destroy();
// Add the Login Window
Ext.create({
xtype: 'login'
});
},
onClickShareButton: function(){
var text = window.location;
window.prompt("Copy to clipboard:", text);
},
onNavigate:function(node){
console.log("on route change");
this.setCurrentView(node);
},
onNavigateDeep: function (node, id) {
console.log("Tab");
console.log(node + '/' + id);
var route = node+'/'+id;
this.setCurrentView(route);
},
onNavigateDeepTab: function (node, id, tabid) {
console.log("navigate Tab");
}
});
My main view is:
Ext.define('App.view.main.Main', {
extend: 'Ext.container.Viewport',
xtype: 'app-main',
requires: [
'App.view.Dashboard',
'App.view.immo.List',
'App.view.settings.Settings',
'App.view.news.News',
'App.view.help.Help'
],
controller: 'main',
viewModel: 'main',
cls: 'sencha-dash-viewport',
itemId: 'mainView',
layout: {
type: 'vbox',
align: 'stretch'
},
listeners: {
render: 'onMainViewRender'
},
items: [{
xtype: 'toolbar',
cls: 'dash-dash-headerbar shadow',
height: 64,
itemId: 'headerBar',
items: [{
xtype: 'component',
reference: 'logo',
cls: 'logo',
html: '<div class="main-logo"><img src="resources/images/logo.png">App</div>',
width: 250
}, {
margin: '0 0 0 8',
ui: 'header',
iconCls:'x-fa fa-navicon',
id: 'main-navigation-btn',
handler: 'onToggleNavigationSize',
tooltip: 'Navigation umschalten'
},
'->',
{
xtype: 'button',
ui: 'header',
iconCls: 'x-fa fa-share-alt',
handler: 'onClickShareButton',
tooltip: 'Share'
},
{
iconCls:'x-fa fa-question',
ui: 'header',
href: '#help',
hrefTarget: '_self',
tooltip: 'Hilfe'
}, {
iconCls:'x-fa fa-th-large',
ui: 'header',
href: '#Dashboard',
hrefTarget: '_self',
tooltip: 'Zum Dashboard'
}, {
xtype: 'button',
ui: 'header',
iconCls: 'x-fa fa-power-off',
handler: 'onClickLogoutButton',
tooltip: 'Logout'
}]
}, {
xtype: 'maincontainerwrap',
id: 'main-view-detail-wrap',
reference: 'mainContainerWrap',
flex: 1,
items: [{
xtype: 'treelist',
reference: 'navigationTreeList',
itemId: 'navigationTreeList',
ui: 'navigation',
store: 'NavigationTree',
width: 250,
expanderFirst: false,
expanderOnly: false,
listeners: {
selectionchange: 'onNavigationTreeSelectionChange'
}
}, {
xtype: 'container',
flex: 1,
reference: 'mainCardPanel',
cls: 'sencha-dash-right-main-container',
itemId: 'contentPanel',
layout: {
type: 'card',
anchor: '100%'
}
}]
}]
});
When we click on the tree I change the container but one of them has the route if the :id where I have a Tab:
Ext.define('App.view.settings.Settings',{
extend: 'Ext.tab.Panel',
xtype: 'settings',
itemId:'settings',
requires: [
'App.view.settings.SettingsController',
'App.view.settings.SettingsModel',
'App.view.settings.property.Property',
'App.view.settings.user.User'
],
controller: 'settings-settings',
viewModel: {
type: 'settings-settings'
},
reference: 'tab',
tabPosition: 'left',
tabBar:{
flex: 1,
tabRotation: 0,
tabStretchMax: true,
cls: 'immoNavi'
},
layout: 'Container',
defaults: {
padding: 0,
textAlign: 'left'
},
listeners: {
tabchange: 'onTabChange'
},
items: [{
xtype: 'component',
tabConfig:{
hidden: true
}
},{
title: 'Property',
itemId: 'property',
xtype: 'property',
cls: 'container'
},{
title: 'User',
itemId: 'user',
xtype: 'user'
}]
});
I went through the documentation but didn't find any tip that might help me with it. What am I missing here? Should I take care the rendering on the tab controller? Or How?
Thanks in advance for the help

extjs proper way to replace main center panel

In ExtJS, on a menu toolbar button, I am trying to remove the current panel in my center window, then recreate it with the new selection. I do not understand the proper way to do this. So far when I click the menu item, it removes whatever is currently there successfully, then it will add the new panel successfully. The problem is the 2nd time I hit the button I get the following error:
REGISTERING DUPLICATE COMPONENT ID 'mainportalID'.
I realize its telling me I already used this ID, but then what would be the correct way to remove the current panel, and replace with a new one?
Here is my view controller:
selectMenuButton: function (button, e) {
console.log('select menu button section was hit')
console.log(button);
console.log(e);
var optionString = button.text;
var myDetailsPanel = Ext.getCmp('navview');
console.log(myDetailsPanel);
var count = myDetailsPanel.items.items.length;
if (count > 0) {
myDetailsPanel.items.each(function (item, index, len) {
myDetailsPanel.remove(item, false);
});
}
myDetailsPanel.add({
xtype: optionString
});
}
var myStore = Ext.create('ExtApplication1.store.PositionsStore');
var gridSummary = Ext.create('Ext.grid.Panel', {
store: myStore,
width: 600,
title: 'my first grid',
columns: [
{
text: 'AcctNum',
dataIndex: 'AcctNum',
width: 100
},
{
text: 'AcctShortCode',
dataIndex: 'AcctShortCode',
flex: 1
},
{
text: 'Exchange',
dataIndex: 'Exchange',
width: 200
}
]
});
This is my view
Ext.define('ExtApplication1.view.main.MainPortal', {
extend: 'Ext.panel.Panel',
xtype: 'mainportal',
alias: 'widget.mainportal',
id: 'mainportalID',
html: 'user... this is the main portal window',
autoScroll: true,
bodyPadding: 10,
items: [
gridSummary
]
});
adjusted panel
Ext.define('ExtApplication1.view.main.MainPortal', {
extend: 'Ext.panel.Panel',
xtype: 'mainportal',
alias: 'widget.mainportalAlias',
reference: 'gridtextfield',
//id: 'mainportalID',
html: 'user... this is the main portal window',
autoScroll: true,
bodyPadding: 10,
items: [
gridSummary
]
});
adjusted view controller
onComboboxSelect: function (combo, record, eOpts) {
console.log('new listener was hit');
//return selected Item
var selectedValue = record.get('ClientName');
var selectedCID = record.get('ClientID');
//find the grid that was created
var me = this;
console.log(me);
var xxx = this.lookupReference('gridtextfield');
debugger;
//debugger;
var mainPortalView = Ext.getCmp('mainportalID');
var targetGrid = mainPortalView.down('grid');
//find the store associated with that grid
var targetStore = targetGrid.getStore();
//load store
targetStore.load({
params: {
user: 'stephen',
pw: 'forero',
cid: selectedCID
}
//callback: function (records) {
// Ext.each(records, function (record) {
// console.log(record);
// });
// console.log(targetStore);
//}
});
},
added listeners to MainPortal.js
var myStore = Ext.create('ExtApplication1.store.PositionsStore');
var gridSummary = Ext.create('Ext.grid.Panel', {
store: myStore,
width: 600,
title: 'my first grid',
columns: [
{
text: 'AcctNum',
dataIndex: 'AcctNum',
width: 100
},
{
text: 'AcctShortCode',
dataIndex: 'AcctShortCode',
flex: 1
},
{
text: 'Exchange',
dataIndex: 'Exchange',
width: 200
}
],
listeners: {
destroy: function () {
debugger;
}
}
});
Ext.define('ExtApplication1.view.main.MainPortal', {
extend: 'Ext.panel.Panel',
xtype: 'mainportal',
alias: 'widget.mainportalAlias',
//id: 'mainportalID',
itemId: 'mainportalID',
html: 'user... this is the main portal window',
autoScroll: true,
bodyPadding: 10,
items: [
gridSummary
],
listeners: {
destroy: function () {
debugger;
}
}
});

Config Proprety in Extjs-6 Picker doese not work perfectly

I'm developing an application using Extjs-6. I extend a viewclass from a Ext.form.field.Picker as follow:
Ext.define('Fiddle.MyCombo', function(){
var me;
var initComponent = function()
{
me = this;
Ext.apply(me, {});
me.callParent(arguments);
};
var createPicker = function ()
{
var textfield = {
xtype: 'textfield',
width: '100%',
border: false,
listeners: {
change: function(component, newValue)
{
me.setStr(newValue);
}
}
};
var panel = new Ext.panel.Panel({
rtl: true,
minWidth: 300,
floating: true,
items: [textfield]
});
Ext.Msg.alert('Attension', 'Init Value is : ' + me.getStr());
return Ext.widget(panel);
};
return {
extend: 'Ext.form.field.Picker',
alias: 'widget.mycombo',
initComponent: initComponent,
createPicker: createPicker,
config: {
str: ''
}
};
});
I use this class as follow:
Ext.define('Fiddle.Main', {
extend: 'Ext.panel.Panel',
width: 400,
height: 200,
title: 'Its me!',
items: [{
xtype: 'mycombo',
name: 'item1'
}, {
xtype: 'mycombo',
name: 'item2'
}]
});
When I open first mycombo(item1) and type some word in textfield input, and then open second mycombo item(items2), in createPicker function I alert str value of item, and it show the item1's value.
Why it show item1's str value?
Where is wrong?
My Sample fiddle is here.

How to create a field class containing an image in Ext JS 4?

i'm creating an application in Ext JS 4 and i'm stuck because i need a class containing an image to use into a form or a fieldset (like a regular textfield); moreover the image will change depending on the value passed to the form.
Something like an imagefield:
Ext.define('Properties', {
extend : 'Ext.form.Panel',
alias : 'properties',
bodyPadding: 5,
// The fields
defaultType: 'textfield',
items: [{
fieldLabel: 'Device Name',
name: 'deviceName'
},
{
xtype:'imagefield',
fieldLabel: 'Status',
name: 'status'
}
],.......
I've tried to extend Ext.form.field.Base without any success.
Somebody can help me ?
Thank you.
There is Ext.Image class you can use. But you probably would need to wrap it into some kind of border and add logic to load specific image in a run-time. If you want I can post some code later today.
Update: I did something like that:
Ext.define('QP.view.base.ImageContainer', {
extend: 'Ext.container.Container',
alias: 'widget.baseimagecontainer',
NO_IMAGE_FILE: 'resources/images/no_image.png',
DOWNLOAD_URL: '/Image/',
UPLOAD_URL: '/UploadImage',
CLEAR_URL: '/ClearImage/',
width: 205,
layout: 'hbox',
initComponent: function() {
var me = this;
Ext.apply(me, {
items: [{
xtype: 'fieldset',
itemId: 'imageWrapper',
title: 'Image',
width: 122,
height: 140,
margin: '0 0 0 0',
layout: 'anchor',
items: [{
xtype: 'image',
itemId: 'image',
maxWidth: 100,
maxHeight: 100
}]
}, {
xtype: 'container',
margin: '4 0 0 5',
layout: 'anchor',
defaults: {
xtype: 'button',
width: 70,
margin: '0 0 5 0'
},
items: [{
itemId: 'clearButton',
text: 'Clear',
handler: function() {
me.clearImage();
}
}, {
xtype: 'fileuploadfield',
buttonOnly: true,
hideLabel: true,
itemId: 'uploadButton',
buttonText: 'Upload...',
buttonConfig: { width: 70 },
listeners: {
change: function(el, val) {
// this.up('window').fireEvent('uploadimage', fb, v);
me.uploadImage(el, val);
}
}
}, {
itemId: 'fullResButton',
text: 'Download',
handler: function() {
window.open(me.fullImagePath);
}
}]
}]
});
me.callParent(arguments);
},
success: function() {
var me = this,
fs = me.down('[itemId=imageWrapper]'),
b1 = me.down('[itemId=clearButton]'),
b2 = me.down('[itemId=fullResButton]');
fs.enable();
b1.enable();
b2.enable();
},
loadImage: function(recordId) {
var me = this,
fs = me.down('[itemId=imageWrapper]'),
b1 = me.down('[itemId=fullResButton]'),
b2 = me.down('[itemId=clearButton]'),
img = me.down('image');
me.fullImagePath = me.DOWNLOAD_URL + '/' +recordId;
me.imageRecordId = recordId;
fs.disable();
b1.disable();
b2.disable();
img.getEl().on('load', me.success, me, { single: true });
img.getEl().on('error', function() {
img.getEl().un('load', me.success, me);
img.setSrc(me.NO_IMAGE_FILE);
fs.enable();
}, me, { single: true });
img.setSrc(me.DOWNLOAD_URL + '/' +recordId);
},
uploadImage: function(el, val) {
var me = this,
fm = Ext.create('Ext.form.Panel', {
items: [ el ]
}),
f = fm.getForm();
f.submit({
method: 'POST',
params: {
recordId: me.imageRecordId
},
url: me.UPLOAD_URL,
waitMsg: 'Uploading your image...',
success: function(fp, o) {
me.loadImage(me.imageLocation, me.imageRecordId);
},
failure: function(fp, o) {
console.log('upload failed', fp, o);
}
});
},
clearImage: function() {
var me = this;
QP.util.Msg.askConfirmation('Are you sure you want to delete an image?', function() {
Ext.Ajax.request({
method: 'GET',
url: me.CLEAR_URL + me.imageLocation + '/' + me.imageRecordId,
success: function(fp, o) { me.loadImage(me.imageLocation, me.imageRecordId); },
failure: function(fp, o) { console.log('upload failed', fp, o); }
});
}, me);
}
});

Resources