PDA

View Full Version : Tab close, doesn't show previous tabs



rgraham
May 12, 2020, 1:39 AM
Hi All, or Fabricio,

We have a tab panel to which a user could add up to six or so tabs. In EXT 2.5.3, the previously viewed tab would automatically be displayed when a user closes a tab.

In EXT 5, when a user closes a tab, if it was a tab opened earlier, any tab opened later will be viewable. But if it was a tab opened later, when you close it, any earlier tabs cannot be seen. The tab itself is visible, but the content is not seen. I believe, by viewing the Dev tools, that the content is still loaded in the browser, but the ext code is not making it visible.

Again, open tab 1, then open tab 2. Go back to tab 1, then close it, tab 2 is visible in all its glory.
Open tab 1, then open tab 2, then close tab 2, tab 1 TAB is visible, but content is not visible.

How the tab panel is declared:

<body>
<ext:ResourceManager ID="ResourceManager1" runat="server"/>

<ext:Viewport runat="server" Border="false" Layout="Fit">
<Items>
<ext:TabPanel ID="mainTabPanel" Border="false" runat="server" >

</ext:TabPanel>
</Items>
<Bin>

</Bin>
</ext:Viewport>
</body>

How we add tabs (name and such are coming from a dataabase):


<script type="text/javascript">
var addTab = function (id, url, menuItem, title) {
console.log('url: ' + url);
var mainTabPanel = window.Ext.getCmp("mainTabPanel");
var tabitem = mainTabPanel.getComponent(id);

if (!tabitem) {
var tab = mainTabPanel.insert(mainTabPanel.items.length + 1, {
id: id,
title: title,
closable: true, border: false,
menuItem: menuItem,
loader: {
url: url,
renderer: "frame",
loadMask: {
showMask: true,
msg: "Loading"
}
}
});
}

mainTabPanel.setActiveTab(tab);
}
</script>

Appreciate your help!

fabricio.murta
May 12, 2020, 3:50 AM
Hello Bob!

I have tried to put together a sample given your description, using the shell code you provided and script you provided, and it works just right.

Scenario 1
1. Open tab 1 (made a button to call that client-side method you provided)
1.1. tab 1 opens with its contents shown.
2. Open tab 2 (made another button to call that method)
2.1. tab 2 opens, contents shown.
3. Click the tab 1 to switch back to it
3.1. tab 1 contents are displayed. the tab's handle is highlighted, to indicate it is the active tab.
4. Click the tab 1 "close" little button at top-right of the tab handle
4.1. tab 1 is dismissed, handle erased from tab panel;
4.2. tab 2 is selected, handle highlighted and contents shown.

So far I think it agrees with your description. Right?

Scenario 2
1. Open tab 1 (via that button)
1.1. tab 1 is displayed, contents included.
2. Open tab 2 (via that other button)
2.2. tab 2 displayed. Glory and all.
3. Close tab 2.
3.1. tab 2 is dismissed, handle erased from tab panel;
3.2. tab 1 is selected, handle highlighted and contents shown.

This is where I believe our scenarios diverge. I can't see the problem you described. Maybe you should try drawing an actual example with fake data to let us reproduce the scenario.

Overall, by your description and code, all looks right, I have no clue how have you reproduced the behavior you described.


tab 1 TAB is visible, but content is not visible.

Do I understand this? tab 1's handle is highlighted to indicate the tab is the active one, but the contents therein are but blank? I can't reproduce this, nevertheless. There must be something else missing. Please try to make a standalone example with the scenario you described. I'm sure you'd need to add something else in order to reproduce the behavior you described.

Looking forward to your follow-up.

rgraham
May 12, 2020, 5:10 PM
Hi Fabricio,

No, the initial tab does not have the "selected" appearance (See magnified screen grab).

I tried writing a script in the beforeClose event handler to set the previous tab to be the active tab. I could see that this worked as I stepped through the code, and I could see that this worked as I stepped through the code in the debugger (I could see the first tab clearly, though dimmed slightly by the browser due to being in debugging mode).

However, when I let the page's events continue on after the beforeClose event, the tab's contents became hidden again, and the tab's appearance was as in the screenshot. (There doesn't seem to be a way to delete the first attachment I uploaded???)

25335

Thanks, Bob Graham

fabricio.murta
May 13, 2020, 2:02 AM
Hello Bob!

Sorry, even with the screenshot I am not sure I understand how to reproduce this issue.

The dashed box around the tab name means a "focus" visual feedback some themes feature. You say the tab is getting the focus but it is not being effectively selected, right? I am honestly out of ideas; if you change the theme to "triton" do you get any hint on what's going on?

If you can wrap that behavior in a test case, please let us know; if we can reproduce the behavior we will be able to tell you exactly why it happens and how to properly overcome the issue. I tried making a simple test case here, but it simply works.

fabricio.murta
May 13, 2020, 3:00 AM
Just a little follow-up for your last post, Bob.

About your misuploaded file, the file should be deleted in one hour after it is uploaded if it is not posted/referenced in any post. So by now it should have been deleted already.

rgraham
May 13, 2020, 6:06 PM
Hi Fabricio,

Actually, the screenshot shows that the tab text is highlighted, but the tab itself is not in the "selected" state as the line below the tab should be "open" below that tab, instead it is a solid line.

I doubt that I could reproduce this in a simple sample, it is always my hope that the knowledge of the support personnel might include experience with a particular glitch. But I fully realize this may not always be the case.

AS far as using a workaround, I can make the tab and it's contents display properly by putting code to select it in the beforeClose event of the closing tab, but once I get past that line in debugging, it goes back into hiding. Some event after the beforeClose handler is causing the tab's selected state to go away and the content to be hidden. Curious that this only happens when closing a later tab and expecting an earlier tab to be shown.

I did find the way to eliminate the unwanted upload btw, it is done with a little delete "X" in the upper corner of the attachment list!

rgraham
May 18, 2020, 11:30 PM
Hi Fabricio,

Still banging my head on the wall here. I will try to assemble a test case to reproduce the problem, but, most of the time, problems that crop up in complex applications do not show themselves in simple test apps.

After looking at this some more, I see that the TabPanel is highlighting the handle of the tab it should display, but it actually shows the tab one higher in the tab order.

Meaning that when more than two tabs have been opened, if the focus was not on the last tab, there will not be a "blank content" situation.

Put in methodical description. Open Tab1, then Tab2, then Tab3. Now focus on Tab2. Next open Tab4. Finally close Tab4. Tab2 should become focused and visible. Instead, Tab2 gets it's focus highlight, but Tab3 has it's content visible and has the selected appearance (not the focused dashed line).

See illustration attached. "Purge Viewer" was the selected, visible tab. Then I opened a third tab. Then I closed the third tab and "Purge Viewer" should have become highlighted, selected and visible.

25337

Instead "Purge Viewer" is highlighted, but the NEXT tab is selected and visible. This shows that the reason I see the problem I do when closing the last tab, say Tab3, after Tab2 was the previously visible tab. It is putting the highlight dashed line on Tab2, but it is trying to make the NEXT tab visible, which is no longer in the tab group, hence the blank content situation.

Final comment in the blank content situation, the non-visible content is never actually gone, it is just not visible. Adding another tab and then going back to the blank tab always reveals its content is still there, and I can observe that the server was not called to re-fetch the content.

Somebody among the developers must be able to have a pretty good guess as to how we're having this classic "off-by-one" situation, or how to add a workaround.

Thanks again, especially for your patience!

Bob Graham

rgraham
May 19, 2020, 1:09 AM
Still digging,

Discovered the beforeshow event, which didn't help. Then I discovered the afterrender event.

The afterrender even fires just as expected, except if you close the last tab and the previously viewed tab was the next to last tab.

Heading home, but wanted to show you this screenshot before I leave so you will see it before I come in tomorrow morning.

Thanks, Bob Graham

25338

fabricio.murta
May 19, 2020, 4:18 AM
Hello Bob! I will try to answer by quoting some parts of your last two posts, hope it results in a clear response. :)


Still banging my head on the wall here. I will try to assemble a test case to reproduce the problem, but, most of the time, problems that crop up in complex applications do not show themselves in simple test apps.

Okay, I just hope you understand how difficult it is for us to help when we can't reproduce the issue. We can return some ideas but, that's kind of a "shoot in the dark", and it may become frustrating for both parties as the thread just gains pages, pages, and the issue does not get resolved. As long as you understand that we are doing our best to help you, all things considered, I guess that's alright.


Put in methodical description. Open Tab1, then Tab2, then Tab3. Now focus on Tab2. Next open Tab4. Finally close Tab4. Tab2 should become focused and visible. Instead, Tab2 gets it's focus highlight, but Tab3 has it's content visible and has the selected appearance (not the focused dashed line).

Okay, take a look at this animation I did (http://extnet.github.io/Ext.NET/forumIssues/6/2/62900-tabSwitching.gif). I tried to the best of my ability to precisely follow your step thru, and as a result, well, you can see it works just fine.


Discovered the beforeshow event, which didn't help. Then I discovered the afterrender event.

It didn't help... because it triggers at the time you have the issue raise, right?


The afterrender even fires just as expected, except if you close the last tab and the previously viewed tab was the next to last tab.

This makes sense. I mean, why should afterrender trigger if there's no component being rendered? There's a logic in the tabs that maybe you missed:
1. you create a tab, it gets rendered. afterrender fires as soon as Ext JS decides it should have already been rendered on screen.
2. you switch to another (existing) tab. afterrender is not fired, nothing is rendered; because the old tab is set to CSS-hidden whilst the switched tab is set to CSS-visible. No rendering takes place.

Even if a tab has a loader the tab itself does not need to be rendered even if you determined/programmed it to re-load its inner loaded content on show (and you'd be using an event to make it re-load every time it is switched to).

I'm sorry if the response is not really helpful. I genuinely can't reproduce the issue and with the information I could gather so far, it makes no sense for the tab not to be switched. I suspect there may be another client-side code (javascript) that used to work in 2.5 that is not working in v5, simply because it has hit a breaking change -- either a "supported and documented" breaking change, or a breaking change that doesn't get documented (common if any of your code hits private/"protected" Ext JS entitites).

I think you could decide on two approaches to reduce your page into the minimal set to reproduce the issue, and break through the issue in that chosen approach. Either 'top-down' by making an identical copy of the page and iteractively remove components or part of the code until you can't reproduce the issue; or 'bottom-up', from a simple bare page, gradually and selectively (as possible) add components of the real page until you reproduce it.

First thing you should check either way is, if there's any override you used to that page try to remove (or add) it first, as chances is that overrides are influencing how the page behaves.

You may also want to look for "rogue lefovers" from the v2.5 version, like some included javascript source (which could bring overrides), and also consider -- if you are using a master page -- if something may be coming from there. If you check sources in F12 developer tools in browser, you may check one by one of the actual referenced scripts in the final rendered page; maybe there's a rogue poking the code to give you that much headache.

Hope this (somehow) helps, that's all I can think about right now. Sorry for the very long answer.

rgraham
May 19, 2020, 5:12 PM
I appreciate the continued help Fabricio!

I am revisiting the logic to see what I may have missed. Since the beforeshow event does fire, I am looking to see if there's a way to intercept at this point and arbitrarily set the selected property, because, in the end, that's where something is breaking, as my screenshot shows, the focused tab and the selected tab are not the same. (Therefore, if the focused tab was the last tab, the afterrender event never fires because there is nothing to render).

It helps to have someone knowledgeable to talk back and forth with, and yes, I completely understand that you are powerless to directly point to a fix for an issue that is not a known issue and/or is not affecting most customers.

Do you have any code snippets that would properly show how to navigate the TabPanel's Tab collection and set the "selected" property programmatically?

I feel a bit lost here without some of the tools available for working with ExtJs since EXT.NET seems to be aimed at not delving into the ExtJs too much, and relying on the EXT.NET declarative markup more.

There is an "Inspector" tool available from Sencha, that is advertised at being free. But when I try to install it it wants me to have a JRE installed, which I prefer to avoid. Would this tool perhaps be helpful?

Thanks and I'll get back with more of what I find after troubleshooting more in the tab's before/after events.

We don't touch the tabs in our application other than the declaration of the tabpanel and the JavaScript method of adding tabs as seen in my original post. I'm left to wonder if there is something in the HTML/iFrame we are putting into the tab that is breaking the TabPanel's collection of tabs, or their ordinal values?

Bob Graham

rgraham
May 19, 2020, 8:17 PM
Hi Fabricio,

Hoping to catch you before end of day.

I set some console.log on the beforeshow and activate events. Something is causing them to fire twice, once with the correct tab to show (on closing another tab), and then both events fire a second time with the next tab higher in the ordinal count. (This only happens when closing a tab, not when switching tabs.)

So I decided to work on a workaround until we can figure out why this is happening. I have tried adding a sessionStorage value that basically says "skip me" and then a timeout that destroys that sessionStorage item a second later.

This is working to return false on beforeshow and activate but then the tabpanel crashes on setactivetab. The documentation seems to indicate that returning false on beforeshow cancels the event, but this doesn't seem to work in practice.

Is there a simple way to stop the tabpanel from processing the setactivetab? Overriding it looks scary, as it is a complex event that is probably part of a chain of events.

I have not successfuly located the reason why beforeshow and activate are getting called a second time. In fact, these are just symptoms of the tabPanel setting active tab twice, right?

I know I'm still asking you to work blindfolded, but I sure do appreciate your help!

Bob Graham

fabricio.murta
May 19, 2020, 8:20 PM
Hello again, Bob!


Do you have any code snippets that would properly show how to navigate the TabPanel's Tab collection and set the "selected" property programmatically?

Fiddling with a simple tab panel where I gave it the id mainTabPanel, I could get the list of IDs of the panels (that can be used to select the specific tabs) via:



App.mainTabPanel.getTabBar().items.each(function(t ab) { console.log(tab.card.id); });


This is what you can use to select a given tab via



App.mainTabPanel.setActiveTab(id);



I feel a bit lost here without some of the tools available for working with ExtJs since EXT.NET seems to be aimed at not delving into the ExtJs too much, and relying on the EXT.NET declarative markup more.

Yes, Ext.NET is meant to remove the burden of javascript and focusing in C#. But the possibilities with Ext JS are so many that even in our examples you will often find client-side code. Especially when you want (or need) to go "out of the box", you'd ultimately have to javascript to some extent. But it still makes life easier with many other possibilities from direct methods.

For instance, from the above code, code behind to get the list of tabs currently in a tab panel (first code block) is not really practical, as due to the nature of client-server communication in WWW you end up needing the client-side code anyway.

On the other hand, the server-side mainTabPanel.SetActiveTab(id) is pretty plausible. Given you know the ID of the tab you want to show; you can associate a bigger server-side code with it to, once finished, show the desired tab, without further wiring server-response-with-client-side-effect; so in this case you don't really need to know how to select tabs client-side -- if you know the ID and don't need to traverse the tab for present tabs you'd want to show.


There is an "Inspector" tool available from Sencha, that is advertised at being free. But when I try to install it it wants me to have a JRE installed, which I prefer to avoid. Would this tool perhaps be helpful?

I never used Sencha Inspector, and I don't really know how "free" it is; not sure it would mingle together with Ext.NET nicely or it'd require applications to be built fully in JavaScript, maybe with other Sencha tools, in order to be more useful.


I'm left to wonder if there is something in the HTML/iFrame we are putting into the tab that is breaking the TabPanel's collection of tabs, or their ordinal values?

I don't think that should be the case; at least an exception should have been thrown if that was the case, and you'd have been seeing red error messages blinking on your developer tool as you run the page with issues. Me not thinking it should be the case does not necessarily mean it is not the case, though. :)

Maybe this bit of information helps (if I am not just repeating this): more often than not, when reducing real-world cases to simple tests with Ext.NET-only code does not reproduce the issue, third party software is affecting the behavior. It could be other javascript libraries, NuGet packages, and also custom overrides or listener handlers. I see three outcomes of factoring a real-world code into a test case:

1. you find an issue with Ext.NET
2. you find an issue with code used to customize the component's behavior (that understandably worked in older versions)
3. you find an issue with third-party code

But at least you can isolate and demystify the cause of that "black magic preventing your code from working".

I didn't see anything "off" from your "add tab" client-side handler though. So -if- it was cause (2), there would be another code lurking somewhere.

Hope this helps!

rgraham
May 20, 2020, 7:25 PM
Hi Fabricio,

Some progress here. I changed the beforeshow event as below, to forcibly set the correct activeTab after it tries to set the active tab off-by-one to the right:

beforeshow: function (element) {
var tabToSet = sessionStorage.getItem('idShouldBeSet');
var titleToshow = sessionStorage.getItem('titleShouldBeSet');
if (tabToSet != null) {
console.log('Tab to set is: ' + tabToSet + ' Title should be: ' + titleToshow);
setTimeout(function () {
var mainTabPanel = window.Ext.getCmp("mainTabPanel");
mainTabPanel.setActiveTab(tabToSet);
debugger;
console.log(titleToshow + ', ID: ' + tabToSet + ' was set to active tab');
}, 850);
}
console.log('Show, Title: ' + element.title + ', ID: ' + element.id);
sessionStorage.setItem('idShouldBeSet', element.id);
sessionStorage.setItem('titleShouldBeSet', element.title);
setTimeout(function () {
sessionStorage.removeItem('idShouldBeSet');
sessionStorage.removeItem('titleShouldBeSet');
}, 500);
}
This works nicely to set the activeTab when previous active tab was 1, and you close tab 3 (prevents it from focusing tab 1 but selecting and displaying tab 2). Essentially I'm storing the tab to set in sessionStorage the first time beforeshow is hit, and then correcting the set tab 850 milliseconds later. This only happens if the sessionStorage is not null, and that sessionStorage is destroyed at 500 milliseconds.

However, still have an issue when there are only two tabs, it fails to make tab 1 visible when you close tab 2. This is our most significant scenario, very few users have permissions to access more than two functions and even more rarely would any user have three tabs open for any purpose.

I'm starting to wonder if the Button we're adding as our menu button in the TabPanel is causing this problem? (See original post.) It looks like and is positioned as a non-closable tab, though I haven't thoroughly looked at how it ends up in the object model.

Thanks, Bob Graham

fabricio.murta
May 20, 2020, 8:31 PM
Hello Bob!

This is just a guess by what you just said in the last post, but I believe you may be "barking at the wrong tree".

This issue shouldn't be happening in the first place, other existing tabs in a tab panel are correctly selected when the active one is closed, as I shown you in the animated-gif last post.

You should really really consider either factoring down the page (removing feature by feature until it works), or starting from a fresh one adding feature by feature until you notice the tab closing issue happen; then you'd be able to isolate which change is introducing the misbehavior and progressively pinpoint what the issue is.

As you said in one of the first posts, you don't know how to reproduce this issue outside the own page. So perhaps if you come afresh you'll just skip whatever triggered that issue in the new version.

There must be some code improperly adding a tab (so the tab panel could not know it still has a tab to display), or removing more tabs than it should when closing. Some code fiddling with the inner implementation of tab panel. This is what I believe to be the most likely thing to be happening there. So unless you get rid of that code, your page will not work properly. You'll keep hitting wall after wall and may end with a working but very slow page.

Hope this helps.

rgraham
May 20, 2020, 9:39 PM
Hi Fabricio,

I agree with all you are saying in principle. It's just quite hard to do in very large application with hundreds of pages of code.

Our first priority is to get this released as soon as possible. The fix above is reliable and doesn't cause a performance hit. I just need to figure out the "only two tabs" scenario.

I will keep this in mind for the day when I can delve back in to this solution with more time on my hands.

Thanks for all your help!

Bob Graham

fabricio.murta
May 20, 2020, 10:14 PM
Hello again, Bob!

Sorry for insisting with that and thanks for the feedback!

Use the App.mainTabPanel.getTabBar().items.each(function(t ab) { console.log(tab.card.id); }); command I shared two posts before this one and try to manually show (setActiveTab()) right when you reproduce the issue.

In case the tab still doesn't properly display, you may want to step thru setActiveTab() and compare what's different there in spite to a similar call to the panel you make before the issue is reproduced.

This may help you at least identify what's different between the working and broken scenarios, and possibly help figure out a way to circumvent the situation.

Hope this helps!

rgraham
May 21, 2020, 4:24 PM
HI Fabricio,

Sorry to make this the "everlasting thread" :-)

But it doesn't seem like the busiest forum, so I'm just trying to help you stay awake???

Trying your advice, can't figure out where I'm going wrong, or perhaps this is a useful clue?

There is no "card" property in the tab object:

25339

I'll start researching it myself, but I just wanted to hit you with the preliminary question as early as possible.

Thanks, your pain in the neck fiend, Bob Graham

rgraham
May 21, 2020, 5:28 PM
Hi again Fabricio,

I've noticed something of interest.

My temporary workaround for the wrong tab displayed is working beautifully. The hitch is that the tabpanel doesn't call all its events when only one tab exists. The beforeshow and activate events are never hit when adding the first tab or when closing a tab when only one tab will remain.

Is there a command to force the tabpanel to render()?

The ExtJs documentation is quite helpful on properties and events but less so on methods...

Thanks Again.

fabricio.murta
May 21, 2020, 8:03 PM
Hello Bob!


My temporary workaround for the wrong tab displayed is working beautifully. The hitch is that the tabpanel doesn't call all its events when only one tab exists. The beforeshow and activate events are never hit when adding the first tab or when closing a tab when only one tab will remain.

It would make sense to have the event called when creating the first tab. But there's more to it, I'll explain last.

In the other hand, beforeshow and activate events are being called when closing the "one before last" tab. If they are not triggering for you, then that's some custom/third party code affecting the panel's behavior.


Is there a command to force the tabpanel to render()?

Why, yes, App.mainTabPanel.render() (documentation entry (https://docs.sencha.com/extjs/7.2.0/classic/Ext.tab.Panel.html#method-render)).

beforeshow

Back to the beforeshow not triggering on first tab inclusion blocking your case, I am afraid that event is not supposed to be triggered when a component is rendered "initially not hidden". It needs to be rendered as hidden and then have its show() method called -- or render, hide and show.

For instance, if you create a simple page with a panel (not a tab panel), and give this panel a beforeshow event, it is not going to trigger if you render the panel not initially in the "hidden" state.

If you add the panel with hidden="true", then once you call its show() method, the event gets fired. Or, of course, if you hide and show it back.

But if we bring this hidden concept to Tab Panels, we hit some kind of design issue. Tab Panels work by hiding and showing panels in the same container (clicking through the tabs triggers hiding all panels and showing the panel corresponding to the clicked tab).

So by default, adding a panel to a tab panel adds it in hidden state (to keep current tab shown). Then you can call setActiveTab() to properly run its logic to show the desired tab. The problem lies when there's no tab and you add a panel. It should show at once. And that's why the panel is rendered as "not hidden" and the beforeshow event never fires.

If the beforeshow event is what you need to have it all working, what you can try to do is hide the whole tab panel until the first tab is added. Then -after- you add the first tab, you can call its show() method and have the event fire. But you probably want something else, maybe added (documentation entry (https://docs.sencha.com/extjs/7.2.0/classic/Ext.panel.Panel.html#event-added)).

Hope this helps!

rgraham
May 21, 2020, 9:40 PM
Hi Fabricio,

I found the remaining "symptom" of our problem. It was that, in the two tab scenario, closing the later one failed to remove the 'x-hidden-offsets' class from the final remaining tab.

So my modified beforeclose handler:


beforeshow: function (element) {
var tabToSet = sessionStorage.getItem('idShouldBeSet');
if (tabToSet != null) {
console.log('Tab to set is: ' + tabToSet);
setTimeout(function () {
App.mainTabPanel.setActiveTab(tabToSet);
var that = document.getElementById(tabToSet);
that.classList.remove("x-hidden-offsets");
}, 850);
}
sessionStorage.setItem('idShouldBeSet', element.id);
setTimeout(function () {
sessionStorage.removeItem('idShouldBeSet');
}, 500);
}

...And we are good!!! Tadaaaa!

Yes, we will do more analysis later to fix the cause rather than the symptom, but I wanted to share this before you go home for the day.

Thanks, Bob Graham

fabricio.murta
May 21, 2020, 10:55 PM
Hello Bob!

Great news! Glad you could find at least a way to get on rails with that issue. Seems our everlasting thread has come to a (temporary?) end!

Don't hesitate to let us know if there's anything else that you feel we can help with. Let us know also if you're done with this thread and we may mark it as closed.

EDIT: I was wondering if the thread wouldn't get to the third page, when I noticed this very post "turned it three".