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