2

here's the code & output: https://stackblitz.com/edit/d3-angular-gridster2-working-axhc7u?file=src%2Fapp%2Fgrid%2Fgrid.component.html

GRID-HTML

<gridster [options]="options">
  <gridster-item [item]="item" *ngFor="let item of dashboard">
   
  </gridster-item>
</gridster>

GRID-TS

ngOnInit() {
  @Input() editing: any;
    this.options = {
      gridType: GridType.Fit,
      displayGrid: DisplayGrid.Always,
      enableEmptyCellClick: false,
      enableEmptyCellContextMenu: false,
      enableEmptyCellDrop: false,
      enableEmptyCellDrag: false,
      enableOccupiedCellDrop: false,
      emptyCellClickCallback: this.emptyCellClick.bind(this),
      emptyCellContextMenuCallback: this.emptyCellClick.bind(this),
      emptyCellDropCallback: this.emptyCellClick.bind(this),
      emptyCellDragCallback: this.emptyCellClick.bind(this),
      emptyCellDragMaxCols: 50,
      emptyCellDragMaxRows: 50
    };

    this.dashboard = [
      { cols: 2, rows: 1, y: 0, x: 0 },
      { cols: 2, rows: 2, y: 0, x: 2 },
      { cols: 1, rows: 1, y: 0, x: 4 },
      { cols: 3, rows: 2, y: 1, x: 4 },
      { cols: 1, rows: 1, y: 4, x: 5 },
      { cols: 1, rows: 1, y: 2, x: 1 },
      { cols: 2, rows: 2, y: 5, x: 5 },
      { cols: 2, rows: 2, y: 3, x: 2 },
      { cols: 2, rows: 1, y: 2, x: 2 },
      { cols: 1, rows: 1, y: 3, x: 4 },
      { cols: 1, rows: 1, y: 0, x: 6 }
    ];
  }

What I'm trying to do here is to enabled the enableEmptyCellDrag. for example I clicked the button edit then the value of edit is true and then the value of enableEmptyCellDrag is true.

I already tried this:

ngOnChanges() {
 ///this.options['enableEmptyCellDrag'] = true // the enableEmptyCellDrag is undefined
 ///if (this.editing) {
 /// this.options['enableEmptyCellDrag'] = true // the value of enableEmptyCellDrag is change to true, but when I try to drag from the empty cell it doesn't work
 ///}

}
ABC
  • 752
  • 4
  • 17
  • 40

2 Answers2

1

If I understand correctly, you want to set this.options['enableEmptyCellDrag'] to the value of @Input() editing.

And you want to gridster2 (I must admit I don't know what this is) to recognise the change.

So you have 2 problems:

  1. When you're in ngOnChanges, accessing your @Input() directly will give you the "old" value.

  2. Usually, for Angular to detect changes in objects, you need to change the reference of the object.

So this is what your ngOnChanges should look like.

  ngOnChanges(changes: SimpleChanges) {
    if (changes.editing && changes.editing.currentValue) {
      // Solve problem 1)
      const newValueOfEditingInput = changes.editing.currentValue;

      // Solve Problem 2) - Create a new reference for this.options, so that angular (grister2) can detect the change
      this.options = {
        ...this.options,
        enableEmptyCellDrag: newValueOfEditingInput
      };
    }
  }

Of Course I haven't tested this but I hope it can help you

Tonio
  • 4,082
  • 4
  • 35
  • 60
  • Question what If it cancel. it shouldn't able to drag. – ABC Nov 04 '20 at 15:32
  • 1
    Sorry like I said, I'm good with Angular but I don't know this gridster component or what it is suppose to achieve so it's hard for me to help you on this – Tonio Nov 04 '20 at 15:34
  • ahmm.. how it will return to false? cause When I click the edit the value of ```enableEmptyCellDrag```. but when it false it still true. – ABC Nov 04 '20 at 15:37
  • I agree but don't understand why its this messy... your assigning options back to itself with allows gridster to detect and initiate any changes declared to options... but generally I should just have to change the option it would be detected, at least in most frameworks... this seems odd. – gunslingor May 23 '21 at 10:16
  • Understanding this key to avoiding bug in Angular (and any javascript framework in general). Change detection works when you're changing the reference of the Input. And if your @Input is an object or an array, changing inner properties won't change the reference (which won't trigger change detection). I agree and understand that it's very confusing in the javascript world, it's a real challenge to master. – Tonio May 23 '21 at 16:26
0

I found a more elegant solution IMHO.

The GridsterConfig object has an api.optionsChanged sub-object which is a function. If you run it that also tells Gridster the options changes without having to, essentially, re-instantiate the object (which probably just runs this function anyway). Seems safer and more elegant.

Thus, your on change can now look like this:

  ngOnChanges(changes: SimpleChanges) {
    if (changes.editing && changes.editing.currentValue) {
      this.options.enableEmptyCellDrag = changes.editing.currentValue;
      this.options.api.optionsChanged();
    }
  }

I also suggest creating a class like the following, which will prevent you from being forced to check if these options exist or not (the if statement is just checking to see if the GridsterConfig interface optional options are defined... so if you define them ahead of time there is no need to do that... not sure why Gridster made there existence optional... IMHO the options should always exist but can be set to null or a default).

export class DashboardOptions implements GridsterConfig{
  gridType = GridType.Fit;
  compactType = CompactType.None;
  margin = 10;
  outerMargin = false;
  outerMarginTop = null;
  outerMarginRight = null;
  outerMarginBottom = null;
  outerMarginLeft = null;
  useTransformPositioning = true;
  mobileBreakpoint = 720;
  minCols = 1;
  maxCols = 100;
  minRows = 1;
  maxRows = 100;
  maxItemCols = 100;
  minItemCols = 1;
  maxItemRows = 100;
  minItemRows = 1;
  maxItemArea = 2500;
  minItemArea = 1;
  defaultItemCols = 1;
  defaultItemRows = 1;
  fixedColWidth = 105;
  fixedRowHeight = 105;
  keepFixedHeightInMobile = false;
  keepFixedWidthInMobile = false;
  scrollSensitivity = 10;
  scrollSpeed = 20;
  enableEmptyCellClick = false;
  enableEmptyCellContextMenu = false;
  enableEmptyCellDrop = false;
  enableEmptyCellDrag = false;
  enableOccupiedCellDrop = false;
  emptyCellDragMaxCols = 50;
  emptyCellDragMaxRows = 50;
  ignoreMarginInRow = false;
  public draggable = {
    enabled: false,
    delayStart: 200,
    start: () => {},
    stop: () => {}
  };
  public resizable = {
    enabled: true,
    delayStart: 200,
    start: () => {},
    stop: () => {}
  };
  swap = false;
  pushItems = true;
  disablePushOnDrag = false;
  disablePushOnResize = false;
  pushDirections = {north: true, east: true, south: true, west: true};
  pushResizeItems = false;
  displayGrid = DisplayGrid.Always;
  disableWindowResize = false;
  disableWarnings = false;
  scrollToNewItems = false;
  api = {
    resize: () => {},
    optionsChanged: () => {},
  };
  itemChangeCallback = (item: GridsterItem, itemComponent: GridsterItemComponentInterface) => {};
}

Then, your on change can now look like this:

  ngOnChanges(changes: SimpleChanges) {
      this.options.enableEmptyCellDrag = changes.editing.currentValue;
      this.options.api.optionsChanged();
  }
gunslingor
  • 1,358
  • 12
  • 34