ManifestWebDesign / angular-gridster

An implementation of gridster-like widgets for Angular JS
http://manifestwebdesign.github.io/angular-gridster/
MIT License
964 stars 394 forks source link

Save/Restore layout #327

Open Tyderion opened 9 years ago

Tyderion commented 9 years ago

Hi there :) I hope you understand what I'm trying to do and how I tried to do that.

I'm trying to create a dashboard-like page by using angular-gridster.

This dashboard can either be edited (dragging/adding/removing of widgets enabled) or not. While editing, items can be added or removed.

Upon cancelling the edit, the old grid and all all items should be restored.

Adding/Removing

Sometimes restoring the grid works perfectly, sometimes a lot more gridsterItems get added to the grid than widgets are available. I'll try to describe the steps I take to (sometimes) reproduce this problem. I did not yet find a series of steps which always result in the problem, but it does it from time to time.

  1. At start we have a visible widget at {col: 0, row: 0}
  2. Then we start editing (oldGrid = _.clone(gridster.grid)) -> oldGrid = [{col: 0, row: 0}]
  3. Then I remove this widget (gridster.removeItem({col: 0, row: 0}) and widgetElement.hide()
  4. Then I add an additional widget (gridsterElement.append($compile(widget2)(scope))
  5. Right now the grid is "identical" to the old one, we still just have 1 item in the topleft most position, but a new one
  6. Then I cancel the editing (gridster.grid = _.clone(oldGrid), widgetElement.unhide(), widget2.remove())
  7. Grid now contains: {col: 0, row: 0}as well as {col: 0, row: 1} instead of just the first.
  8. If I add new items now, there is an empty space between the widgets, this is the space where gridster.grid has an item but there is no corresponding HTML-widget.

Is there a better way to remove widgets from the grid than calling gridster.removeItem? Is there a better way to save/restore the grid than just copying and the restoring it?

Thanks for trying to help :)

Please feel free to ask me to clarify unclear passages/things.

P.S. I did not manage to create a jsfiddle which exhibits this behaviour, I will update this issue if I manage that.

andrey-skl commented 9 years ago

You shouldn't use $compile to add new widget. Just use angular model and ng-repeat:

<div gridster="gridsterOptions">
    <ul>
      <li gridster-item ng-repeat="widget in widgets">
        <dashboard-widget widget="widget"></dashboard-widget>
      </li>
    </ul>
  </div>

When you need to add a widget just push it into $scope.widgets.array. When you need to edit, just make copy of $scope.widgets and store it. When you need to restore, just place it back $scope.widgets = $scope.storedWidgets. Should work.

Tyderion commented 9 years ago

thats a very good point, it somehow didn't even occur to me to do it with an ng-repeat.

Thanks for the heads up :)

jakepens71 commented 9 years ago

I use a combination of local storage and database (Oracle) saving as blob.

I have a button that calls a function in my controller:

$scope.dashboardJSON = angular.toJson($scope.standardItems);

    localStorageService.set("DashboardInfo", $scope.dashboardJSON);

    //Send HTTP request 'POST' to saveDashboard function in Rails controller
    $http({
        method: 'POST',
        url: 'saveDashboard',
        data: {'dashboardInfo': $scope.dashboardJSON },
        headers: {'Content-Type': 'application/json' }
        }).success(function(data, status, headers, config)
        {

        }).error(function(data, status, headers, config)
        {

        }); 

};

I use Rails as a backend web server so then it takes it from there to communicate with our Oracle database.

In order to load the desired content back into Gridster I have:

var dashboardInfo = localStorageService.get("DashboardInfo");

if (dashboardInfo == null)
{
    console.log("Loading from database");
    //Make an http request to get the current logged in user's saved dashboard
        $http({
        method: 'get',
        url: 'getSavedDashboard',
        headers: {'Content-Type': 'application/json' }
        }).success(function(data, status, headers, config)
        {
            //console.log(data);

            if (data == null)
            {

            }
            else
            {
                var parsedDashboard = angular.fromJson(data);
                //console.log(parsedDashboard[0]);

                for(var i = 0; i < parsedDashboard.length; i++)
                {
                    //console.log(parsedDashboard[i]);
                    $scope.standardItems.push(parsedDashboard[i]);
                    market.setMarket(parsedDashboard[i].market);
                }                           

                $scope.dashboardJSON = angular.toJson($scope.standardItems);
                localStorageService.set("DashboardInfo", $scope.dashboardJSON)
                $scope.successAlert();
            }

        }).error(function(data, status, headers, config)
        {

        });
}
else
{
    console.log("Loading from Local Storage");
    var parsedDashboard = angular.fromJson(dashboardInfo);
    for(var i = 0; i < parsedDashboard.length; i++)
    {
        console.log(parsedDashboard[i]);
        $scope.standardItems.push(parsedDashboard[i]);
        market.setMarket(parsedDashboard[i].market);
    }
    $scope.successAlert();
}

$scope.standardItems is already linked to Gridster. When the items are being returned they get automatically placed into gridster in their original spots.

I dont seem to have any trouble with Gridster when bringing objects back. I can move them around and resize them.

If it helps any, I have this as the gridster optoins:

$scope.gridsterOptions = {
        margins: [50, 50],
        columns: 2,
        draggable: {
            handle: 'h3'
        },
        width: 'auto',
        margins: [10, 10],
        rowHeight: 'auto',
        resize: {
            enabled: true,
             stop: function (event, ui) {
                //$(window).trigger('resize');

             }
        }
    };

Its a pretty basic set up.