Avoid Ext.form validation scrolling to top - forms

I have a Ext.form.Panel inside Ext.window. Form height is more than window height so I have vertical scroll on window.
On form fields validation (on validitychange event) scroll jumps to the top.
How to avoid this behaviour?

I tried to figure out, why one of my forms did scroll up and other did not. Turned out, that I have forgot to explicitly specify layout manager and that default layout manager (anchor) scrolled to top on validity change, while vbox layout did not. While everything looked exactly the same (vbox with align: 'stretch'), it behaved differently when the error was either shown or hidden.

I have the same problem :(
I made a creepy workaround (it works to 80%) Sometimes it still jumps to the top.
You should know, that I have a window with a layout of 'form'. If you have a window with (for example) a layout of 'fit' with an xtype of 'form' - you may have to change the code a little bit.
For example the line el.child(".x-window-body", fasle) wouldn't work.
init: function() {
this.control({
...
/** My Ext.window.Window is called reservationwindow **/
'reservationwindow': {
afterrender: function(comp) {
// comp is this Ext.Component == wrapper
var el = comp.getEl();
//extjs adds the scrollbar to the body element...
var elForm = el.child(".x-window-body", false);
// or el.child(".x-panel-body", false);
//we are listinig to the scroll-event now
this.myFormEl = elForm;
this.safeScroll = {top:0, left:0};
elForm.on('scroll', function() {
console.log("save");
this.safeScroll = this.myFormEl.getScroll();
}, this);
elForm.on('click', function() {
var resWin = this.getResWin();
resWin.scrollBy(0,this.safeScroll.top,false);
console.log("reset");
}, this);
elForm.on('keyup', function() {
var resWin = this.getResWin();
resWin.scrollBy(0, this.safeScroll.top, false);
console.log("reset");
}, this);
}
As you can see, I am listening to the scroll-event and safe and reset the scroll bar. Sometimes (especially if you are writing very quickly in a textbox) the events come in a different order and the page will still jump to the top. Sometimes you also see it flickering around (if it needs too long to set it back to the original position).
So.... As I said, its a creepy workaround.
If you find a better solution, please let me know.
EDIT
I also figured out, that the grow option on a textareafield was one of the troublemakers.
{
id: this.id + '-details',
xtype: 'textareafield',
// grow: true, now it isn't jumping
name: 'message',
fieldLabel: 'Zusätzliche Informationen',
labelAlign: 'top',
renderder: 'htmlEncode',
disabled: isDisabled,
anchor: '100%'
}

Related

How to add a horizontal scrollbar on top of the ag-grid

I have an ag-grid set up with a series of components in place for cell rendering. When my dataset loads the vertical scroll works well but the horizontal scroll isn't obvious unless using a trackpad or horizontal scroll enabled mouse.
I would like to be able to add a scroll bar to the top of the grid as well as the automatically generated one at the bottom?
Has anyone encountered this, come up with as solution?
Thanks in advance
This question is old but I struggled with the same issue and came up with something working.
💡 The Idea
The main idea behind my solution is to...
clone AgGrid scrollbar when grid is ready
insert the cloned scrollbar on top of the grid
add event listeners on both scrollbars to keep the scroll position synchronized
use MutationObserver to observe style attribute changes on original AgGrid scrollbar element (and child) to keep the size of the cloned scrollbar synchronized
⚡ The Code
The following code is for Angular but the concept is the same for Vanilla JS, React or Vue.
First, get a hook on gridReady event:
<ag-grid-angular
...
(gridReady)="onGridReady()">
</ag-grid-angular>
In the function associated to the event use the following code to clone the AgGrid scrollbar and keep the scrollbars synchronized:
// hold the `MutationObserver` to be disconnected when component is destroyed
private mutationObserver: MutationObserver;
onGridReady() {
// css class selectors
const headerSelector = '.ag-header';
const scrollSelector = '.ag-body-horizontal-scroll';
const scrollViewportSelector = '.ag-body-horizontal-scroll-viewport';
const scrollContainerSelector = '.ag-body-horizontal-scroll-container';
// get scrollbar elements
const scrollElement = document.querySelector(scrollSelector);
const scrollViewportElement = document.querySelector(scrollViewportSelector);
const scrollContainerElement = document.querySelector(scrollContainerSelector);
// create scrollbar clones
const cloneElement = scrollElement.cloneNode(true) as Element;
const cloneViewportElement = cloneElement.querySelector(scrollViewportSelector);
const cloneContainerElement = cloneElement.querySelector(scrollContainerSelector);
// insert scrollbar clone
const headerElement = document.querySelector(headerSelector);
headerElement.insertAdjacentElement('afterend', cloneElement);
// add event listeners to keep scroll position synchronized
scrollViewportElement.addEventListener('scroll', () => cloneViewportElement.scrollTo({ left: scrollViewportElement.scrollLeft }));
cloneViewportElement.addEventListener('scroll', () => scrollViewportElement.scrollTo({ left: cloneViewportElement.scrollLeft }));
// create a mutation observer to keep scroll size synchronized
this.mutationObserver = new MutationObserver(mutationList => {
for (const mutation of mutationList) {
switch (mutation.target) {
case scrollElement:
cloneElement.setAttribute('style', scrollElement.getAttribute('style'));
break;
case scrollViewportElement:
cloneViewportElement.setAttribute('style', scrollViewportElement.getAttribute('style'));
break;
case scrollContainerElement:
cloneContainerElement.setAttribute('style', scrollContainerElement.getAttribute('style'));
break;
}
}
});
// start observing the scroll elements for `style` attribute changes
this.mutationObserver.observe(scrollElement, { attributeFilter: ['style'], subtree: true });
}
When destroying the component, disconnect the MutationObserver to avoid memory leaks.
ngOnDestroy() {
// stop observing
this.mutationObserver.disconnect();
}
It's tricky and all based on keeping the cloned scrollbar synchronized with the original scrollbar but so far it works great for my use cases.
Good luck 😎
Update 2022
::ng-deep{
.ag-root-wrapper{
.ag-root-wrapper-body{
.ag-root{
.ag-body-horizontal-scroll{
order: 1;
}
.ag-header{
order: 2;
}
.ag-floating-top{
order: 3;
}
.ag-body-viewport{
order: 4;
}
.ag-floating-bottom{
order: 5;
}
.ag-overlay{
order: 6;
}
}
}
}
}

How to collapse the leaflet control

I start my application with expand Layer-Control:
L.control.layers(baseMaps, overlays, { collapsed:false } ).addTo(mymap);
I found no Mouse-Action to minimize the Layer-Control. I want to minimize the Layer-Control. But I don't know the handler. Could anybody give me a tip?
I had the same requirement for Leaflet. I needed to have the layer control expanded at first and then return to its normal hiding after someone realizes what it does.
I am using JQuery, but you could probably manipulate the DOM as well.
I have a function that instantiates the layer control object, and then I immediately reset the mouseenter and mouseleave events for the expanded control and the smaller toggle widget.
let layerControl = L.control.layers(basemap_items, { 'specialLayer': layer}, { collapsed: false }).addTo(map);
$('.leaflet-control-layers').on('mouseleave', () => {
layerControl.collapse();
});
$('.leaflet-control-layers-toggle').on('mouseenter', () => {
layerControl.expand();
});

Jumpy transitions on Chrome and Safari using FullScreen API (or resize)

I have created a portfolio-type (WordPress-based) website, using FullPage and Flexslider (as a absolute positioned pop-up), and it has a FullScreen button, which is currently giving me some nightmares, but only on the second ".section" in of the FullPage (it only has two sections).
I am also using SlimScroll.js as advised on the FullPage documentation as it can be taller than the window.
For Chrome the animation is "clunky", and when it goes fullscreen it waits like a second until it actually does. Please see the image below:
Screenshot of transition happening
I have added the following code and it worked for the first section, but not to the second section...:
html:not(.ios) .fp-section.active {
height: 100vh !important;
}
html:not(.ios) .fp-section.active .fp-tableCell {
height: 100vh !important;
}
On Safari, though, the transition is smooth but, every now and then, when it finishes it flickers...!
On Firefox there's not much problem as the fullscreen fades in and out. (Is there a way to replace it for a zoom-type animation?
My FullPage settings:
$('#fullpage').fullpage({
// Navigation
slideNavigation: false,
// Scrolling
easingcss3: 'cubic-bezier(0.850, 0.000, 0.250, 1.000)', //easeInOutCirc
scrollingSpeed: 500,
scrollOverflow: true,
// Design
controlArrows: false,
// Events
afterLoad: function(anchorLink, index) { // after changing section
if (index == 1){
// Load scrollDown link so that you don't have to load it afterwards
$('#main').load(scrollDown + ' .main-content', function(){
$.fn.fullpage.reBuild();
});
// Hide menu
if ( $( '#site-navigation' ).hasClass( 'toggled' ) ) {
$( '#site-navigation' ).removeClass('toggled');
$( '#site-navigation .menu-toggle').attr( 'aria-expanded', 'false' );
$( '#site-navigation ul').attr( 'aria-expanded', 'false' );
}
}
colorInversion();
popupSlider();
},
afterRender: function() { // so that it applies to first section too
colorInversion();
popupSlider();
},
afterSlideLoad: function( anchorLink, index, slideAnchor, slideIndex) { // after changing slide
//$.fn.fullpage.reBuild();
popupSlider();
}
});
My FlexSlider settings:
$('#popup-slider').flexslider({
animation: 'slide',
slideshow: false,
easing: 'easeInOutExpo',
animationSpeed: 0,
customDirectionNav: $(".flex-direction-nav a"),
// Usability features
video: true,
// Special Properties
manualControls: '.popup-slider-link',
// Callback API
start: function(slider){
$('.slides li *').click(function(event){
event.preventDefault();
slider.flexAnimate(slider.getTarget("next"));
});
},
after: function(){ // After each slider animation completes
flexslideColorInversion(); // Check for color inversion
$('#popup-slider').data('flexslider').vars.animationSpeed = 500; // Put animation speed back to 500
},
});
(Flexslider is initialised inside the popupslider() function.)
Is there a way to "fix" these issues?
Thank you so much in advance to anyone who may be able to help me with this.
EDIT:
I have seen that the lag in Chrome was because the popup was over the thumbnails and therefore was still resizing them even though they weren't in view; my solution to this was to apply a "display: none" to when the popup slider was on.
The Flicker in Safari is because FullPage.js changes the sections' sizes and their "translate3d", so there is a flicker when that adjustment occurs. The default Fullpage.js characteristic is to actually show part of the section above while it's adjusting, but as I am using 100vh for the .active section it doesnt show on Chrome, Opera or Firefox and only flickers in Safari (hence me wondering what the flicker was!)
Probably the only way around it is to recode Fullpage.js's translate3d (and height/width) codes also with "vh" so that it doesn't have to adjust the size. If any one has a ready code of this, that would be really appreciated! (IE8 is support is not required).
Cheers

Dynamic Carousel Content does not show

I have been working on this for a number of days now, but my limited JS knowledge seems to hurt me.
I am creating a dynamic Ext.Carousel component in my ST2 application, which is based on the contents of a Store file.
That all works fine, but I will show the code anyway, so that nothing is left to imagination:
Ext.getStore('DeviceStore').load(
function(i) {
Ext.each(i, function(i) {
if (i._data.name == 'Audio Ring') {
var carousel = Ext.ComponentManager.get('speakerCarousel');
var items = [];
Ext.each(i.raw.speakers, function(speaker) {
items.push({
sci: Ext.create('SmartCore.view.SpeakerCarouselItem', {
speakerId: speaker.speakerid,
speakerName: speaker.speakername,
speakerEnabled: speaker.speakerenabled
})
});
});
carousel.setItems(items);
}
});
})
Now, this adds me the appropriate number of items to the carousel. They display, but without the content I specified:
This is the Carousel itself:
Ext.define('SmartCore.view.SpeakerCarousel', {
extend: 'Ext.Carousel',
xtype: 'speakerCarousel',
config: {
id: 'speakerCarousel',
layout: 'fit',
listeners: {
activeitemchange: function(carousel, item) {
console.log(item);
}
}
}
});
This is the item class, that I want to fill the data from the store into:
Ext.define("SmartCore.view.SpeakerCarouselItem", {
extend: Ext.Panel,
xtype: 'speakerCarouselItem',
config: {
title:'SpeakerCarouselItem',
styleHtmlContent: true,
layout: 'fit'
},
constructor : function(param) {
this.callParent(param);
this.add(
{
layout: 'panel',
style: 'background-color: #759E60;',
html: 'hello'
}
)
}
});
Again, the right number of items shows in the carousel (11), but the content is not visible, nor is the background colour changed.
When I check the console.log(item) in the browser, the items show as innerItems inside the carousel object.
Any help is greatly appreciated!!
Well, I fixed it myself, or better, I found a workaround that seems to be what I want.
I ended up ditching the constructor all together.
Instead I overwrote the apply method for the 'speakerName' key-value pair.
From there, I can use:
this._items.items[0]._items.items[i].setWhatever(...)
to set the content inside the item.
If anyone knows the "real" way to do this, I would still greatly appreciate input!

Sencha Touch 1.1.0: Form is not showing scrollbars

I am creating an Application that consist of a Panel,
This panel contains a Tab-Panel and a Form-Panel. (Initially, Form-Panel is Hidden)
The Tab-Panel has a Tab, which contains a List.
When Tapped on a List-Item it dose the following
Shows the Form-Panel
Hides the Tab-Panel
My Problem is When it does so , The form do not show any scroll bars, How ever when i change the orientation of the device(iPhone) and then it allows me to scroll.
Can anyone explain me if i am doing it correctly, or is there any better way to achieve this functionality, or can the Main Panle be changed with a view Port ?
A small example will be really great.
Below is my Code (i will try to keep it simple)
Decleration of List and Event Listener
var lstRequestTracker = new Ext.List({
itemTpl : '{emplFirstName} {emplLastName}'
,store : storeRequestTracker
,fullscreen: true
});
lstRequestTracker.on('itemtap', function( oThis, index, item, event) {
var rec = oThis.getStore().getAt(index);
tpnlMyForms.hide();
fpnlOnBoard.show();
//pnlMain.doComponentLayout();
fpnlOnBoard.doComponentLayout();
});
Code for declaring the Main-Panel, Tab-Panel and The Form-Panel
var tpnlMyForms = new Ext.TabPanel({
tabBar : {dock : 'bottom', layout:'hbox'}
,fullscreen : true
,defaults : {scroll: 'vertical', layout:'fit'}
,items : [ {
title : 'Request Tracker'
,items : [lstRequestTracker]
,iconCls: 'time'
}
]
});
var fpnlOnBoard = new Ext.form.FormPanel({Contains form Fields});
Ext.setup({
onReady: function() {
var pnlMain = new Ext.Panel({
fullscreen : true
,dockedItems: [{dock:'top', xtype:'toolbar',title:'STARS'}]
,layout: 'fit'
,items : [tpnlMyForms,fpnlOnBoard]
});
fpnlOnBoard.hide();
}// eo onReady Function
});
Have you tried giving your formPanel a scroll option (scoll: 'horizontal') ? I really don't know wether this will help, but I remember I also had a form a few days ago and this was the solution. That had nothing to do with the device orientation by the way, but who knows..