Sencha Touch: Clicking a button rapidly will push a view twice

旧巷老猫 提交于 2019-12-22 10:55:27

问题


Say I have a button that triggers a push of a new view. I noticed that if I click it more than once, fast enough, it will push the same view twice.

You can mimic this behavior using their official docs on this page, where they have a live sample: http://docs.sencha.com/touch/2-0/#!/guide/navigation_view

the clear question is, simply how to prevent it?


回答1:


Masking successfully prevents double tapping problem.

In my code I'm using two functions for mask/unmask navigation container:

/**
 * Mask container with rolling wheel. Usually need if Ajax-request is sent to the server and app waiting for response
 * Best practice is masking the current navigator container, to prevent blocking whole app. Method warns if no container
     * is defined. In some cases warning could be suppress with parameter
     *
     * @param container
     * @param {boolean} [suppressWarning]
     */
    startLoading: function(container, suppressWarning) {
        var loadingComponent = container;

        if (!loadingComponent) {
            // <debug>
            if (!suppressWarning) {
                console.warn('Please define navigator container for non-blocking operation, or define suppressWarning parameter');
            }
            // </debug>
            loadingComponent = Ext.Viewport;
        }

//      var lastMaskedContainer = container;
        this.lastMaskedContainer = container;

        loadingComponent.setMasked({
            xtype: 'loadmask',
            message: 'Loading...'
        });

/*
        Ext.defer(function() {
            lastMaskedContainer.setMasked(false);
        }, Pipedrive.app.maskingTimeout * 1000)
*/
    },

    /**
     *
     * @param {Ext.Container} container
     * @param {boolean} [suppressWarning]
     */
    stopLoading: function(container, suppressWarning) {
        var loadingComponent = container;

        if (!loadingComponent) {
            // <debug>
            if (!suppressWarning) {
                console.warn('Please define either navigator container for non-blocking operation, or define suppressWarning parameter');
            }
            // </debug>
            loadingComponent = Ext.Viewport;
        }

        var alreadyMasked = loadingComponent.getMasked();

        var lastMaskedContainer = this.lastMaskedContainer;
        if (!alreadyMasked && !suppressWarning) {
            // <debug>
            if (lastMaskedContainer != container) {
                console.warn('Found Start/Stop Loading inconsistency. Please revise code'
                    + (container ? '. Container: ' + container.getId() : 'Ext.Viewport')
                    + (lastMaskedContainer ? ', last masked container: ' + lastMaskedContainer.getId() : '')
                );
            }
            // </debug>
            loadingComponent = Ext.Viewport;
        }
        loadingComponent.setMasked(false);
    }

than in the tap handler:

onDealDetailsTap: function(ct) {
    console.log('onDealDetailsTap', ct);
    var form = ct.getReferenceForm(),
        navigatorContainer = this.getNavigatorContainer(form),
        model = form.getRecord();

    UiHelper.startLoading(navigatorContainer);
    Ext.Viewport.fireEvent('detailfields', {
        title: model.get('title'),
        id: model.get('id'),
        store: 'DealFields',
        navigatorContainer: navigatorContainer
    })
},

to cleanup the loading mask:

control : {
    activitiesContainer: {
        push: 'onPushActivitiesContainer'
    },




onPushActivitiesContainer: function(ct) {
    //console.log('onPushActivitiesContainer', ct);
    UiHelper.stopLoading(ct);
},

especially it is cool for waiting for long-timed ajax requests....

Cheers, Oleg




回答2:


Another method is to check what the active view is, and only push if it is not the same as the view you are about to push. I've tested this and it works.

E.g.

if (this.getNavigationView().getActiveItem().xtype != "someView") {
    this.getNavigationView().push({ xtype: "someView" });
}



回答3:


Extending jayteejee's answer, I've overridden the push method in a custom navigation view, like this:

Ext.define('BT.navigation.View', {
   extend: 'Ext.navigation.View',
   xtype: 'btnavigationview',

   push: function (view) {
      if(this.getActiveItem().xtype != view.xtype)
         this.callParent(arguments);
      else
         console.warn("Prevented pushing a potentially duplicate view of xtype: " + view.xtype);
   }
});

I'm not totally sure if the xtype assumption is safe enough, but I can't think of any situation in my current app that would require one view pushing another view of the same type onto the navigation stack. So, the solution works for me, and it's pretty neat. The warning is there to save me headache later on and possibly pulling my hair out trying to work out why push wouldn't work!




回答4:


Just suspend the events on the button when it's tapped and resume them when the view is pushed

button.suspendEvents();
...
button.resumeEvents();

I don't think there is another way. As a developer or a user, when you tap a button twice, you expect the event handler to be called twice.

Hope this helps




回答5:


simply mask the entire container and then unmask it; create a ref for the container or panel in which the button exists in your controller and on tap set:

ref.setMasked(true)

After the new view is pushed simply unmask by

ref.setMasked(false)



回答6:


Another way is to flip a parameter once the list item has been tapped once, like this:

{
   onListItemTap: function () {
      if (!this.tapped) {
         this.tapped = true;
         ...
      }
   }
}

Of course, that only works if you are destroying the list view as soon as the user goes to a different screen.




回答7:


I created a method for checking this:

    ENSURE_NO_DOUBLE_TAP : function(classNameToPush) {
        if (Ext.getClassName(Ext.getCmp('MyViewport').getActiveItem()) == classNameToPush) {
            return false;
        }

        return true;
    }

Then from your app before anything that could be double tapped is processed:

        if (!ENSURE_NO_DOUBLE_TAP('MyApp.view.View')) {
            return;
        }



回答8:


If you are listening to the tap event of a button using listeners,then here is my solution:

listeners : {   
     release : function(){                                  
          if(this.getDisabled())return false;
          this.setDisabled(true);
          this.fireEvent('tap');
     },
     tap : function() {
         //do what you want
     }
 }



回答9:


Extending on jayteejee's and Merott's answers, I've added some code to intercept on multiple fast pushes to not only prevent duplicates but to prevent pushing of different views as well before the page transition completes. Think of a user tapping different list items.

Also notice the view.destroy(); method in the else block to prevent view instances from heaping up in memory.

Ext.define('Overrides.navigation.View', {
    extend: 'Ext.navigation.View',
    xtype: 'ovrnavigationview',

    interceptPush: false,

    push: function (view) {
        var activeItem = this.getActiveItem();

        // Prevent multiple pushes & duplicates
        if (!this.interceptPush && activeItem.xtype !== view.xtype) {

            // Set interceptPush
            this.interceptPush = true;

            // Reset interceptPush after 500 ms
            Ext.defer(function() {
                this.interceptPush = false;
            }, 500, this);

            // Handle push
            this.callParent(arguments);

        } else {

            // Warn developer
            console.warn("Prevented pushing view of xtype: " + view.xtype);

            // Destroy view
            view.destroy();

            return false;
        }
    }
});



回答10:


You can just use the "itemsingletap" event.

If you want to support double taps as well, make a second listener for "itemdoubletap" and invoke the same function, both listeners work fine together.



来源:https://stackoverflow.com/questions/11522736/sencha-touch-clicking-a-button-rapidly-will-push-a-view-twice

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!