Listening for position changes using jQuery events

It is essential to be able to track the relative position of elements, especially when dealing with dynamic layout issues. Unfortunately, there are no built-in options in CSS to listen for changes in position() or offset() attributes.

Reason: Changes in a sibling element's dimensions within dialogs or forms can alter the relative position. This information can be valuable for interactive forms, allowing for adjustments based on factors like the maximum available height or width of the parent container.

Answer №1

This unique custom code extension utilizes a timer poll to track the position of an object. It is believed that using a timer is necessary in this scenario as the position can be altered without jQuery being triggered, such as when sibling elements are re-laid out. This solution monitors the elements' .position() and .offset() properties. Additionally, it can be enhanced to monitor other properties not covered by standard jQuery events.

Custom jQuery Extension:

jQuery.fn.onPositionChanged = function (callback, interval) {
    if (interval == null) interval = 100;
    var element = $(this[0]); 
    if (element.length < 1) return element;

    var lastPosition = null;
    var lastOffset = null;
    setInterval(function () {
        if (element == null || element.length < 1) return element; 
        if (lastPosition == null) lastPosition = element.position();
        if (lastOffset == null) lastOffset = element.offset();
        var newPosition = element.position();
        var newOffset = element.offset();
        if (lastPosition.top != newPosition.top || lastPosition.left != newPosition.left) {
            $(this).trigger('onPositionChanged', { lastPos: lastPosition, newPos: newPosition });
            if (typeof (callback) == "function") callback(lastPosition, newPosition);
            lastPosition = element.position();
        }
        if (lastOffset.top != newOffset.top || lastOffset.left != newOffset.left) {
            $(this).trigger('onOffsetChanged', { lastOff: lastOffset, newOff: newOffset});
            if (typeof (callback) == "function") callback(lastOffset, newOffset);
            lastOffset= element.offset();
        }
    }, interval);

    return element;
};

Implementation:

$("#<SOME_ID>").onPositionChanged(function(){alert("foobar")});

Answer №2

My approach to solving this issue was inspired by willsteel's solution. I focused on monitoring the changes to the width and offsetWidth properties of the element. This allows the function to be triggered even if the element becomes invisible or visible for any reason.

Check out the updated code below:

jQuery.fn.onPositionChanged = function (trigger, millis) {
    if (millis == null) millis = 100;
    var o = $(this[0]); // our jquery object
    if (o.length < 1) return o;
    var lastPos = null;
    var lastOff = null;
    var lastWidth = null;
    var lastOffWidth = null;
    setInterval(function () {
        if (o == null || o.length < 1) return o; // abort if element is non existend eny more
        if (lastPos == null) lastPos = o.position();
        if (lastOff == null) lastOff = o.offset();
        if (lastWidth == null) lastWidth = o.width();
        if (lastOffWidth == null) lastOffWidth = o[0].offsetWidth;
        var newPos = o.position();
        var newOff = o.offset();
        var newWidth = o.width();
        var newOffWidth = o[0].offsetWidth;
        if (lastPos.top != newPos.top || lastPos.left != newPos.left) {
            $(this).trigger('onPositionChanged', { lastPos: lastPos, newPos: newPos });
            if (typeof (trigger) == "function") trigger(lastPos, newPos);
            lastPos = o.position();
        }
        if (lastOff.top != newOff.top || lastOff.left != newOff.left) {
            $(this).trigger('onPositionChanged', { lastOff: lastOff, newOff: newOff});
            if (typeof (trigger) == "function") trigger(lastOff, newOff);
            lastOff= o.offset();
        }
        if (lastWidth != newWidth) {
            $(this).trigger('onPositionChanged', { lastWidth: lastWidth, newWidth: newWidth});
            if (typeof (trigger) == "function") trigger(lastWidth, newWidth);
            lastWidth= o.width();
        }
        if (lastOffWidth != newOffWidth) {
            $(this).trigger('onPositionChanged', { lastOffWidth: lastOffWidth, newOffWidth: newOffWidth});
            if (typeof (trigger) == "function") trigger(lastOffWidth, newOffWidth);
            lastWidth= o.width();
        }
    }, millis);
    return o;
};

Answer №3

Here is a variation of the code that can be used on multiple objects and with any selector, although it does not specifically rely on jQuery.

var onPositionChanged = function (selector,trigger, millis) {
if (millis == null) millis = 200;
setInterval(function(){
    var o_s = jQuery(selector); // our jquery object
    if (o_s.length < 1) return o_s;

    for(var i = 0; i<o_s.length; i++)
    {
        var o = o_s.eq(i);

        var lastPos = jQuery(o).attr("lastPos");
        var lastOff = jQuery(o).attr("lastOff");
        lastPos = ((lastPos == "" || lastPos == undefined) ? null : JSON.parse(lastPos));
        lastOff = ((lastOff == "" || lastOff == undefined) ? null : JSON.parse(lastOff));
        setTimeout(function (o) {
            if (o == null || o.length < 1) return o; // abort if element is non existend eny more
            if (lastPos == null) lastPos = o.position();
            if (lastOff == null) lastOff = o.offset();
            var newPos = o.position();
            var newOff = o.offset();
            if (lastPos.top != newPos.top || lastPos.left != newPos.left) {
                jQuery(this).trigger('onPositionChanged', { lastPos: lastPos, newPos: newPos });
                if (typeof (trigger) == "function") trigger(o,lastPos, newPos);
                lastPos = o.position();
                jQuery(o).attr("lastPos",JSON.stringify(lastPos));
            }
            if (lastOff.top != newOff.top || lastOff.left != newOff.left) {
                jQuery(this).trigger('onOffsetChanged', { lastOff: lastOff, newOff: newOff});
                if (typeof (trigger) == "function") trigger(o,lastOff, newOff);
                lastOff= o.offset();
                jQuery(o).attr("lastOff",JSON.stringify(lastOff));
            }
        }, millis,o);
    }
},millis);

};

Example of how to use this:

jQuery(document).ready(function(){
onPositionChanged(".grid-item:not(.d-none)",function(object){

    var left_percentage = parseInt(jQuery(object).position().left / jQuery(object).parent().width() * 100);
    var parent_width = jQuery(object).parent().width();

    var percentage_of_parent = parseInt(jQuery(object).width() / parent_width * 100);

    if(left_percentage > 74 && percentage_of_parent >= 25
    || left_percentage > 66 && percentage_of_parent >= 33
    || left_percentage > 49 && percentage_of_parent >= 50)
    {
        jQuery(object).find(".card").css("margin-right","0px");
        jQuery(object).parent().masonry('layout');
    }
    if(left_percentage < 1)
    {
        jQuery(object).find(".card").css("margin-left","0px");
        jQuery(object).parent().masonry('layout');
    }
});

});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Display the iframe website without it being visible to the user

Is there a way to load a separate website, such as a Wikipedia article, in an iframe on a webpage without freezing up the whole page when it becomes visible after clicking a "show" button? And if not, how can we display a loading gif while the iframe is ...

Steps to disable ajax global setting when making an ajax call in a kendo grid

When working with MVC 5 in the _layout page, I have incorporated .ajaxStart and .ajaxStop events to display a busy indicator. <body> <script type="text/javascript"> $(document).ajaxStart(function (e) { $( ...

Jpicker is renowned for its transparency feature

I am currently using the Jpicker jpicker-1.1.6.js script which can be found at Below is a snippet of my code: <script type="text/javascript"> $(function() { $.fn.jPicker.defaults.images.clientPath='/img'; var ...

Troublesome php ajax application failing to function

Despite creating a simple PHP and AJAX application, I am encountering issues and unable to identify the root cause. Below is my code snippet: <?php $grId = $_GET["groupId"]; $limit = $_GET["limit"]; if ($limit <= 0) { $limit = 10; } $serverna ...

hiding html elements by using the display property set to none instead of physically removing

I am currently utilizing an if-else statement to display different HTML structures. As a result, the entire HTML is being rendered twice. Is there a way we can utilize 'display: none' instead? I attempted to use it in th ...

Prevent horizontal HTML scrolling while displaying a layer

I am currently working with a .layer div element that darkens the page to highlight a modal. However, I have encountered an issue where upon triggering the event, the div does not occupy 100% of the screen and the original browser scroll bar disappears. I ...

What is the method for placing a title in the initial column with the help of v-simple-table from Vuetify.js?

I am interested in using the v-simple-table UI component from Vuetify.js to create a table similar to the one shown below. After creating the code in codesandbox and previewing the output, I noticed that the title is not aligned properly. HTML↓ < ...

What is the best way to retrieve content from a different website using javascript in an asp.net environment?

Currently working on a web application in asp.net where I want to provide users with a JavaScript code that allows them to fetch content from my website and display it on their own website. To handle user requests on my website, I have implemented a gener ...

Is the ng bootstrap modal within Angular failing to show up on the screen

In the midst of working on my project, I encountered an issue with opening a modal using ng bootstrap. Although I found a similar thread discussing this problem, it did not include bootstrap css. I decided to reference this example in hopes of resolving t ...

Expanding the rowspan within a table column has the effect of reducing its overall width

I have created a table with two rows, where the first row has three columns and the second row has two columns. The middle column in the first row has been set to rowspan="2". However, the issue is that it appears smaller than its intended width. .kolon ...

Error: Unable to access the 'login' property of an undefined object

An error occurred: Uncaught TypeError: Cannot read property 'login' of undefined........... import Login from '../components/Login.jsx'; import { useDeps, composeWithTracker, composeAll } from 'mantra-core'; export const com ...

Troubleshooting: JavaScript Bookmarklet Fails to Execute on Certain Websites

Recently, I created a unique bookmarklet that functions flawlessly on some websites, but unfortunately fails to work on others. Interestingly, even when it doesn't work, the script is still added to the bottom of the page; however, only a portion of t ...

How to apply gradient colors to borders using CSS

Is it possible to create a simple border bottom color with a gradient effect? div{ border-bottom:10px solid linear-gradient(#FF4000, transparent); height:20px; width:auto; background:#ccc; } <div></div> ...

What is the correct way to utilize ng-if/ng-show/ng-hide to hide or show HTML elements within the app.run function

I am currently working on developing an app that loads views correctly. HTML: <body> <loading outerWidth='1000' outerHeight='1000' display='isReady'></loading> <div class='wrapper' ng-sho ...

Using HTML Select field to make ajax calls to web services

When working with modals that contain forms to create objects for database storage, there is a Select field included. This is the code snippet for the Select field: <div class="form-group" id=existingUser> <label>Username</label> < ...

Resolving the bothersome complications of self-looping steps in jQuery animate delay

My timeline definition includes selectors and a sequence of delays and animations to apply to an object. I have also provided the option to loop through the steps for a specific object. Here is the function that I use to queue the animations: function an ...

Angular.js, require.js, and jQuery Plugin all combined to create a uniquely customized directive

As a newcomer to Angular and Require, I am seeking assistance with the following code snippet. Despite successfully integrating Angular and Require, I am facing an issue where the bootstrap-switch element fails to initialize: define(['myapp.ui/module ...

Guide to changing an image on a canvas with KineticJS

I am currently working on developing a canvas that will display a hotel floor view. I have images stored in a database which I am drawing onto the canvas using x and y coordinates from the database as reference points. However, I want to add touch events t ...

Struggling with CSS, seeking improvements to align with my previous coding style

After spending a considerable amount of time working on my game, I made the decision to change my navigation bars to buttons. However, I'm facing issues while trying to finalize the style that I had previously. Here is the old code fiddle: https://js ...

Is there a way in CSS to enable caps lock for specific characters only?

After downloading a new font and setting font-variant: small-caps;, I noticed that my numbers appear much larger than the letters. Is there a way to apply small caps only to the letters, not the numbers? While traditionally numbers do not have a capital ...