Showing a window breaks multiple functionality on close

  1. #1

    Showing a window breaks multiple functionality on close

    Hi Fabricio,

    I have code that shows a window, and where the close event runs, there is an error I will show below. After that error, any attempt to re-show this window shows a blank window with only a slightly corrupted "Close" button at top left.

    Here is how the window is instantiated, including the definition of the tree control from which it originates:

    Ext.define('Paramit.view.tree.ProductTreeController', {
        extend: 'Ext.app.ViewController',
        alias: 'controller.bom-tree',
    
        requires: [
            'Paramit.store.PartClass',
            'Paramit.store.PartType',
            'Paramit.view.part.PartWindow',
            'Paramit.view.part.PartImport',
            'Paramit.view.part.costing.CostImport',
            'Paramit.view.part.FileUploadWindow',
            'Paramit.view.part.FilesWindow',
            'Paramit.view.octoPart.PartOcto',
            'Paramit.view.part.revision.RevisionForm',
            'Paramit.view.buyPartList.BuyPartList',
            'Paramit.store.OctoPartPriceList',
            'Paramit.view.po.poGrid',
            'Paramit.view.part.ItemChanges',
            'Paramit.view.editBom.BomTree',
            'Paramit.view.part.partIssues.PartIssueWindow',
            //'Paramit.view.part.costing.editCostWindow'
    
    
        ],
    	...
    	
    	showTaskWindow: function () {
            let view = this.getView(),
                theItem = this.getView().selection;
            let partNo, revision;
    
            if (theItem) {
                partNo = theItem.get('partNo');
                revision = theItem.get('revision');
    
                this.winTask = view.add({
                    xtype: 'part-issue-list',
                    height: Ext.getBody().getViewSize().height * 0.9,
                    width: Ext.getBody().getViewSize().width * 0.8,
                    renderTo: Ext.getBody(),
                    title: 'Task for Part# ' + partNo + (revision ? '  Rev: ' + revision : ''),
                    viewModel: {
                        links: { theItem: theItem }
                    },
                    listeners: {
                        close: function () { /*Ext.getCmp('btnRefresh').click();*/
                            //var taskCount = this.getOpenTask(theItem.get('itemId'));
                            Ext.Ajax.request({
                                url: '../../api/bom/opentask?itemId=' + theItem.get('itemId'),
                                method: 'GET',
                                async: false,
                                scope: this,
                                success: function (response) {
                                    result = Ext.JSON.decode(response.responseText);
                                    var taskCount = result.data;
                                    theItem.set('taskStatus', taskCount);
                                },
                                failure: function (err) {
                                    Ext.Msg.alert("Error", err);
                                }
                            });
                         
                            this.destroy();
                        }
                    }
                });
    
                this.winTask.center();
                this.winTask.show();
            } else {
                Ext.Msg.alert('Error', 'No part was selected');
            }
    
    
        },
    The form shows and functions correctly, it's when it closes that things go wrong, specifically after the call to "this.destroy()."

    After calling that, it goes wrong somewhere after this line in the ext.axd files:
    Click image for larger version. 

Name:	Where it goes wrong.png 
Views:	74 
Size:	24.6 KB 
ID:	25384

    And then errors out at this removeListeners function:
    Click image for larger version. 

Name:	What goes wrong.jpg 
Views:	71 
Size:	88.3 KB 
ID:	25385

    Interestingly, the "m" parameter when calling the removeListener event is undefined. This seems like it could be the culprit.

    After that, any effort to show this window again only shows the corrupted version, and, more strangely, the tree view from which the "Tasks" window was opened no longer has a functioning context menu. I have tried setting "winTask" to undefined when reloading the window and also setting winTask.managedListers to [], but neither of these ideas worked to allow reshowing the window and, in any case, the right-click menu of the parent tree view is still broken.

    Apparently the tree view had its events damaged along with the Tasks window.

    Obviously, this is not somewthing I can reproduce in a sample app, we will need to troubleshoot and fix it in the actual app as we have done thus far with the other issues.

    I'm pretty sure that this is an issue somewhere in a deprecated method call that worked fine in EXT 4.2.

    I know I don't give you easy stuff to fix! My apologies!

    Thanks, Bob Graham

    For your information, below is the definition of the "part-issue-list" xtype referenced in the showTask function:

    Ext.define('Paramit.view.part.partIssues.PartIssueWindow', {
        extend: 'Ext.window.Window',
        xtype: 'part-issue-list',
        alias: 'widget.part-issue-list',
    
        requires: [
              'Paramit.view.part.partIssues.PartIssueController',
              'Paramit.view.part.partIssues.PartIssueCreate',
              'Paramit.model.PartIssue',
              'Ext.layout.container.VBox',
              'Paramit.view.part.partIssues.RelatedIssue'
    
        ],
    
        controller: 'part-issues',
    
        height: Ext.getBody().getViewSize().height * 0.8,
        width: Ext.getBody().getViewSize().width * 0.8, 
        layout: 'fit',
        closable: true,
        maximizable: true,
        modal: true,
        
        items: [{
    
            xtype: 'tabpanel',
            id:'tbTask',
            items: [{
                xtype: 'panel'...
  2. #2
    Hello Bob!

    As far as I can understand, you should only call destroy() to the 'part-issue-list' xtype once the callback is run. So you probably want to move the destroy() call to within the Ext.Ajax.request()'s success, failure or callback if it should always be destroyed.

    If using callback, double-check whether it runs before or after the success and failure ones; if it runs after, there should be no issue; if it is run before, then you may need to Ext.defer() the destroy() call.

    Quote Originally Posted by rgraham
    I have code that shows a window, and where the close event runs, there is an error I will show below. After that error, any attempt to re-show this window shows a blank window with only a slightly corrupted "Close" button at top left.
    This usually happens when javascript throws an exception before layout is run for the component (or whole page); so upon solving the js issue and letting the script run to its completion, you should have the page show nicely as it would.

    Note: the window should handle its destroy() call by itself, and at the right time. Destroy logic has changed significantly since Ext.NET 2, and even between Ext.NET 4 releases, and so far it proved to the better; so you probably want to give the window extension's Ext.window.Window.closeAction config option a try. Probably all you need is to completely remove the destroy() call from your code, as the default is to destroy when closed. Instead this.callParent(arguments) should do everything you need to consistently close the window.

    Hope this helps!
    Fabrício Murta
    Developer & Support Expert
  3. #3
    Hi Fabricio,

    Thanks for your reply.

    I'm still trying to wrap my head around this.

    If I remove the this.destroy() command from the showTaskWindow function, the problem is just moved to when I try to reshow the window, rather than when the Task window is closed.
    With the destroy() call removed, the context menu on the tree control remains functional until I try to re-show the window a second time. Commenting out the entire listeners -> close function from the showTaskWindow leaves me with the identical error. The error without the destroy call is identical to before, with b.fireFn within removeListener being "undefined."

    Click image for larger version. 

Name:	What the menu looks like.jpg 
Views:	55 
Size:	77.6 KB 
ID:	25386

    Are you recommending that I add a close action to the part-issue-list Ext.window instead of in the tree controllers's showTaskWindow function? How would that look?

    closeAction: 'destroy' ?
    OR 
    closeAction: function(){
        this.destroy();
    }
    Excuse my ignorance, building this functionality within these ExtJs "classes" is still very unfamiliar to me. The previous project I worked on used mostly EXT.Net declarative syntax with method calls to straightforward JavaScript functions.

    The documentation for both EXT.Net and ExtJs is lacking in clear example code.

    Where and how would I use a defer function? This is basically like a JavaScript setTimeout function right? Just alllows you to leave a time gap for other things to complete before your action is carried out...

    Your next reply will probably get me on track to a solution!

    Thanks, Bob Graham
  4. #4
    Hello @rgraham!

    I will quote some parts of your response and respond to them, in an attempt to be clear.

    Quote Originally Posted by rgraham
    If I remove the this.destroy() command from the showTaskWindow function, the problem is just moved to when I try to reshow the window,
    If you want window with closeAction="destroy" you won't be "re-showing" it. You need to make it once again. When you destroy() things they are destroyed beyond reuse.

    If you want just to hide it, then you'd want a corresponding closeAction and perhaps tweak its hideMode setting.

    Quote Originally Posted by rgraham
    ... rather than when the Task window is closed.
    And this makes sense to me. See, if you are calling destroy() too early on something during its "close" process, it is expected to trigger issues just because e.g. Ext JS still wanted to traverse the component to see if it had anything else within it to cascade-destroy (this would avoid memory leaks!).

    Then if you destroy() it at the right time, no issue. But if you kept a reference of the window object, it will become something full of undefined all around if not awhole. Then if you tried to reference this destroyed object later (to "re-show" the component) it is... well, bound to break the code.

    Quote Originally Posted by rgraham
    Are you recommending that I add a close action to the part-issue-list Ext.window instead of in the tree controllers's showTaskWindow function? How would that look?
    No, I am not recommending that, I simply can't say it is or is not the case the close action should be here or there.

    Quote Originally Posted by rgraham
    Excuse my ignorance, building this functionality within these ExtJs "classes" is still very unfamiliar to me. The previous project I worked on used mostly EXT.Net declarative syntax with method calls to straightforward JavaScript functions.
    Yes, the code you shared looks very client-side, ExtJS-reliant. While it is not a problem for us to provide support to Ext JS client-side code, it is just that I can't piece the jigsaw together to tell you exactly what you need there. I can just provide generic insight on how things should work, and tip why it worked before but not now (because the way destroy() works changed since earlier versions, even thru Ext.NET 4.x).

    Quote Originally Posted by rgraham
    Where and how would I use a defer function? This is basically like a JavaScript setTimeout function right? Just alllows you to leave a time gap for other things to complete before your action is carried out...
    Yes, it is like a setTimeout; it is just embellished with Ext JS features for further integration and ease-of-use. I can't tell exactly where you should use it in your case, or even if that's the case; it is up to understanding the scenario and applying the code if you really have a reason to destroy the components "manually", and just need the current "close" event to finish. Take a look at its definition linked in the last post, understanding it might help; if not now, in the future.

    Quote Originally Posted by rgraham
    Your next reply will probably get me on track to a solution!
    Well, I hope you are right! :) Not that I didn't try though.

    Hope this helps!
    Fabrício Murta
    Developer & Support Expert
  5. #5
    Hi Fabricio,

    New approach to locating bug.

    Here is a diagram of the structure between our main panel and the child window that breaks things:

    Click image for larger version. 

Name:	Basic diagram of app.jpg 
Views:	74 
Size:	93.3 KB 
ID:	25387

    Note the orange text in fourth block, where I have effectively detached the "Task" popup window from its controller, and also removed everything from the window except its two panel headers.

    This yields a window like this:

    Click image for larger version. 

Name:	Task window.png 
Views:	52 
Size:	14.4 KB 
ID:	25388

    With these "disabling" changes, I can show and hide the window as many time as I like, and it continues to function. Also the context menu in the top level Tree continues to work properly.

    Can I conclude from this test that the problem lies between the "part-issues" window and its controller?

    The only thing that mystifies me is how misbehavior in the "part-issues" window causes the context menu of the Tree to become broken. Perhaps this is just because the entire event model of the app is compromised.

    Hope you have input based on this simplified diagnostic of the issue!

    Thanks, Bob Graham
  6. #6
    Hi Fabricio,

    After much hair-pulling and frustration, I found one line of code several controllers downstream of where I was looking before that seemed to have been causing the problem.

    Ext.define('Paramit.view.project.ProjectIssuesController', {
        extend: 'Ext.app.ViewController',
        alias: 'controller.ProjectIssuesController',
    
    
    
    
        listen: {
            controller: {
                "*": {
                    "loadProjectIssues": function () { console.log("tab selected project issue"); this.loadData() }//,
                    //"loadDashboard": 'loadProjectIssues',
                }
            },
            component: {
                "project-issues": {
                    'selectionChange': function (view, records) {
                    },
                    'itemdblclick': function (grid, record, item, index, e, eOpts) {
                        this.editTasks(record);
                    }
                }
            }
        }
    It's the commented-out line with "loadDashboard." Of course, I have little idea what this syntax is doing, but the app seems to work fine without it. I will do more validating tomorrow, but I wanted to see what you thought of this strange syntax (if you un-comment the offending line).

    Thanks, Bob Graham
  7. #7
    Hello Bob!

    The client-side "model-view-controller" paradigm applied in the code you are debugging is not really something we use while with Ext.NET is concerned. There use of this concept makes more sense in a "standalone Ext JS" scenario rather than when Ext.NET is used.

    Either because the concept is not really pertinent to someone developing ASP.NET WebForms projects, and when one is in ASP.NET MVC world, well, another "MVC" layer may become confusing. Notwithstanding, if I am not mistaken, this concept was introduced after Ext.NET design was outlined back in Ext JS 3.x. Introduced in Ext JS 4.x, this view-controller apparatus was not integrated in Ext.NET.

    So, our ability to help with that will be somewhat limited simply because it is not part of our everyday code exercise with Ext JS.

    That said, aside the fact we can't have the so-called test cases just aggravates how limited we are to try to effectively help you. That said, again, the points made below may be off, but we won't just ignore it, and I will do my best to give you appropriate directions.

    I believe having a good look at the documentation of Ext.app.ViewController might help if you didn't so yet. I am not really familiar with the listen and "*" keywords but the documentation above suggests by commenting the loadDashboard event, you are just preventing the code of loadProjectIssues function to run. So the problem may not really be in the controller definition, and the event probably just references to the problematic window after it is destroyed -- because the windows' own event destroys it before that custom event is triggered.

    This makes sense as between Ext.NET 4 and 5. Actually -- if I recall well -- it was an unfortunate breaking change introduced by Sencha introduced between Ext.NET 4.x rollups. The change consisted in a review of event firing that -- initially harmless -- could break scenarios where exact timing were imprescindible. In other words, some events started to fire too early and others could fire too late; and the only way into fixing that would be changes in the logic of the affected project. Often it was possible to overcome the issue just by using what's already exposed by Ext JS, like the parameter it passed to the listener's handler instead of directly referencing components throughout the page scope... Long story short: some issues arose, but usually they were easy to fix.

    So I believe you should compare what changed in the environment at the point the exception is raised, with how it was in the previous Ext JS version the project used to work well with. There was a change where all components' destroy() method was changed to a "private" doDestroy() one, and this is very likely to be related to the issues you are getting, although it would be more probable a memory leak would happen instead of an "early object nullifying" event like you are facing.

    In the post before last, you shown a new debugging approach and asked:

    Quote Originally Posted by rgraham
    Can I conclude from this test that the problem lies between the "part-issues" window and its controller?
    I can't really tell you can conclude that -- or can't. It makes sense, as if you remove a code that references to its controller, and then it works. But later you shown that listener. Well, the listener -is- in the controller, so it would be effectively part of it, then you could say "yes". But it is not really the controller that's broken, it is code activated by the controller when it wires up an event handler for the page.

    If you commented that event handler and it worked, then I believe you'd best uncomment it, and then dive in the handler and get where exactly it fails.

    Bottomline, it still looks to me the window's destroy logic has to change. Or maybe, the moment that breaking event fires should be adequated to match how early (or late) it should take place.

    I'm sorry this doesn't really help, but I hope by luck -- or fate -- some of this information shed some light into your problem. Well, if you feel like reading, that is. :)
    Fabrício Murta
    Developer & Support Expert

Similar Threads

  1. Replies: 7
    Last Post: Jan 20, 2015, 6:06 PM
  2. Replies: 1
    Last Post: Apr 11, 2014, 4:42 PM
  3. Replies: 0
    Last Post: Oct 24, 2012, 12:20 PM
  4. Replies: 1
    Last Post: Apr 01, 2009, 12:24 PM
  5. Replies: 3
    Last Post: Jun 24, 2008, 12:32 AM

Posting Permissions