Sencha Touch: Removing an item then updating view on orientation change etc - sencha-touch

thanks for the reply, looks like we might be getting somewhere. I have created a new view thats plain and in a simple form. See below:
var homePanelTop = new Ext.Panel({ id:'topCont',
cls:'topCont'
});
var homePanelBtm = new Ext.Panel({
id:'btmCont',
cls:'btmCont'
});
App.views.HomeIndex = Ext.extend(Ext.Panel, {
id:'mainlayout',
fullscreen : true,
layout: {
type: 'vbox',
align: 'stretch',
},
defaults:{flex:1},
items: [homePanelTop, homePanelBtm],
suspendLayout: true,
monitorOrientation: true,
orientationchange: this.onOrientationChange,
onOrientationChange: function(orientation, w, h){
this.suspendLayout = false;
if(orientation === 'portrait'){
console.log('P: ' + orientation);
this.add(homePanelTop, true);
} else {
console.log('L: ' + orientation);
this.remove(homePanelTop, false);
}
this.doLayout();
}
});
Ext.reg('HomeIndex', App.views.HomeIndex);
What i expect to see with the above view is on first load and portrait, there will be two panels, the top panel(yellow) and a bottom panel (blue). When I rotate as normal I still get the same effect.
But what I am after is that when I rotate to landscape the top panel (yellow) is removed and the bottom panel (blue) fills the rest of the space.
Then when I rotate back to portrait I get both panels back at their design sizes (flex:1)
Whats happening using the code above (testing in chrome) is that the top panel (yellow) remains at the top but slightly smaller in height and does not disappear like it should
Anyway notice the two console trace commands I have and these are showing the following readings on rotation:
After first load, I then rotate to landscape and the output is:
L: landscape
L: landscape
Attempted to remove a component that does not exist. Ext.Container: remove takes an argument of the component to remove. cmp.remove() is incorrect usage.
L: landscape
Attempted to remove a component that does not exist. Ext.Container: remove takes an argument of the component to remove. cmp.remove() is incorrect usage.
L: landscape
Attempted to remove a component that does not exist. Ext.Container: remove takes an argument of the component to remove. cmp.remove() is incorrect usage.
The when I rotate back to portrait I get the following output:
L: landscape
Attempted to remove a component that does not exist. Ext.Container: remove takes an argument of the component to remove. cmp.remove() is incorrect usage.
L: landscape
Attempted to remove a component that does not exist. Ext.Container: remove takes an argument
of the component to remove. cmp.remove() is incorrect usage.
P: portrait
P: portrait
So looking at this on the lanscape rotation it actually some how fires the onorientationchange function 4 times, the first one is ok the other three with an error as the first one already removed it so thats what the warnings are for I believe.
Then with the portrait ones I get two registering as lanscape calls then two hits registering portrait calls.
All this with one movement, so is this somehow causing the remove and add code's not to work as predicted and how to prevent the orientation being called four times on rotation??
If anyone has an idea on the development of this feel free to join in.
Thanks for the help so far
Si

Many years later... and more for someone like me that stumbles on to this looking for help.
Two things.
1) The message "Attempted to remove a component that does not exist" is found only in the "development" version of the ExtJS library and I don't know that it is a reliable indicator of a problem.
2) If you can upgrade to ExtJS 4.1x. It will give you access to better debugging tools. I am thinking specifically of the 'Ext JS Page Analyzer'. This will help you see what the layout engine is doing as apposed to what you hope it is doing.
See: http://www.sencha.com/blog/optimizing-ext-js-4-1-based-applications

Related

How to stay in position when new messages are loaded in a ScrollView in React-Native?

I have a ScrollView containing messages (most recent messages are further) in a chat application.
I limit the number of pre-loaded messages, and I dynamically load a new batch when the Scroll View is scrolled to the top. So when new messages are loaded, the current scrollPos is at 0.
The problem is that when the new messages arrive, the scrollPos stays at 0, so the user is teleported to the oldest newly loaded message.
I have tried to deal with it by manually scrolling back down to the position using the size of the content change, but this is not satisfying as the user sees a back and forth scrolling.
Can someone think of a way to do this so that the user does not see any change when the new messages appear an can simply gradually scroll up to see them.
I found a way to do it.
The idea comes from the Invertible Scroll View component: https://github.com/expo/react-native-invertible-scroll-view
I didn't use the component but implemented the idea directly on the Scroll View to have minimal changes in my code.
To explain, we translate vertically the Scroll View using the style of the Scroll View and transform: [{ scaleY: -1 }]. We do the same for the children. Then, we revert the order of the messages.
In that setup, the scrollPos() measures from the visual bottom. To trigger the loading of the new messagges, now I use
const isCloseToBottom = ({layoutMeasurement, contentOffset, contentSize}) => {
const paddingToBottom = 20;
return layoutMeasurement.height + contentOffset.y >=
contentSize.height - paddingToBottom;
};
The trick is that now, when the new messages appear on top, you have nothing to do as the distance from the user's point of view to the bottom does not change.
You can use the onContentSizeChange prop to scroll to the bottom anytime it detects a change in content size.
The scrollToEnd function may differ depending on RN version.
<ScrollView
...
onContentSizeChange={() => this.scrollView.scrollToEnd({animated: true})}>
</ScrollView>
Ref: https://reactnative.dev/docs/scrollview#scrolltoend

Owl Carousel is ignoring the items option

I'm having an issue with owlcarousel. When I use large images with items:1 everything works well and each slide contains 1 image. But when I use smaller images the items:1 option is ignored and the images display 4 per slide.
owlcarousel is version 2.3.4 as are the corresponding CSS files.
$(document).ready(function(){
$(".news-post-gallery").owlCarousel({
navigation : false, // Show next and prev buttons
autoplay:false,
items: 1,
loop:false,
margin: 10,
center: true,
nav: true,
navText: [
"<div>Left</div>",
"<div>Right</div>"
],
responsive:{
0:{
items:1,
}
}
});
});
My first guess is that this is a CSS issue. Mind you even the small images are not that "small", the large images that I used were like half my screen width.
Edit: navText is being ignored as well when small images are used.
The issue was another carousel being initialized targeting the owl-carousel class. This ended up initializing the one I needed with the wrong settings. The carousels initializations were coming from different templates so the result was only visible in the source once the page was loaded.
Adding $(...).owlCarousel('destroy'); before i initialized mine solved the problem.

How to keep bootstrap carousel paused until it enters in the viewport?

EDIT: reason for this request. This edit has been added when the solution has been found for the sake of describing my needs. I had a Carousel that showed a logical sequence step 1, step 2, step 3.. That carousel is not a top of page, so I want it to stay stopped / paused until the user sees it and when it will see it, as first, I want the user to see the first slide, step 1. Nevertheless, some users (and they are not few, believe me) don't know about carousels and sliders, so I don't wanna miss their view on the subsequent slides. This is the reason for what follow.
I'm wondering about this
I have a bootstrap 3.1 carousel that is not at top of the home page.
Instead you "reach it" when scrolling down some "bootstrap' rows".
Well I'd like it to keep the carousel stopped / paused until the user will scroll the page down to where the carousel is placed (let's say the carousel height is 500 pixel, when at least the first top 150 pixels are entered in the viewable area)
when those 150 pixel have been scrolled in, the pause / stop should turn to "play" and so, if the pause between each slide is 5000 msec, after 5000 msec the next slide should turn.
According with this solution it is matter of javascript but it is not what I'm seeking for also excuse me but currently I'm not so strong with javascript and jquery, so thank you for any hint with some explanation.
EDIT 01
This script looks to be the correct and also a great solution :-), especially reading the comments at bottom of that page, but as stated above, I miss the knowledge to properly take advantage of it, thank you for any hint.
Here's a method using Intersection Observer API; it will fail silently for IE and other unsupported browsers.
setTimeout(function() {
if (IntersectionObserver === undefined) return;
const carousels = $(".carousel");
if (carousels.length === 0) return;
const RATIO = 0;
// You can set a intersection percentage, such as 0.25 for 25% visible, but
// if you want pixels, I'm using `rootMargin` in the options below
var observer = new IntersectionObserver(function (entries, observer) {
entries.forEach(function(entry) {
jQuery(entry.target).carousel(entry.intersectionRatio < RATIO ? 'pause' : 'cycle');
});
}, {
root: null,
rootMargin: '-150px 0px', // 150px visible on top or bottom of viewport
threshold: RATIO
});
carousels.each(function () {
observer.observe(this);
});
}
});
I went for the long path, self answered myself.
I've tried several plugins, but they were not effective or either they were breaking the Carousel engine.
Researching so much, finally I've landed on this jQuery plugin
http://www.jqueryscript.net/other/jQuery-Plugin-To-Determine-If-An-Element-Is-In-the-Viewport-Viewport-Checker.html
It works pretty fine, straight and as expected and there is a bonus included: the offset I was seeking for!!! (yeeeh!)
Pretty easy to implement
<script src="viewportchecker.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$('.carousel').carousel('pause'); /** load page with carousel paused
$('.carousel').viewportChecker({
offset: 200, /** wait for the first 200 pixel of the element
to enter in the viewport
callbackFunction: function(elem){
setTimeout(function(){
$('.carousel').carousel(''); /** remove pause
},500);
}
});
});
</script>
"thank you" to myself :-)
I suppose this would also help the problem when the viewport cuts the carousel in half. ie: With a carousel at the top of the page and you scroll down, forcing the top of browser window to show only the bottom half of carousel.
Currently, when the carousel cycles, the carousel images load to the top of the viewport, not the top of the carousel container.
When you scroll back up, the carousel only displays half the image and the top half is grey. This is very annoying. Will try this to see if it fixes.

How to properly anchor popovers in Bootstrap 3x

If you look at the bootstrap demo that is hosted here And scroll down to the demo that has all 4 buttons. Now click on the left popover, it shows properly. However, When I shrink or extend the screen the popover is no longer anchored to the proper point. Is there a way around this?
This has to do with the container property for the popover.
http://jsfiddle.net/yvkhbw4b/1/
See the attached example. Show both popovers then resize the window from xs breakpoint to sm breakpoint. You will see the top item will seperate from the button as the container defaults to body. (I'm also setting it to body though options). The second item is attached to the parent div so that one remains attached to the element even though the breakpoint changed.
Documentation on popover options
Appends the popover to a specific element. Example: container: 'body'.
This option is particularly useful in that it allows you to position
the popover in the flow of the document near the triggering element -
which will prevent the popover from floating away from the triggering
element during a window resize.
$('#btn1').popover({
'container': 'body'
});
$('#btn2').popover({
'container': '.col-sm-12'
});
Potential Fix: you could add the following code. Currently only handles bottom aligned popovers but you can add options for other alignments.
$(window).resize(function () {
$('.popover.in').each(function () {
var el = $('[aria-describedby="' + this.id + '"]');
if ($(this).hasClass('bottom')){
$(this).css('top',el.offset().top + el.outerHeight(true));
}
});
});
http://jsfiddle.net/yvkhbw4b/2/

Fullscreen Panel overlay in Sencha Touch 1

I am trying to slide a Panel from the bottom, so that it covers the entire viewport, like the Bookmarks panel in iOS Safari. This is similar to the ActionSheet, but fulscreen, and without the dark frame around it.
this.advSearch = Ext.ComponentMgr.create({xtype: 'advanced_search', itemId: 'pnlAdvancedSearch'});
this.advSearch.autoRender = true;
this.advSearch.show({type: 'slide', direction: 'up'});
This sort of works, but the new panel doesn't fill the whole screen, and parts of it appear behind the background panel. I've tried various layouts, including fit, vbox, with varying degrees of ugliness, but the root problem seems to be that the panel doesn't know how tall it needs to be. Maybe because it doesn't have a container?
Any suggestions? Is this even the right approach, or should I try to hack the ActionSheet to expand to fullscreen, and show without the border?
Thanks.
Because your panel is floating (or I presume it is), you will need to give the panel a fixed height in Sencha Touch 1. You are very restricted in that respect. This following code should work:
var sheet = new Ext.Sheet({
html: 'hello',
style: 'color:#fff',
height: window.innerHeight,
stretchX: true
});
// replace this show with your animation
sheet.show();
As you can see, I give it a fixed height of the window and then stretch it on the X axis (y doesn't work).