2012-08-10 8 views
7

Używam Primefaces 3.2 z jsf 2 i glassfish 3.1.2.Problem z opóźnieniem z Primefaces overlayPanel - ładunki do leniwych

Mam p: dataTable użytkowników zawierających avatary użytkownika. Gdy użytkownik przesuwa kursor myszy nad ap Avatar: pojawia overlayPanel z dodatkowymi informacjami (leniwy załadowany) na użytkownika, a znika, gdy użytkownik przesunie kursor z daleka - tak:

<p:overlayPanel for="avatar" dynamic="true" showEvent="mouseover" hideEvent="mouseout" ...>

To działa bardzo dobrze - o ile użytkownik jest "wolny od pracy". Za każdym razem, gdy użytkownik przesunie kursor szybko nad wiele awatarów, wiele z overlayPaneli pozostanie widocznych. Na przykład, gdy użytkownik ma kursor nad pozycją, w której wyświetlane są awatary użytkownika, i używa kółka myszy do przewijania w dół lub w dół ekranu użytkownika.

Uważam, że panel nakładkowy rozpoczyna ładowanie informacji dynamicznie (dynamic="true") z serwera po wywołaniu showEvent="mouseover" i wyświetla panel nakładania po otrzymaniu odpowiedzi od serwera. W ten sposób nie można wykryć, czy kursor jest już oddalony, gdy panel nakładkowy staje się widoczny - dlatego hideEvent="mouseout" nigdy nie jest wywoływany.

Czy istnieje sposób na sprawienie, aby główny panel nakładek pojawił się bezpośrednio na urządzeniu przenośnym, pokazujący ładujący plik gif i aktualizujący zawartość do panelu nakładkowego, gdy odpowiedź pochodzi z serwera.

Czy to dobry pomysł lub czy ktoś wie jakikolwiek inny sposób na rozwiązanie tego nieprzyjemnego problemu?

Dzięki Pete

+0

Masz szczęście, że faktycznie dostaniesz treści. Podczas gdy mam do czynienia z dokładnie tym samym problemem, moje treści również są całkowicie pomijane. Nawet prosty h: outputText bez odwołań do rzeczywistego modelu wiersza (ten, który określasz za pomocą var) nie jest wyświetlany. Smutne jest to, że deweloperzy z wcześniejszych wersji nie uważali nawet za bardzo powszechny problem przedsiębiorstwa (IMO nie wygląda na to, że p: overlayPanel lub p: tooltip zostały zaprojektowane do użycia w tabelach). – Paranaix

+0

Czy przetestowałeś przepływ pracy za pomocą firebuga? Sprawdź błędy JS, a także sprawdź zawartość odpowiedzi ajax z serwera. –

+0

Tak, wysyłane jest żądanie ajax. To naprawdę dziwne; chociaż nie używam 3.3, ale najnowszej wersji 3.4. To może być nowy błąd. – Paranaix

Odpowiedz

4

Ponieważ moja pierwsza odpowiedź jest już bardzo długa i zawiera ważne informacje, postanowiłem otworzyć nową odpowiedź przedstawiającą moje ostateczne podejście.

Im teraz używam wzoru dziedziczenia Primefaces, czyniąc kod dużo czystszym. Zauważyłem również, że zastąpienie/nadpisanie całej funkcji bindEvents nie jest konieczne, ponieważ możemy usunąć stare procedury obsługi zdarzeń. Wreszcie ten kod naprawia najnowszy problem doświadczony: Ukryj wydarzenie przed przybyciem ajax.

PrimeFaces.widget.OverlayPanel = PrimeFaces.widget.OverlayPanel 
     .extend({ 

      bindEvents : function() { 
       this._super(); 

       var showEvent = this.cfg.showEvent + '.ui-overlay', hideEvent = this.cfg.hideEvent 
         + '.ui-overlay'; 

       $(document).off(showEvent + ' ' + hideEvent, this.targetId).on(
         showEvent, this.targetId, this, function(e) { 
          var _self = e.data; 

          clearTimeout(_self.timer); 
          _self.timer = setTimeout(function() { 
           _self.hidden = false; 
           _self.show(); 
          }, 300); 
         }).on(hideEvent, this.targetId, this, function(e) { 
        var _self = e.data; 

        clearTimeout(_self.timer); 
        _self.hidden = true; 
        _self.hide(); 

       }); 
      }, 

      _show : function() { 
       if (!this.cfg.dynamic || !this.hidden) { 
        this._super(); 
       } 
      } 

     }); 

Im przepraszam za słabą formatowania: Zaćmienia winy;)

2

Wow, wreszcie po sesji długo debuging i testując różne podejścia i uznaje się, że problem isnt wniosek ajax ale sam obsługi zdarzeń:

.on(hideEvent, this.targetId, this, function(e) { 
      var _self = e.data; 

      if(_self.isVisible()) { 
       _self.hide(); 
      } 
     }); 

Jak widać, Widżet jest po prostu ukryty, jeśli jest widoczny wcześniej. Jeśli poruszając myszą się zbyt szybko, teraz dwie rzeczy mogą się zdarzyć:

  • widżet widoczny we wszystkich
  • animacji isnt trwa nadal

W tym przypadku zdarzenie jest odrzucane i panel pozostaje widoczny. Ponieważ animacje są w kolejce, po prostu trzeba usunąć instrukcję if, aby naprawić problem. Zrobiłem to, wymieniając całą metodę bindEvents:

PrimeFaces.widget.OverlayPanel.prototype.bindEvents = function() { 
    //mark target and descandants of target as a trigger for a primefaces overlay 
    this.target.data('primefaces-overlay-target', this.id).find('*').data('primefaces-overlay-target', this.id); 

    //show and hide events for target 
    if(this.cfg.showEvent == this.cfg.hideEvent) { 
     var event = this.cfg.showEvent; 

     $(document).off(event, this.targetId).on(event, this.targetId, this, function(e) { 
      e.data.toggle(); 
     }); 
    } 
    else { 
     var showEvent = this.cfg.showEvent + '.ui-overlay', 
     hideEvent = this.cfg.hideEvent + '.ui-overlay'; 

     $(document).off(showEvent + ' ' + hideEvent, this.targetId).on(showEvent, this.targetId, this, function(e) { 
      var _self = e.data; 

      if(!_self.isVisible()) { 
       _self.show(); 
      } 
     }) 
     .on(hideEvent, this.targetId, this, function(e) { 
      var _self = e.data; 

      _self.hide(); 

     }); 
    } 

    //enter key support for mousedown event 
    this.bindKeyEvents(); 

    var _self = this; 

    //hide overlay when mousedown is at outside of overlay 
    $(document.body).bind('mousedown.ui-overlay', function (e) { 
     if(_self.jq.hasClass('ui-overlay-hidden')) { 
      return; 
     } 

     //do nothing on target mousedown 
     var target = $(e.target); 
     if(_self.target.is(target)||_self.target.has(target).length > 0) { 
      return; 
     } 

     //hide overlay if mousedown is on outside 
     var offset = _self.jq.offset(); 
     if(e.pageX < offset.left || 
      e.pageX > offset.left + _self.jq.outerWidth() || 
      e.pageY < offset.top || 
      e.pageY > offset.top + _self.jq.outerHeight()) { 

      _self.hide(); 
     } 
    }); 

    //Hide overlay on resize 
    var resizeNS = 'resize.' + this.id; 
    $(window).unbind(resizeNS).bind(resizeNS, function() { 
     if(_self.jq.hasClass('ui-overlay-visible')) { 
      _self.hide(); 
     } 
    }); 
}; 

wykonanie tego kodu na obciążenia i problem powinien zniknąć.



jak wasz zastępując kod js niemniej, można skorzystać z tej oppurtunity wdrożyć całkiem miły funkcji. Poprzez zastosowanie limity czasu w obsługi zdarzeń można łatwo wdrożyć trochę opóźnienia nie tylko poprawia użyteczność (nie więcej tysięcy pop-upów pojawić), ale także ograniczenie ruchu sieciowego:

 $(document).off(showEvent + ' ' + hideEvent, this.targetId).on(showEvent, this.targetId, this, function(e) { 
      var _self = e.data; 

      _self.timer = setTimeout(function(){ 
       if(!_self.isVisible()) { 
        _self.show(); 
       } 
      }, 300); 
     }) 
     .on(hideEvent, this.targetId, this, function(e) { 
      var _self = e.data; 

      clearTimeout(_self.timer); 
      _self.hide(); 

     }); 

Oczywiście można użyć zmiennej globalnej kontrolować opóźnienie czas.Jeśli chcesz bardziej elastycznego podejścia, musisz nadpisać metodę encodeScript w OverlayPanelRender, aby przesłać dodatkową właściwość. Możesz uzyskać do niego dostęp za pomocą _self.cfg.delay. Zauważ jednak, że będziesz musiał zastąpić model komponentu OverlayPanel również dostarczając mu dodatkowego atrybutu.

+0

Brzmi dobrze i źle w tym samym czasie, dzięki za twój wysiłek. Sprawdzę to i wrócę później. –

+0

Czy używałeś Primefaces 3.3 lub Snapshot for 3.4? Obecnie staram się dostosować twoje pomysły/zmiany do Primefaces 3.2 –

+0

Im używają migawki dla 3.4. Myślę, że to od 10,8; Nie jestem tego jednak pewien. Niektóre błędy, których doświadczyłem z 3.3, zostały naprawione przez aktualizację. Najbardziej godna uwagi jest prawdopodobnie f: obsługa param w p: menuitem. – Paranaix

2

Jednocześnie dziękuję za to wspaniałe rozwiązanie biorę możliwość zaktualizowania go do Primefaces 5.2. W naszej aplikacji kod złamał się po tej aktualizacji.

Follows kod aktualizowana Primefaces 5,2:

PrimeFaces.widget.OverlayPanel.prototype.bindTargetEvents = function() { 
    var $this = this; 
    //mark target and descandants of target as a trigger for a primefaces overlay 
    this.target.data('primefaces-overlay-target', this.id).find('*').data('primefaces-overlay-target', this.id); 

    //show and hide events for target 
    if(this.cfg.showEvent === this.cfg.hideEvent) { 
     var event = this.cfg.showEvent; 

     this.target.on(event, function(e) { 
      $this.toggle(); 
     }); 
    } 
    else { 
     var showEvent = this.cfg.showEvent + '.ui-overlaypanel', 
     hideEvent = this.cfg.hideEvent + '.ui-overlaypanel'; 

     this.target 
      .off(showEvent + ' ' + hideEvent) 
      .on(showEvent, function(e) { 
       clearTimeout($this.timer); 

       $this.timer = setTimeout(function() { 
        $('.ui-overlaypanel').hide(); 
        $this.hidden = false; 
        $this.show(); 
       }, 500); 
      }) 
      .on(hideEvent, function(e) { 

       clearTimeout($this.timer); 

       $this.timer = setTimeout(function() { 
        // don't hide if hovering overlay 
        if(! $this.jq.is(":hover")) { 
         $this.hide(); 
        } 
       }, 100); 
      }); 
    } 

    $this.target.off('keydown.ui-overlaypanel keyup.ui-overlaypanel').on('keydown.ui-overlaypanel', function(e) { 
     var keyCode = $.ui.keyCode, key = e.which; 

     if(key === keyCode.ENTER||key === keyCode.NUMPAD_ENTER) { 
      e.preventDefault(); 
     } 
    }) 
    .on('keyup.ui-overlaypanel', function(e) { 
     var keyCode = $.ui.keyCode, key = e.which; 

     if(key === keyCode.ENTER||key === keyCode.NUMPAD_ENTER) { 
      $this.toggle(); 
      e.preventDefault(); 
     } 
    }); 
}; 

I dodała również dodatkową funkcję, która pozwala użytkownikowi poruszać myszą nad nakładką bez ukrywania go. Powinien się ukryć, gdy wyniesiesz mysz, a potem to, co osiągnąłem:

<p:overlayPanel .... onShow="onShowOverlayPanel(this)" ...> 

function onShowOverlayPanel(ovr) { 
    ovr.jq.on("mouseleave", function(e) { 
     ovr.jq.hide(); 
    }); 
} 

Mam nadzieję, że ci się spodoba!

Powiązane problemy