'jQuery UI Portlet Save State on Database

We can drag and drop elements using jQuery UI sortable - Portlets. I want to save the state into the MySQL database. Any way (Perhaps AJAX) to do so?

My HTML:

<div class="column" id = "column-1">
First Category
 
  <div class="portlet">
    <div class="portlet-header">Feeds</div>
    <div class="portlet-content">Lorem ipsum dolor sit amet, consectetuer adipiscing elit</div>
  </div>
 
  <div class="portlet">
    <div class="portlet-header">News</div>
    <div class="portlet-content">Lorem ipsum dolor sit amet, consectetuer adipiscing elit</div>
  </div>
 
</div>
 
<div class="column" id = "column-2">
Second Category
 
  <div class="portlet">
    <div class="portlet-header">Shopping</div>
    <div class="portlet-content">Lorem ipsum dolor sit amet, consectetuer adipiscing elit</div>
  </div>
 
</div>

<div class="column" id = "column-3">
Third Category
 
  <div class="portlet">
    <div class="portlet-header">Shopping</div>
    <div class="portlet-content">Lorem ipsum dolor sit amet, consectetuer adipiscing elit</div>
  </div>

  <div class="portlet">
    <div class="portlet-header">Shopping</div>
    <div class="portlet-content">Lorem ipsum dolor sit amet, consectetuer adipiscing elit</div>
  </div>
 
</div>
 
<div class="column" id = "column-4">
Fourth Category
 
  <div class="portlet">
    <div class="portlet-header">Links</div>
    <div class="portlet-content">Lorem ipsum dolor sit amet, consectetuer adipiscing elit</div>
  </div>
 
  <div class="portlet">
    <div class="portlet-header">Images</div>
    <div class="portlet-content">Lorem ipsum dolor sit amet, consectetuer adipiscing elit</div>
  </div>
 
</div>

My JavaScript:

<script>
  $( function() {
    $( ".column" ).sortable({
      connectWith: ".column",
      handle: ".portlet-header",
      cancel: ".portlet-toggle",
      placeholder: "portlet-placeholder ui-corner-all"
    });
 
    $( ".portlet" )
      .addClass( "ui-widget ui-widget-content ui-helper-clearfix ui-corner-all" )
      .find( ".portlet-header" )
        .addClass( "ui-widget-header ui-corner-all" )
        .prepend( "<span class='ui-icon ui-icon-minusthick portlet-toggle'></span>");
 
    $( ".portlet-toggle" ).on( "click", function() {
      var icon = $( this );
      icon.toggleClass( "ui-icon-minusthick ui-icon-plusthick" );
      icon.closest( ".portlet" ).find( ".portlet-content" ).toggle();
    });
  } );
  </script>

Styling:

<style>
  body {
    min-width: 520px;
  }
  .column {
    width: 170px;
    float: left;
    padding-bottom: 100px;
  }
  .portlet {
    margin: 0 1em 1em 0;
    padding: 0.3em;
  }
  .portlet-header {
    padding: 0.2em 0.3em;
    margin-bottom: 0.5em;
    position: relative;
  }
  .portlet-toggle {
    position: absolute;
    top: 50%;
    right: 0;
    margin-top: -8px;
  }
  .portlet-content {
    padding: 0.4em;
  }
  .portlet-placeholder {
    border: 1px dotted black;
    margin: 0 1em 1em 0;
    height: 50px;
  }
  </style>

Scripts and Stylesheets:

<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>

Any help would be appreciated for PHP. Below is the screenshot of current state:

enter image description here

Whenever the user drags and drops element from First Category to Second Category, it should be updated on the database.



Solution 1:[1]

I don't really really understand your question, or even what you mean by states, but I'll take a shot in the dark and assume you mean that you want to save the position of each box relative to the columns.

I would set it up so that each column has a name/number, and each box has a rank.

So each box when either initialized or changed would have a rank (0 to infiniti), and it's parent, the column, would have a name

Quick Example: example

Say you move the News box from the first category to the second category under the shopping box.
When you first look at it, News would be designated as ['First', 1]. After the switch it would be ['Second', 1].

Solution 2:[2]

I found a way to save states of a portlet (expanded, collapsed and position) https://github.com/coyote333666/pjp

for example, if showOrHide = {"portlet-content-01":0,"portlet-content-02":0,"portlet-content-03":1,"portlet-content-04":0}

to save expanded and collapsed states:

$( ".portlet" )
    .addClass( "ui-widget ui-widget-content ui-helper-clearfix ui-corner-all" )
    .find( ".portlet-header" )
    .addClass( "ui-widget-header ui-corner-all" )
    .prepend( "<span id='s1' class='ui-icon ui-icon-minusthick portlet-toggle'></span>");   
$( ".portlet-toggle" ).on( "click", function() {
    var icon = $( this );
    icon.toggleClass( "ui-icon-minusthick ui-icon-plusthick" );
    icon.closest( ".portlet" ).find( ".portlet-content" ).toggle();
    var x = icon.closest( ".portlet" ).find( ".portlet-content" ).attr("id"); 


    if ( showOrHide[x] == 1 ) 
    {
        showOrHide[x] = 0;
    } 
    else if ( showOrHide[x] == 0 ) 
    {
        showOrHide[x] = 1;
    }       


    var data = { 
                    'state' : JSON.stringify(showOrHide)                    
                }
    $.ajax({
        data: data,
        type: 'POST',
        url: '<?php echo("?" . S_PARAMETER_REDIRECTOR .S_FILE_PORTLET_UPDATE); ?>'
    });         
});

to restore expanded and collapsed states:

$(window).ready(function()
{
    for (var k in showOrHide)
    {
        var last2 = k.slice(-2);
        if (showOrHide.hasOwnProperty(k)) 
        {
            if (showOrHide[k] == 1 ) 
            {
                $('#' + k).show();
            } 
            else if (showOrHide[k] == 0 ) 
            {
                $('#' + k).hide();
                $('#portlet-header-' + last2 + ' #s1.ui-icon-minusthick').removeClass('ui-icon-minusthick').addClass('ui-icon-plusthick');
            }
        }
    }
});

to save position state:

var showOrHide = <?php
    $sQuery =
    "
        SELECT portlets_state,portlets_left,portlets_right
        FROM portlet_user
        WHERE user_id               = " . fncSetInt($_SESSION["user_id"])   . ";
    ";
    $oRecordset = fncQueryPg($sQuery);  
    if(!empty($oRecordset[0]["portlets_state"]["VALUE"]))
    {
        echo($oRecordset[0]["portlets_state"]["VALUE"]);
    } 
    else
    {
        if(!empty($oRecordset[0]["portlets_left"]["VALUE"]))
        {
            $portlet = explode(",", $oRecordset[0]["portlets_left"]["VALUE"]);
        }
        if(!empty($oRecordset[0]["portlets_right"]["VALUE"]))
        {
            $section_2 = explode(",", $oRecordset[0]["portlets_right"]["VALUE"]);
            for($z=0; $z<sizeof($section_2); $z++)
            {
                array_push($portlet,$section_2[$z]);
            }   
        }
        for($z=0; $z<sizeof($portlet); $z++)
        {
            $key = str_replace('portlet_','portlet-content-',$portlet[$z]);
            $aPortlet[$key] = 1;
        }   
        echo(json_encode($aPortlet));
    } ?>;

$( ".column" ).sortable({       
    connectWith: ".column",
    handle: ".portlet-header",
    cancel: ".portlet-toggle",
    placeholder: "portlet-placeholder ui-corner-all",
    update: function (event, ui) {
        var list =  $(this).sortable("toArray").join(",");
        var data = { 
                    'section': this.id,              
                    'components': list
                    }
        $.ajax({
            data: data,
            type: 'POST',
            url: '<?php echo("?" . S_PARAMETER_REDIRECTOR .S_FILE_PORTLET_UPDATE); ?>'
        }); 
    }
});

to restore position state :

<div class="column" id="section-1">
<?php
    $sQuery =
    "
        SELECT portlets_left,portlets_right
        FROM portlet_user
        WHERE user_id               = " . fncSetInt($_SESSION["user_id"])   . ";
    ";
    $oRecordset = fncQueryPg($sQuery);
    $section_1 = $oRecordset[0]["portlets_left"]["VALUE"];
    $section_2 = $oRecordset[0]["portlets_right"]["VALUE"];


    if(!empty($section_1))
    {
        $portlet = explode(",", $section_1);
        for($z=0; $z<sizeof($portlet); $z++)
        {
            require_once($portlet[$z] . ".php");
        }
    }
    
?>
</div>
<div class="column" id="section-2">
<?php
    if(!empty($section_2))
    {
        $portlet = explode(",", $section_2);
        for($z=0; $z<sizeof($portlet); $z++)
        {
            require_once($portlet[$z] . ".php");
        }
    }
?>
</div>

and portlet update :

if(isset($_POST["components"]) && isset($_POST["section"]))
{
    $sListePortlet = preg_replace('/\,+/', ',', trim($_POST["components"],','));
    if($_POST["section"] == 'section-1')
    {
        $sQuery =
        "
            UPDATE portlet_user
            SET portlets_left   = " . fncSetString($sListePortlet) . "
            WHERE user_id               = " . fncSetInt($_SESSION["user_id"])   . ";
        ";
        fncQueryPg($sQuery);
    }
    if($_POST["section"] == 'section-2')
    {
        $sQuery =
        "
            UPDATE portlet_user
            SET portlets_right  = " . fncSetString($sListePortlet) . "
            WHERE user_id               = " . fncSetInt($_SESSION["user_id"])   . "
        ";
        fncQueryPg($sQuery);
    }
}
if(isset($_POST["state"]))
{
    $sQuery =
    "
        UPDATE portlet_user
        SET portlets_state          = " . fncSetString($_POST["state"]) . "
        WHERE user_id               = " . fncSetInt($_SESSION["user_id"])   . ";
    ";
    fncQueryPg($sQuery);
}

Note that you place eache portlet in a separate file : portlet_99.php where 99 = 01,02,...

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 hamza765
Solution 2