2

I have a page with a list of objects, clicking one of them opens a popup-menu.

I want to align the popup-menu with the object that was clicked. So I created a custom-binding that waits for the object JQuery element and then aligns the popup according to the object's offset and scrollTop.

It all works fine, but I have a small issue. Before that list of objects I have a container that displays some extra details, and it fades out after a specific time.

So if I try to open the popup menu before the container fades out, it will remain in that position even after the container fades out, while the object list moves.

So I thought I'll just add 'update' to the custom binding, but it doesn't work.

In my custom binding:

ko.bindingHandlers.alignPopup = {
        init: function (element, valueAccessor) {
            var value = valueAccessor();
            var element = value(); // jQuery.fn.init[1] , this is the object clicked
            ... some aligning computations ...
            }
        },
        update: function(element, valueAccessor) {
            ... same thing ...
        }
    };

In my ViewModel, I've tried:

var elementObs = ko.observable(objectElement) // objectElement is the object clicked jQuery element

In html I've just added the custom binding with the above elementObs

Update is never called, so my guess is that the observable does not know that the 'offset()' and the 'scrollTop' have modified, because they are not observables as well.

How can I make the jQuery observable notice that those 2 attributes have changed?

EDIT: I said that 'update' is never called, it is called only in the beginning when the binding is applied (as it always should)

Dragos
  • 776
  • 8
  • 32
  • Have you considered using callback inside fade? – Rajesh Jan 26 '16 at 12:53
  • Yes I thought of that, but I would prefer not to. I wanted to find out if there's some other way to notice the changes. That way it would work even if I'd add some other dynamic elements that fade out – Dragos Jan 26 '16 at 12:55
  • You can use setInterval(function() { /* place for code getting new offset and scroll and update jQuery UI widget */ }, 250); in order to update place and scroll. – TSV Jan 26 '16 at 13:04
  • A JsFiddle of working example will help here. – Dandy Jan 26 '16 at 13:30
  • http://stackoverflow.com/questions/7074907/how-do-you-listen-for-a-html-element-moving-in-javascript – Roy J Jan 26 '16 at 14:51
  • @TSV first it should be `setTimeout`. Second using timeout for such task is more of patch work and callbacks (promises) are better approach. – Rajesh Jan 27 '16 at 01:43
  • Can you please provide the jsfiddle code – Haridarshan Jan 27 '16 at 06:11

1 Answers1

0

Unfortunately, the answer is "you can't". At least, not with Knockout or jQuery, in a way that you seem to be after.

The 'scrollTop' and 'offset' attributes are not observable, and you cannot make them observable in any direct way.

The best you can do, is play with the observer pattern and the DOM events. E.g., whenever a scroll-event happens on the window, cache the current value of scrollTop for your element. A library like RxJs makes this very easy.

I am not sure if a similar solution exists for offset.

In this case, I'd probably fire a custom event from inside the fade callback, and respond to that event (and probably a few others) by re-positioning the menu.

Hans Roerdinkholder
  • 3,000
  • 1
  • 20
  • 30