Search code examples
javascriptjquerypackery

Packery init without triggering layout


I have packery with jQuery Draggable all setup and working correctly on my development environment.

At the moment I am saving my ordered (packery) html to the database. Before everything is inserted to the DB I change the order of the dom elements to match the packery order. Everything works nicely

when re-loading the page with the saved html all the divs appear in their position as per the save.

The problem I am having is when I set up packery again with my loaded HTML using ($grid is the parent div)

var $grid = $('.grid');
$grid.packery({
      columnWidth: '.grid-sizer',
      itemSelector: '.grid-item',
      stamp: ".stamp",
      gutter:0,
      percentPosition: true
}); 

Packery does its thing a "packs" everything again. which is exactly what it is supposed to do. Thing is i want to keep my old layout that may of had empty space in it.

My question is...

Is it possible to init packery without triggering the layout function? I have tried adding initLayout: false to the options. but it doesn't let me drag elements & layoutInstant: false doesn't seem to do anything.

Screens of saved html (after dragging everything how i want it) and then after re-loading and then $grid.packery()

https://i.sstatic.net/fS2Vp.png
https://i.sstatic.net/pAnkW.png


Solution

  • Alright i managed to sort this out myself. mainly from this answer on the metafizzy git metafizzy isse tracker

    Added code before the initial packery set up

    Packery.prototype.getShiftPositions = function( attrName ) {
        attrName = attrName || 'id';
        var _this = this;
        console.log(_this.packer.width);
        return this.items.map( function( item ) {
            return {
                attr: item.element.getAttribute( attrName ),
                x: item.element.offsetLeft,
                y: item.element.offsetTop
            }
        });
    };
    
    Packery.prototype.initShiftLayout = function( positions, attr ) {
        if ( !positions ) {
            // if no initial positions, run packery layout
            this.layout();
            return;
        }
        // parse string to JSON
        if ( typeof positions == 'string' ) {
            try {
                positions = JSON.parse( positions );
            } catch( error ) {
                console.error( 'JSON parse error: ' + error );
                this.layout();
                return;
            }
        }
    
        attr = attr || 'id'; // default to id attribute
        console.log(this.items);
        this._resetLayout();
        // set item order and horizontal position from saved positions
        this.items = positions.map( function( itemPosition ) {
            var selector = '[' + attr + '="' + itemPosition.attr  + '"]';
            var itemElem = this.element.querySelector( selector );
            var item = this.getItem( itemElem );
            if (item) {
                item.rect.x = itemPosition.x;
                item.rect.y = itemPosition.y;
                return item;
            }
        }, this );
    
        // filter out any items that no longer exist
        this.items = this.items.filter(function(item) {
            return item !== undefined;
        });
        // add new items
        var newitems = [];
        var p = this;
        $(this.$element[0]).find(this.options.itemSelector).each(function(i, e) {
            if (!p.getItem(e)) {
                newitems.push(e);
            }
        });
        this.addItems(newitems);
    
        this.shiftLayout();
    };
    

    When setting packery up. set initLayout:false e.g.

    $grid.packery({
        columnWidth: parseInt($columnWidth),
        itemSelector: '.grid-item',
        stamp: ".stamp",
        gutter:0,
        percentPosition: true,
        initLayout: false,
    });
    

    Then setting everything up (data-item-index) is a unique value added to each div that can be moved around. you could use 'id'

    var initPositions = $grid.packery( 'getShiftPositions', 'data-item-index');
    $grid.packery( 'initShiftLayout', initPositions, 'data-item-index');