Search code examples
javascripthtmlangularjsgridsterangular-grid

Align gridster items using row and col values angularjs


I have created a dashboard using angularjs, kendoui charts and angular gridster (https://github.com/ManifestWebDesign/angular-gridster).

So I have a function to add a gridster with chart like below :-

// add widget to a dashboard
$scope.addWidget = function () {
  
  // new widget configuration
  var newWidget = {
    id: $scope.allWidgetData.selectedOption.id,
    data_source: {},
    config: {
      name: $scope.allWidgetData.selectedOption.name,
      sizeX: 3,
      sizeY: 2,
      row: $scope.row,
      col: $scope.col
    }  
  };
}

// make api call and save data

I can save this object to backend and get the values too. I am setting row and col values for each chart as follows as the sizeX and sizeY values are constant as 3 and 2.

  1. First chart row:0 and col:0
  2. Second chart row:0 and col:3
  3. Third chart row:2 and col:0
  4. Fourth chart row:2 and col:3

I referred and searched for solution on below pages :-

  1. Save gridster layout using angularjs

  2. https://github.com/ManifestWebDesign/angular-gridster

So now my HTML is like below so I set row and col values:-

<div gridster="gridsterOptions" ng-if="isShowing(index)">
    <ul>
        <li gridster-item="widget" ng-repeat="widget in widgetData.availableOptions" row="widget.config.row" col="widget.config.col" style="overflow:hidden;" >
            <div class="box">                         

            // kendo ui chart in  div
        </li>
    </ul>       
</div> 

My gridster configuration is like below :-

$scope.gridsterOptions = {
      minRows: 2, // the minimum height of the grid, in rows
      maxRows: 100,
      columns: 6, // the width of the grid, in columns
      colWidth: 'auto', // can be an integer or 'auto'.  'auto' uses the pixel width of the element divided by 'columns'
      rowHeight: 'match', // can be an integer or 'match'.  Match uses the colWidth, giving you square widgets.
      margins: [10, 10], // the pixel distance between each widget
      defaultSizeX: 3, // the default width of a gridster item, if not specifed
      defaultSizeY: 2, // the default height of a gridster item, if not specified
      mobileBreakPoint: 600, // if the screen is not wider that this, remove the grid layout and stack the items
      swapping: false,
      pushing: true,
      floating: false,
      resizable: {
          enabled: true,
          start: function(event, uiWidget, $element) {}, // optional callback fired when resize is started,
          resize: function (event, uiWidget, $element) {
          }, // optional callback fired when item is resized,
          stop: function(event, uiWidget, $element) {
          } // optional callback fired when item is finished resizing
      },
      draggable: {
         enabled: true, // whether dragging items is supported
         handle: '.box-header', // optional selector for resize handle
         start: function(event, uiWidget, $element) {}, // optional callback fired when drag is started,
         drag: function(event, uiWidget, $element) {}, // optional callback fired when item is moved,
         stop: function(event, uiWidget, $element) {          
        } // optional callback fired when item is finished dragging
      }
  };  

When I get the gridster items from backend they are in random order and gridster does not align them as per row and col values.


Solution

  • I created a working pen for you how to do this: https://codepen.io/shnigi/pen/JLVZpK

    I had a similar problem, this is how I tackled it. Make sure you are referencing to right object value. You may also have to set positions when your ajax call is ready:

    <li ng-repeat="widget in widgets"
              class="panel" gridster-item
              row="widget.posY"
              col="widget.posX"
              size-x="widget.width"
              size-y="widget.height">
            <div class="panel-heading">
              <h3 class="panel-title">{{widget.title}}</h3>
            </div>
    </li>
    

    Mobile breakpoints are also issue as you set the widget position and then you may have different resolution. So what I did here is that I am now using this fork:

    https://github.com/arkabide/angular-gridster

    I count the columns based on resolution and have "dynamic" columns turned on.

    $scope.gridsterOptions = {
      resizable: {
        enabled: false,
      },
      floating: true,
      pushing: true,
      swapping: true,
      isMobile: true,
      mobileBreakPoint: 768,
      columns: getColumns(),
      dynamicColumns: true,
      minWidthToAddANewColumn: 255,
      rowHeight: 400,
      draggable: {
        enabled: true,
        handle: '.panel-heading'
      }
    };
    
    const getColumns = () => {
      const browserWidth = $window.innerWidth;
      if (browserWidth < 1300) {
        return 3;
      } else if (browserWidth < 1500) {
        return 4;
      } else if (browserWidth < 1700) {
        return 5;
      }
      return 6;
    };
    

    There are some issues with the widget positioning if resolution changes, but this is the best solution I have got so far.

    So make sure you load all data before assigning it using promises. Pseudo code like this:

    const loadedWidgets = [];
        if (settings) {
          const loadAllWidgets = () => new Promise(resolve =>
              loadedWidgets.push(widget);
              resolve();
            }));
    
      const actions = settings.chartsettings.map(loadAllWidgets);
      Promise.all(actions).then(() => {
        const widgetList = loadedWidgets.map(widget => widget);
        $scope.widgets = widgetList;
      });
    }
    

    I guess your issue is related to object referencing or you are not setting position with promises. You can also try the fork I am using. Because for me this setup works and the widgets appear where I save them.