Datepicker does not close

Datepicker does not close

rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

Hi, I am using the latest Editor version. When using more complex Editor pop ups with many fields and dependencies I get the problem that the date picker doesn't close after selecting a date. It just stays open, if I move the mouse away from the picker it might close after more than 10 seconds. The only way to close it is to hit the tab key.

Would you have an idea how to fix this? How can I force date picker to close when selecting a new date?

Answers

  • colincolin Posts: 15,112Questions: 1Answers: 2,583
    Answer ✓

    Hi @rf1243 ,

    We've not seen that problem - are you able to link to an example that demonstrates it please.

    Cheers,

    Colin

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

    I will need to set this up for you. Where should I send the credentials for log in etc.? Can't post them here.

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

    ok, will send it in a private message. Probably on Thursday this week.

  • allanallan Posts: 61,441Questions: 1Answers: 10,053 Site admin
    Answer ✓

    Send it on to me as a PM please. We are about to do a 1.9.1 release of Editor which changes datetime a little, so it might be worth trying that when its available.

    Allan

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

    ok, that was overlapping :smile: Will try 1.9.1 asap.

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406
    edited October 2019

    @allan
    I upgraded to the latest data tables release and to Editor 1.9.1. There was no change. I sent you my credentials etc in a private message.
    Roland

  • allanallan Posts: 61,441Questions: 1Answers: 10,053 Site admin
    Answer ✓

    Thank you for the link. I see the issue on your page - it looks like the click event is being cancelled by something before it can bubble up to the body element and close the input element.

    This is the code that Editor uses:

                $('body').on( 'click.'+namespace, function (e) {
                    var parents = $(e.target).parents();
    
                    if ( ! parents.filter( that.dom.container ).length && e.target !== that.dom.input[0] ) {
                        that._hide();
                    }
                } );
    

    The only way I was able to reproduce the error locally was to use:

    $('*').on('click', function (e) {
       return false;
    });
    

    to prevent the click event bubbling up.

    I'd suggest starting by looking for click event handlers with return false, or use stopPropagation() to stop bubbling.

    Allan

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

    Thanks Allan. Will try a few things and get back to you!
    Roland

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

    @allan
    I tried many things but nothing worked. Even deleting all the "preventDefaults()" etc. didn't work.
    I also noticed that the Editor code that should hide the widget when scrolling doesn't work for me either ... Any ideas?

    In this screenshot I marked everything that doesn't work for me.
    The only "hide()" that works is the one on "keydown" ...

  • allanallan Posts: 61,441Questions: 1Answers: 10,053 Site admin
    Answer ✓

    Its not working because there is something else on the page that it stopping the code for getting that far.

    I haven't dug into the code external to Editor, but those events just aren't happening (or rather that are being cut off).

    The way I'd approach debugging that myself is to start removing other plug-ins / libraries / event handlers on the page to see what is causing the issue.

    Alternatively start from a simple Editor example (since you can see it working on our example pages) and add the other plug-ins / libraries / event handlers you are using to, again, see which one is stopping the event from bubbling.

    Allan

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406
    edited October 2019

    Sounds really, really cumbersome. My page has become so complex that I'll probably do nothing (and ask the users to use the tab key if the widget doesn't close) or I'll make my own field type that shows the day of week right next to the date and has no widget.

    I noticed that most of my users will type in the dates anyway and not select them with the widget (and that is facilitated with date masking so they only need to type 19102019 instead of 19/10/2019 or 19.10.2019). What most people want to know is the day of week of the entered date to figure out whether they have accidentally picked a week end.

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

    @allan, I removed all of the code relevant for the new product one by one and tested it. No effect. The problem persisted. I was surprised. The problem only occurs when selecting the product "current account". All other products available on the same page work without issues.

    I also noticed further Javascript problems when working with "current account":
    - My tooltips in the Editor popup do not work any longer
    - after making a change the selection of the respective contract and the hiding of the unselected contracts does not work any longer.

    I will now remove all of the new code at once and then redo all of the 24 changes for the product one by one. Hopefully this will help.

    Is there any faster way?

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

    I removed all of the new Javascript code for the product: NOTHING improved. I am getting a little desparate with this stuff now. What could I do?

  • allanallan Posts: 61,441Questions: 1Answers: 10,053 Site admin
    edited October 2019 Answer ✓

    Sorry for the delay in getting back to you - I've been off for a few days.

    Looking in more detail I think I was wrong about the stopPropagation - apologies. The effect did look like that, but actually I think what is happening is that you've got an infinite loop on the page which is making the page run very slow and really hard to debug.

    Specifically you have:

                .dependent('fixed.first_repayment', function (val, data, callback) {
                    var self = contractFixedEditor;
                    setEditorFirstRepaymentRepaymentFreeMonthsDependencies(
                            self.field('fixed.first_repayment'),
                            self.field('fixed.repayment_free_months'),
                            self.field('fixed.repayment_method'),
                            self);
                })
    

    So if fixed.first_repayment changes value, then you dropping into that setEditorFirst... method which does:

    that.set( firstRepayment.name(), 0 )
    

    where firstRepayment is the fixed.first_repayment field. So its setting its own value, which is triggering the change event (it has to even although its actually the same value, since you are specifically calling the field().set() method) which calls the dependent method, which called setEditorFirst..., etc. That's killing the page and I think that's resulting in what you are seeing since the browser is taking so long to process the click.

    I've got an i7 processor in this computer and the fans spin up to max when showing that form, which is a good indication of an infinite loop as well.

    Regards,
    Allan

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

    Sorry, I lost track myself I am afraid; just saw your reply for the first time! Will check that out asap. There is a lot of dependencies on that page I know - and I have it on my to do list to remove them all and then add them all back and see what happens. The "dependent" feature is great: My clients recognize it as a great advantage over my competitor's more "static" user interface. My clients can do everything in one dialogue and aren't bothered with irrelevant fields and the like - but this great feature obviously has a price ... It's getting difficult for me to deal with the complexity it creates.

    Thanks @allan. Will get back asap.

    Roland

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

    WOW!!!
    @allan, I am impressed!!! Just got rid of that dependency and everything works like a charm!

    How were you able to identify that it was just this dependency causing the issue? Did you really check all of them? I have ".dependent" 43 times on that page which made me surrender to be honest ...

  • allanallan Posts: 61,441Questions: 1Answers: 10,053 Site admin
    Answer ✓

    When I recorded a JS trace on your page, it was that function that was being hit all the time (in the infinite loop) :).

    Allan

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

    @allan: This made me wonder:

    So its setting its own value, which is triggering the change event (it has to even although its actually the same value, since you are specifically calling the field().set() method) which calls the dependent method, which called setEditorFirst..., etc. That's killing the page and I think that's resulting in what you are seeing since the browser is taking so long to process the click.

    I thought it would "know" that the value hasn't changed and then not set it again. That's why I never worried about this. I will have to change all of my dependent checks and make sure I only set the value when it is actually required.

    The function in the code example above now looks like below. The functionality is the same; I had to add the empty checks for the fields though which inflates the code.

    .....................
    function setEditorFirstRepaymentRepaymentFreeMonthsDependencies( firstRepayment, 
                            repaymentFreeMonths, repaymentMethod, that ) {   
        var fRE = false; var rFME = false; 
        if ( firstRepayment.val() == 0 || firstRepayment.val() == '0,00' || firstRepayment.val() <= '-' ) {
            fRE = true;
        }
        if ( repaymentFreeMonths.val() == 0 || repaymentFreeMonths.val() <= '' ) {
            rFME = true;
        }
        
        if ( repaymentMethod.val() === 'N' ) { //repayment only at the end  
            if ( ! fRE ) {
                that.set( firstRepayment.name(), 0 )  //we can't have a deviating first repayment here
            }
            that.hide( [firstRepayment.name()] ); 
            if ( ! rFME ) {
                that.set( repaymentFreeMonths.name(), 0 );  //we can't have repayment Free months here
            }
            that.hide( [repaymentFreeMonths.name()] );
        } else {
            if ( ! rFME )  { //repayment free months is not empty
                if ( ! fRE ) {
                    that.set( firstRepayment.name(), 0 )  //we can't have a deviating first repayment here
                }
                that.hide( [firstRepayment.name()] );
            } else {
                that.show( [firstRepayment.name()] );
            }
            if ( ! fRE )  { //first repayment is not empty
                if ( ! rFME ) {
                    that.set( repaymentFreeMonths.name(), 0 ) //we can't have repayment Free months here
                }
                that.hide( [repaymentFreeMonths.name()] );
            } else {
                that.show( [repaymentFreeMonths.name()] );
            }
        }                                                   
    }
    

    Is there an easier way to do this? If not I will have to add the empty checks to all of my dependency checks.

    I also found out why the problem only occurred with the product "current account": It has no regular repayments. Hence the code got triggered in an endless loop while with other products the problem was minor: An endless loop could also have been triggered but it was later in the process so that it basically went unnoticed.

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

    When I recorded a JS trace on your page, it was that function that was being hit all the time (in the infinite loop) :).

    I feel a bit ashamed, @allan. I am obviously not smart enough to do this myself ... Just googled to figure this out but didn't find anything useful. Then tried
    chrome://tracing and selected "Javascript and rendering". It did something but I was completely unable to understand any of the results ...

    Can you point me in the right direction on how to do this myself please.

  • allanallan Posts: 61,441Questions: 1Answers: 10,053 Site admin
    Answer ✓

    I thought it would "know" that the value hasn't changed and then not set it again

    I wondered about that as well when I saw what had happened. Honestly, I'm not sure - it is explicit setting the value through the field().val() method, so it feels right that the changed event should trigger, but also its not actually changing the value, so on the other hand it shouldn't trigger.

    I'm not going to change it at the moment as this is the first time I've encountered this I think, but it is something I'm aware of now and will keep an eye on!

    I am obviously not smart enough to do this myself ...

    Pfft. I just don't have a life :). This is a good introduction to profiling Javascript in Chrome. [This also looks useful]https://developers.google.com/web/tools/chrome-devtools/rendering-tools).

    Interpreting the results however, is perhaps a different story! The best thing to get used to it is trigger a known action - e.g. submit an Editor form, while recording a profile and then inspect it to see the code pattern that was executed. It just takes time to get used to doing that kind of thing. I guess I have the "advantage" of spending so much time debugging :).

    Allan

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

    Hi Allan, thanks for the hints regarding Javacript tracing! Your support is excellent as always!

    I thought about this for a while:

    I wondered about that as well when I saw what had happened. Honestly, I'm not sure - it is explicit setting the value through the field().val() method, so it feels right that the changed event should trigger, but also its not actually changing the value, so on the other hand it shouldn't trigger.

    I would strongly agree to your words in italics: In my opinion the "changed" event should only trigger if something was changed in its content and not if it stayed the same even though its content was overwritten with an identical value! "Changed" must not mean it was NOT changed content wise. Otherwise I will have to live with my work around which is: Avoid setting a field if the value of the field is already the desired value.

    This will massively inflate my code! Think about this code with an individual check of each and every field on whether or not it already has the desired value ... 17 additional "if" statements etc.

    It would be great if you could think it over, Allan. I am also willing to do a hack until you are ready to integrate this into a regular Editor release - if you could tell me where I would need to put it. Thank you!

    var selected = table.row( {selected: true} );
    var instrument = '';
    if (selected.any()) {
        if (typeof selected.data().contract !== 'undefined') { // coming from contract
            instrument = selected.data().contract.instrument;      
        } else {  //coming from proposal
            instrument = selected.data().proposal.instrument;  
        }
        if (instrument === 'Y') {   //current account
            that.show( ['fixed.first_payment_date',
                        'fixed.payment_frequency', 'fixed.fee_schedule'] )
                .set( { 'fixed.fixed_interest_amount': 0, 
                        'fixed.repayment_method': 'N',
                        'fixed.deviating_repayment_schedule': 0,
                        'fixed.repayment_frequency': '',
                        'fixed.first_repayment_date': '',
                        'fixed.repayment_percent': '',
                        'fullRepayment': 0,
                        'fixed.first_repayment': '',
                        'fixed.repayment_free_months': '',
                        'fixed.installment': 0, 'fixed.price': 0,                     
                        'fixed.ref_rate': '', 'fixed.ref_rate_period': '',                        
                        'fixed.spread': 0, 'fixed.fra_end_date': '',
                        'fixed.fixing_rule': '', 'fixed.calc_rate_guarantees': '' } )
                .hide( ['fixed.fixed_interest_amount', 
                        'fixed.repayment_method',
                        'fixed.deviating_repayment_schedule',
                        'fixed.repayment_frequency',
                        'fixed.first_repayment_date',
                        'fixed.repayment_percent',
                        'fullRepayment',
                        'fixed.first_repayment',
                        'fixed.repayment_free_months',
                        'fixed.installment', 'fixed.price',              
                        'fixed.ref_rate', 'fixed.ref_rate_period',
                        'fixed.spread', 'fixed.fra_end_date', 
                        'fixed.fixing_rule', 'fixed.calc_rate_guarantees'] )
        }
    }
    
  • allanallan Posts: 61,441Questions: 1Answers: 10,053 Site admin
    Answer ✓

    To put in a hack workaround, search the Editor code base for _triggerChange() - that's the method that is called internally when a field value "changes". You'd need to put a condition around the calls to that method.

    I've filed a bug for this internally (DD-1210) - if we put it in, it will be the next major version of Editor (1.10?! don't know yet...!) since it could be a breaking change.

    Allan

  • allanallan Posts: 61,441Questions: 1Answers: 10,053 Site admin
    Answer ✓

    p.s. Thanks for the feedback and your thoughts on this!

  • rf1234rf1234 Posts: 2,801Questions: 85Answers: 406

    @allan: Has this been fixed in the latest Editor version?

    I came across the issue again, but I am still using Editor 1.9.3

    This is my work around making sure I only make the fewest possible changes to the Editor fields avoiding any "unnecessary" change if the field value hasn't changed.

    I use global variables to make sure I only update the select field options if they have changed.

    What does this do? I have three planning levels in a certain report (not in all other reports.) The user can pick between 1 and 3 of them. Options and visibility need to be adjusted dynamically depending on how many levels the user chooses and what option for each level.

    As you can see the code is unnecessarily inflated because I have to make sure that no editor field setting is done if the field value hasn't changed.

    var ploSavedLevel_1 = planningLevelOptions.slice(); //shallow copy of array of objects
    var ploSavedLevel_2 = planningLevelOptions.slice();
    
    editor
        .dependent(['report.report_type_id',   'report.planning_level_1', 
                    'report.planning_level_2'], function (val, data, callback) {    
            //make sure we do as few field settings as possible due to Editor issue
            //when too many field updates!
            var eraseHidePl_1 = true;
            var eraseHidePl_2 = true;
            var eraseHidePl_3 = true;
            var rptTypeId = this.val('report.report_type_id');  
            if (rptTypeId > '') {            
                var reportTypeLabel = $.grep(serverReportTypeOptions,                 
                        function(obj){return obj.value == rptTypeId;})[0].label;
                var reportTypeNumber = parseInt(reportTypeLabel.substr(0, 2));
                if (this.val('report_type.number') != reportTypeNumber) {
                    this.set({'report_type.number': reportTypeNumber});
                }
                if ( reportTypeNumber === 4 ) { //budget planning with accounts
                    eraseHidePl_1 = false;
                    this.show(['report.planning_level_1']);
                    if ( this.val('report.planning_level_1') > 0 ) {
                        eraseHidePl_2 = false;
                        var plo = planningLevelOptions.slice(); //shallow copy of array of objects
                        var i;
                        for (i=0; i < plo.length; i++) {
                            if ( plo[i].value === this.val('report.planning_level_1') ) {
                                plo.splice(i, 1);
                                break;
                            }
                        }
                        if ( plo != ploSavedLevel_1 ) {
                            this.field('report.planning_level_2').update(plo);
                            ploSavedLevel_1 = plo.slice();
                        }
                        this.field('report.planning_level_2').show();
                        if ( this.val('report.planning_level_2') > 0 ) {
                            eraseHidePl_3 = false;
                            for (i=0; i < plo.length; i++) {
                                if ( plo[i].value === this.val('report.planning_level_2') ) {
                                    plo.splice(i, 1);
                                    break;
                                }
                            }
                            if ( plo != ploSavedLevel_2 ) {
                                this.field('report.planning_level_3').update(plo).show();
                                ploSavedLevel_2 = plo.slice();
                            }
                            this.field('report.planning_level_3').show();
                        }
                    }
                }
            }
            //avoid too many field updates due to Editor bug
            if ( eraseHidePl_1 ) {
                if (this.val('report.planning_level_1') != 0) {
                    this.set({'report.planning_level_1': 0});
                }
                this.hide(['report.planning_level_1']);   
            }
            if ( eraseHidePl_2 ) {
                if (this.val('report.planning_level_2') != 0) {
                    this.set({'report.planning_level_2': 0});
                }
                this.hide(['report.planning_level_2']);   
            }
            if ( eraseHidePl_3 ) {
                if (this.val('report.planning_level_3') != 0) {
                    this.set({'report.planning_level_3': 0});
                }
                this.hide(['report.planning_level_3']);   
            }
        })
    
  • allanallan Posts: 61,441Questions: 1Answers: 10,053 Site admin
    Answer ✓

    Hi Roland,

    Unfortunately, no - this one didn't make it into Editor 2. However, reading over it again I think your suggest is the correct thing to do and I've increased the priority of the issue. It will be fixed in the next release of the DateTime plug-in (which has been split out from Editor now).

    Allan

This discussion has been closed.