1

I'm using a WinMove function to make divs with the class ibox-title movable, but I dont know how to make the users computer save the divs positions in a cookie/localStorage so the divs will be saved in the spot where the user placed them. There are multiple pages and multiple divs on each page so it would be DRY to have a function for each div but I also dont know how to make something like this dynamic because I have very little experience with javascript/jquery, and no experience with cookies/localStorage.

jsfiddle: https://jsfiddle.net/at38xkav/1/

Function that lets the user move the divs around on the page

function WinMove() {
    var element = "[class*=col]";
    var handle = ".ibox-title";
    var connect = "[class*=col]";
    $(element).sortable(
        {
            handle: handle,
            connectWith: connect,
            tolerance: 'pointer',
            forcePlaceholderSize: true,
            opacity: 0.8
        })
        .disableSelection();
}

A sample of what each div will include on any given page

<div class="row">
 <div class="col-lg-6">
  <div class="ibox">
   <div class="ibox-title">
    <h5>Element 1</h5>
   </div>
  <div class="ibox-content"></div>
 </div>
</div>

Thanks! :)

Markus
  • 297
  • 4
  • 19
  • You mean "localStorage"? Why do you prefer cookies over it? – georg Feb 25 '16 at 20:25
  • Ah yes i meant localStorage ill fix that. From my understanding cookies work better with older browsers, that could be backwards but that's the reasoning. – Markus Feb 25 '16 at 20:29
  • Even if you have to support [IE7](http://caniuse.com/#search=localstorage) (do you really?), it's better to use a shim than to downgrade your whole workflow – georg Feb 25 '16 at 20:33
  • Well as long as its saved on the users machine, either a cookie or localstorage, then its great – Markus Feb 25 '16 at 20:39

2 Answers2

1

You have to differentiate between them somehow. I don't know what you mean by not wanting hardcoded variable, but you've got to have something. For example, you could give each div an attribute data-col_id="some_unique_value". After that, when you want to save positions you'd extract them and keep somewhere:

function() {
    var positions = {}
    $('[data-col_id]').each(function() {
        positions[$(this).data('col_id')] = $(this).offset()
    })
    localStorage.setItem('col_positions', JSON.stringify(positions))
}

When you need to restore them, do the opposite — get saved data and use it:

function() {
    var positions = localStorage.getItem('col_positions')
    positions = positions ? JSON.parse(positions) : {}
    for (var col_id in positions)
        $('[data-col_id="' + col_id + '"]').offset(positions[col_id])
}

Of course, your positioning may be different than using jquery offset method, that was just an example. Also, suggested naming (data-col_id) is also just an example and can be easily changed.


If your html structure is constant and you are sure it's gonna be constant, you could avoid giving elements any unique names and just use combination of page identifier (for example location.href) and xpath. You can find how to get xpath from an element and how to retrive the element knowing xpath. However, I really suggest against that, because xpath is quite unreliable and can change on a slight DOM modification.

Community
  • 1
  • 1
Serge Seredenko
  • 3,541
  • 7
  • 21
  • 38
  • Thanks for an answer, what i meant by not wanting to hard code it was that ive seen similar answers that have a section of code dedicated to each div that move the top and left position of that div into its own cookie variable. So if i have 50+ divs id have 50+ code samples that are all the same thing but are for a specific div each – Markus Feb 25 '16 at 21:03
  • Hm, I don't really understand you point: the code from my answer doesn't require to be used more than once. Only `data-col_id` feature should be assigned to every div, or any other way to differentiate between divs (how to tell one from another), for example `id` attribute, or maybe xpath idea, which doesn't require modifiction of html at all (last section of the answer). – Serge Seredenko Feb 25 '16 at 21:07
  • Oh no, i wasnt saying that about your answer, i was just answering something you said you were unsure about in my question. – Markus Feb 25 '16 at 21:11
  • So for the functions do i make them self closing functions? – Markus Feb 25 '16 at 21:38
  • I don't know what self closing function is, but that almost surely doesn't matter. I wrote `function () {...}` just to group the code. – Serge Seredenko Feb 25 '16 at 21:41
  • doesnt seem to be working for me, i put `data-col_id="div5"` in the ibox-title div and put the code you gave without the fucntion(){...} because you said it wasnt needed but it still doesnt work – Markus Feb 26 '16 at 14:56
  • Where div you put the code? First part should be used when you want to save positions, second part — when restore. – Serge Seredenko Feb 26 '16 at 17:03
  • Well im assuming the restore part would be in the `$(document).ready(function () {...}` but the save part im not sure about. Id assume when the user leaves/close the page but how do i go about that – Markus Feb 26 '16 at 18:41
  • I got it working after using the `onbeforeunload` DOM, thanks again! – Markus Feb 26 '16 at 20:54
  • I'm not sure about that, I did another answer, which I think is a solution to your problem. – Serge Seredenko Feb 26 '16 at 21:09
1

I realized you needed restore order of sortable element, and not their position on page. For that you could use update event of sortable plugin, in whose handler you'd save current positions into local storage:

$(element).sortable({
  update: function(e, ui) {
    var parent = ui.item.closest('[data-par_id]');
    var positions = []
    $('[data-col_id]').each(function() {
      positions.push({
        col_id : $(this).data('col_id'),
        par_id : $(this).closest('[data-par_id]').data('par_id')
      })
    })
    localStorage.setItem('all_orders', JSON.stringify(positions))
    console.log(JSON.stringify(positions))
  }
})

Now, do restore the order next time page is opened, I would just take the saved array and, in that order, extract corresponding element an append it back to the list:

(function() {
  // get saved positions
  var positions = localStorage.getItem('all_orders')
  console.log(positions)
  positions = positions ? JSON.parse(positions) : []
  // sort the list
  for (var i in positions) {
    var element = positions[i]
    $('[data-par_id="' + element.par_id + '"]').append(
      $('[data-col_id="' + element.col_id + '"]').detach()
    )
  }
}) ()

This approach requires each row have a unique identifier (in the code above it's data-col_id) and each container also have a unique identifier (which I chose to be data-par_id).

Also, you'd have to call .sortable not on element you want to move, but on their parents.

Here's a working fiddle, in which I rewrote your WinMove function.

Serge Seredenko
  • 3,541
  • 7
  • 21
  • 38