wnr / element-resize-detector

Optimized cross-browser resize listener for elements.
MIT License
1.32k stars 118 forks source link

Registering on a div within an iframe within a hidden div using "scroll" strategy fails #97

Closed awkay closed 5 years ago

awkay commented 6 years ago

OK, we have a really convoluted case that works fine with the "deprecated" method, but totally fails with the scroll method. We're embedding a react app in an existing PHP mess. The outer mess has CSS we want to isolate from, so our react app creates and renders into an iframe, and the resize detector is on a div within that iframe (which is the DOM component that needs to know about inner resizing, so it can resize to not have a double scrollbar).

If the overall outer app div (that React is mounted on) is hidden, then a DOM node gets registered into the resize detector and it fires an initial resize event, but no other events ever happen, even after the outer application DOM is set to display.

The workaround is to not use the scroll mode.

I'm sending this issue so that you know there may be cases where keeping around (and not deprecating) the old way might be important.

wnr commented 6 years ago

Hi, and sorry for the late response - I'm currently on vacation.

That's an interesting case, i'll have a look when I'm back in office next week. Indeed, you and others have discovered that the object approach is actually preferred in some rare cases. I'll remove the deprecation. In the mean time, could you perhaps construct a slim example displaying the issue for me?

Cheers

wnr commented 6 years ago

I have a further question: when you say that the outer div is hidden, do you mean display: none or visibility: hidden or something else?

awkay commented 6 years ago

I do mean display: none.

There is external code (jQuery on the legacy system) that does the show/hide on the portal application in the iframe. I work in Fulcro/Clojurescript, so I'm not sure if my example code will help you, but here it is in case you want to turn it into whatever you use:

(defn element-size
  [element]
  (when element
    (let [rect (.getBoundingClientRect element)]
      {:top    (.-top rect)
       :bottom (.-bottom rect)
       :left   (.-left rect)
       :right  (.-right rect)
       :width  (.-width rect)
       :height (.-height rect)})))

;; erd-factory is what we required resize detector as
(let [resize-detector (erd-factory)]
  (defn resize-tracker-factory
   "Returns a function that, when called, attaches a resize detector to the supplied DOM element
that will call onResize whenever that DOM element changes size"
    [onResize]
    (fn [r]
      (when r
        (.listenTo resize-detector r (fn [ele]
                                       (when-let [sz (element-size ele)]
                                         (onResize sz))))))))

(defsc Root [this {:keys [ui/router] :as props}]
  {:initLocalState     (fn [] {:width 0 :height 400})
   :componentWillMount (fn []
                         ;; save a genereated resize detector in component-local state
                         (let [onResize (fn [sz] (when sz (prim/set-state! this sz)))]
                           (gobj/set this "div-handler" (rt/resize-tracker-factory onResize))))}
  (let [{:keys [height]} (prim/get-state this)]
    ;; A react render-to-iframe component
    (elements/ui-iframep {:frameBorder 0 :width "100%" :height (if (> 400 height) 400 height) :className "col-md-12"
                          ;; Get the body of the iframe so the modals can render on the right mount-point.
                          :head        "<link rel='stylesheet' href='/semantic-ui/semantic.min.css'>"
                          :bodyRef     (fn [r] (gobj/set this "modal-mount-node" r))}
      (dom/div {:className "ui form"}
        (dom/div {:style {:position "relative" :minHeight "400px"}
                  ;; get the detector, and feed this DOM element to it
                  :ref   (gobj/get this "div-handler")}
          ;; main application...
          (ui-top-router router))))))
wnr commented 6 years ago

That's awesome, I'm actually a big fan of Clojure :)

Thanks for the clarification, I'll start working on reproducing this in a test case...

franklixuefei commented 5 years ago

How's this going? 😄

wnr commented 5 years ago

Sorry for the delay, I've been swamped with work :(

I'm looking into this right now.

wnr commented 5 years ago

I've pushed a fix in WIP-1.2.0 . Could you give it a try?

So basically I added a new method initDocument which you need to call when your iframe is mounted/loaded.