# Column Moving

## Live example

{% hint style="success" %}
[Column Moving](https://demos.dikesoft.com/dk-grid/column/moving) live example.
{% endhint %}

## Allowing column dragging

To allow the user moves a column, you must set a flag at the grid scope by providing an input DikeGrid property named <mark style="color:orange;">`allowColumnDragging`</mark>. Its **default** value is **false**.

{% code title="column-moving.component.html" %}

```markup
<dike-grid id="grid-col-moving" height="650px" #grid="dkgGrid"
    [allowColumnDragging]="gridProperties.allowColumnDragging">
</dike-grid>
```

{% endcode %}

{% hint style="info" %}
You can change the value of the <mark style="color:orange;">`allowColumnDragging`</mark> property at runtime.
{% endhint %}

You can open the [Floating Configuration Panel](https://docs.dikesoft.com/overview#floating-configuration-panel) of the live demo and change the value of the property <mark style="color:orange;">`allowColumnDragging`</mark>.

![Floating Configuration Panel - Dragging](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2Fv8NyyoupJ0lcSqptEayo%2Fdragging-panel-conf.png?alt=media\&token=982a2a66-6959-4cc4-8515-2cbcd9d9beca)

## Draggable Columns

You can make a column **movable** by providing a property named <mark style="color:orange;">`draggable`</mark>. Its **default** value is **false**.

{% hint style="warning" %}
Be aware that you can not change the <mark style="color:orange;">`draggable`</mark> property at runtime. Use the <mark style="color:orange;">`locked`</mark> property instead if you want the user not to move a column at runtime. For more details, see the Column Pinning section.
{% endhint %}

Let us set the following column configuration:

{% code title="column-moving.component.html" %}

```markup
<dike-grid id="grid-col-moving" height="650px" #grid="dkgGrid"
    allowRowGrouping
    allowColumnDragging>

    <dike-grid-column
        fieldName="employeeId"
        headerText="Employee Id"
        dataType="Text"
        width="350"
        order="0"
        draggable>
    </dike-grid-column>

    <dike-grid-column
        fieldName="firstName"
        headerText="Name"
        dataType="Text"
        width="150"
        order="2">
    </dike-grid-column>

    <dike-grid-column
        fieldName="lastName"
        headerText="Surname"
        dataType="Text"
        width="150"
        minWidth="50"
        maxWidth="300"
        order="1"
        resizable
        draggable
        groupable>
    </dike-grid-column>

    <dike-grid-column
        fieldName="personalInfoGroup"
        headerText="Personal Info"
        order="0"
        resizable
        draggable>
        <dike-grid-column
            fieldName="completeNameGroup"
            headerText="Complete Name"
            draggable>

            <dike-grid-column
                fieldName="firstName"
                headerText="Name"
                dataType="Text"
                width="150"
                minWidth="50"
                maxWidth="300"
                resizable>
            </dike-grid-column>

            <dike-grid-column
                fieldName="lastName"
                headerText="Surname"
                dataType="Text"
                width="150"
                minWidth="50"
                maxWidth="300"
                resizable>
            </dike-grid-column>
        </dike-grid-column>

        <dike-grid-column
            fieldName="gender"
            headerText="Gender"
            dataType="Binary"
            width="110"
            minWidth="50"
            maxWidth="200"
            resizable
            draggable
            groupable>
        </dike-grid-column>

        <dike-grid-column
            fieldName="age"
            headerText="Age"
            dataType="Numeric"
            contentAlign="center"
            width="85"
            minWidth="50"
            maxWidth="120"
            resizable
            draggable
            groupable>
        </dike-grid-column>
    </dike-grid-column>

    <dike-grid-column
        fieldName="hireDate"
        headerText="Hire Date"
        dataType="Date"
        order="1"
        draggable
        groupable
        panel="rightPanel">
    </dike-grid-column>
</dike-grid>
```

{% endcode %}

With this configuration, we have:

1. All columns and column groups are **movable** except the **Name** column in the **root** group and the **Name** and **Surname** columns under the **Complete Name** group.
2. We have enabled the row grouping to move columns to the group panel. Columns **Surname** and **Hire Date** from the **root** group are **groupable**. **Gender** and **Age** columns under the **Personal Info** group are **groupable** as well.
3. All columns are in the center panel except the **Hire Date** column in the right panel.

{% hint style="warning" %}
You can move only **data** columns to the **group panel**, not column groups.

When you move a column group to the group panel using the **API**, the movement inserts only the **descendant data columns** into the group panel.
{% endhint %}

## Column movements

Once we have established some columns as **draggable**, be aware of the valid movements a column could take.

{% hint style="success" %}
For the description of the following movements, it will be helpful to grasp the [Gutters](https://docs.dikesoft.com/fundamentals/grid-structure/gutters) structure of the DikeGrid.
{% endhint %}

### Interchange Columns

This movement will swap two columns. The **source column** will take the **destination column's** place and vice versa. For this movement, the following rules apply:

1. The columns must belong to the same group of columns.
2. You can interchange columns that belong to the Content panels.

![Interchange Columns](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FyOZckxOd9Yca3iXtSwlQ%2Fcolumn-moving-interchange.gif?alt=media\&token=3e990ddb-b3de-4c1e-ae6f-907c56c41cc7)

{% hint style="info" %}
If you try to swap a ***broken group***, you will join the group in the destination panel.
{% endhint %}

### Move Column Before

You can move a column ***before*** another column.&#x20;

Let us say that you can move a given **column** at the left side of the **target column**. The actual movement will insert the given **column** at the **left-gutter** of the **target column**. Therefore, consider the following rules:

1. Columns must belong to the same group of columns.
2. The target column must belong to the right panel because columns have their gutter at their left.
3. If the target column lives in the left, center panel, or group panel, it must be the first column because they have both gutters.

![Move Column Before](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2Ft77Q1WxMIWFaepkjEg7T%2Fcolumn-moving-before.gif?alt=media\&token=c6202027-2f93-47bb-bd2a-385d9d33bc7f)

### Move Column After

You can move one column ***after*** another column.

Same as before, let us say that you can move a given **column** at the right side of the **target column**. The actual movement will insert the given **column** at the **right-gutter** of the **target column**.&#x20;

The rules are:

1. Columns must belong to the same group of columns.
2. The target column must belong to the group, left or center panel because columns have their gutter at their right.
3. If the target column lives in the right panel, it must be the last column because it has both gutters.

![Move Column After](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FUbMI1bz6vghgLVdxmGyp%2Fcolumn-moving-after.gif?alt=media\&token=f1125acd-0ee2-4ca1-8fde-7066706d39c5)

### Column to panel&#x20;

This movement is possible when you drag a column to the ***left*** or ***right*** grid **border** or use the ***Pinning*** submenu of the **Column Context Menu**.

#### Drag a column to the grid's borders

Drag a column to the left or right grid border, as you can see in the following gif.

![Column to panel](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FgY5VFTMDoMXYJ95GLdzu%2Fcolumn-moving-column-to-panel.gif?alt=media\&token=b6a4b6ad-4c1c-4897-98e5-24a4aa02cda8)

#### Using the Column Context Menu

Now, click on any [Column Context Menu](https://docs.dikesoft.com/fundamentals/grid-structure/column-context-menu) and select a panel to move the column.

![Column to panel using the Column Context Menu](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FROhT5TqujX5X5ffoeoun%2Fcolumn-moving-column-to-panel-context-menu.gif?alt=media\&token=0738ce07-8221-4ce1-a953-372a09424373)

{% hint style="info" %}
It is possible to move **all panel columns** to another panel using the **column** **API**.
{% endhint %}

## Breaking a column group&#x20;

You can take a column that belongs to a column group and place it in another panel. This move grabs the column with its parent column and its parent, and so forth until the root.

The movement's outcome is a ***broken group***. For example, we moved the **Gender** column to the left panel. See the final state of the **Personal Info** group in the following screenshot.

![Breaking a column group](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2F28ThfZmMehgD6f6xHac2%2Fcolumn-moving-broken-groups.png?alt=media\&token=cd1e6187-717d-4c9d-89e2-16733f9592b6)

### Unbroken column groups

If you do not want the user breaks a group, make its child columns **non-draggable**, as we did for **Name** and **Surname** columns under the **Complete Name** column group.

{% code title="column-moving.component.html" %}

```markup
<dike-grid-column
        fieldName="completeNameGroup"
        headerText="Complete Name"
        draggable>
        <dike-grid-column
            fieldName="firstName"
            headerText="Name"
            dataType="Text"
            width="150"
            minWidth="50"
            maxWidth="300"
            resizable>
        </dike-grid-column>

        <dike-grid-column
            fieldName="lastName"
            headerText="Surname"
            dataType="Text"
            width="150"
            minWidth="50"
            maxWidth="300"
            resizable>
        </dike-grid-column>
</dike-grid-column>
```

{% endcode %}

You can not move the **Name** column or the **Surname** column. You can only move those columns by dragging the **Complete Name** group.

![Unbroken column groups](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2FzlDMsIeprjaBRO9wAixr%2Fcolumn-moving-unbroken-groups.gif?alt=media\&token=2d5fb79f-3c42-4e42-b05d-405ae7fc7e29)

{% hint style="info" %}
When you drag a column, the DikeGrid instance **highlights** the proper columns or gutters to drop the column you are moving.
{% endhint %}

## Move columns using the API

You can achieve the previous movements using the column API.

{% hint style="info" %}
Remember, to use the **column API**, you must grab the instance of the [<mark style="color:green;">`DikeGridColumnDef`</mark>](https://docs.dikesoft.com/reference/dkgrid-api/dkgridcolumndef#methods)service.
{% endhint %}

The following table shows the desired movement and its related method in the column API.

| Movement            | Method(s)                                                                                                                                            |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| Interchange Columns | `swapColumns()`                                                                                                                                      |
| Move Column Before  | `moveColumnBefore()`                                                                                                                                 |
| Move Column After   | `moveColumnAfter()`                                                                                                                                  |
| Column to Panel     | <p><code>moveColumnIntoPanel()</code><br><br>To move all columns from one panel to another panel, use the method <code>movePanelColumns()</code></p> |

{% hint style="success" %}
For further details, see the [<mark style="color:green;">`DikeGridColumnDef`</mark>](https://docs.dikesoft.com/reference/dkgrid-api/dkgridcolumndef#methods)definition.
{% endhint %}

{% hint style="info" %}
Even though you do not set the flag <mark style="color:orange;">`allowColumnDragging`</mark>, you can move a column using the API, but the column must be set as **draggable** and not **locked**.
{% endhint %}

To see the use of the API, we have created the following UI:

{% code title="column-moving.component.html" %}

```markup
<form [formGroup]="moveColumnsForm"
    class="mt-2 flex flex-row flex-wrap items-center justify-around">
    <mat-form-field appearance="fill"
        class="flex-none w-56 m-2">
        <mat-label>Source</mat-label>
        <mat-select formControlName="source" required
            (selectionChange)="onSourceSelectionChange($event)">
            <mat-option *ngFor="let column of gridColumns" [value]="column" [disabled]="!column.draggable || column.locked">
                {{ column.headerText }}
            </mat-option>
            <mat-option *ngFor="let panel of gridPanels" [value]="panel">
                {{ panel }}
            </mat-option>
        </mat-select>
    </mat-form-field>

    <mat-form-field appearance="fill"
        class="flex-none w-56 m-2">
        <mat-label>Destination</mat-label>
        <mat-select formControlName="destination" required
            (selectionChange)="onDestinationSelectionChange($event)">
            <mat-option *ngFor="let column of destinationColumns" [value]="column" [disabled]="!column.draggable || column.locked">
                {{ column.headerText }}
            </mat-option>
            <mat-option *ngFor="let panel of destinationPanels" [value]="panel">
                {{ panel }}
            </mat-option>
        </mat-select>
    </mat-form-field>

    <mat-radio-group class="flex-none w-40 m-2 flex flex-col"
        #radioMethods="matRadioGroup" formControlName="method" required>
        <mat-radio-button class="my-2" value="swap-columns">swap-columns</mat-radio-button>
        <mat-radio-button class="my-2" value="column-after">column-after</mat-radio-button>
        <mat-radio-button class="my-2" value="column-before">column-before</mat-radio-button>
    </mat-radio-group>

    <div class="flex-none w-56 flex flex-col m-2 items-center">
        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            [disabled]="radioMethods.disabled || !moveColumnsForm.valid"
            (click)="onMoveColumns()">Move column(s)
        </button>

        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            [disabled]="!radioMethods.disabled"
            (click)="onMoveColumnsToPanel()">Move column(s) to Panel
        </button>
    </div>
</form>
```

{% endcode %}

We added the <mark style="color:red;">`form`</mark> selector above the <mark style="color:red;">`dike-grid`</mark> selector, generating the following output:

![Moving columns using the API](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2F4VGYri3SxZQ7mVgT6xHt%2Fcolumn-moving-ui-for-api.png?alt=media\&token=1b6d7168-f4e5-445a-82e8-53b93aaa16d6)

With the previous UI, you can do the following tasks:

1. You can choose the source column or the source panel from the first select control.
2. Depending on your selected option, the second dropdown control will have a proper destination place. For instance, if you choose a column, the destination control will contain all columns of the same group and panels the column does not live.
3. The radio-button group has methods that involve column between column movements.
4. When you select panels, the corresponding button is enabled.

It is essential to notice that we are **listening** to any change in the **DikeGrid's columns**, attaching a subscription to the `columnsChange` <mark style="color:green;">`Observable`</mark> from the <mark style="color:green;">`DikeGridColumnDef`</mark>.

{% code title="column-moving.component.ts" %}

```typescript
private setChangeGridColumnsSubscription(): void {
  this.changeGridColumnsSubscription.unsubscribe();
  this.changeGridColumnsSubscription = this.dikeGrid.columnDef.columnsChange.pipe(
    map((columns: DikeColumnDef[]) => this.flatColumns(columns)),
    observeOn(asapScheduler)

  ).subscribe((columns) => {
    this.destinationColumns = null;
    this.destinationPanels = null;
    this.moveColumnsForm.patchValue({ source: null, destination: null, method: '' });
    this.moveColumnsForm.get('method').enable();
    this.gridColumns = columns;
  });
}
```

{% endcode %}

Every time we receive a new set of columns, we flat them into a single array, invoking the method `flatColumns()`. So indeed, we are **flattening** the **column groups**, traversing them **recursively**.

{% code title="column-moving.component.ts" %}

```typescript
private flatColumns(columns: DikeColumnDef[]): DikeColumnDef[] {
  return columns.reduce((accum, column) => {
    if (isDikeGroupColumnDef(column) && !!column.children && column.children.length > 0) {
      return [ ...accum, column, ...this.flatColumns(column.children) ];
    }

    return [ ...accum, column ];
  }, [ ]);
}
```

{% endcode %}

If you see the content of the **source dropdown** control, you see the columns **Hire Date**, **Employee Id**, **Personal Info** group, **Complete Name** group, then **Name** and **Surname** columns, **Gender** and **Age** columns, etc.

![Flattening column groups](https://3888584995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpDxfe6pgRLqBLMQgZ0kG%2Fuploads%2Fdk5enRB6YBZoLRYSejkn%2Fcolumn-moving-flattening-groups.png?alt=media\&token=b56d96a6-e508-40ad-a368-ae31eabd0c0c)

{% hint style="info" %}
The **non-draggable** columns are **disabled**, such as **Name** and **Surname**, under the **Complete Name** group.
{% endhint %}

## Column Moving Events

Every previous movement emits an event of type <mark style="color:green;">`DikeColumnMoveEvent`</mark>. We listen to the `columnMove` event at the grid scope.

{% tabs %}
{% tab title="column-moving.component.html" %}

```markup
<dike-grid id="grid-col-moving" height="650px" #grid="dkgGrid"
    (columnMove)="onColumnMove($event)">
</dike-grid>
```

{% endtab %}

{% tab title="column-moving.component.ts" %}

```typescript
onColumnMove(movementData: DikeColumnMoveEvent): void {
    console.log('Column movement: ', movementData);
}
```

{% endtab %}
{% endtabs %}

{% hint style="success" %}
You can also listen to the `columnMove` event from the [<mark style="color:green;">`DikeGridColumnDef<T>`</mark>](https://docs.dikesoft.com/reference/dkgrid-api/dkgridcolumndef#events) instance.
{% endhint %}

See the definition of the <mark style="color:green;">`DikeColumnMoveEvent`</mark> interface:

```typescript
interface DikeColumnMoveEvent {
  type: ColumnMovement;
  movedColumns: DikeColumnDef[];
  beforeColumn?: DikeColumnDef;
  afterColumn?: DikeColumnDef;
  destinationPanel?: DikeGridPanel;
}
```

And the <mark style="color:green;">`ColumnMovement`</mark> definition is:

```typescript
type ColumnMovement = 'swap-columns' | 'join-column-groups' | 'column-after' | 'column-before' | 'columns-to-panel';
```

As you can see, some fields are not required. However, depending on the type of movement, those fields are provided.

| Movement            | DikeColumnMoved                                                                                                                                                                                                                                                 |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Interchange Columns | <p><strong>type</strong>: <mark style="color:red;">swap-columns</mark>.<br><strong>movedColumns</strong>: The source and destination columns.</p>                                                                                                               |
| Interchange Columns | <p><strong>type</strong>: <mark style="color:red;">join-column-groups</mark>.<br><strong>movedColumns</strong>: The joined column group.<br><strong>destinationPanel</strong>: The panel the broken-destination group lives.</p>                                |
| Move Column Before  | <p><strong>type</strong>: <mark style="color:red;">column-before</mark>.<br><strong>movedColumns</strong>: The source column.<br><strong>beforeColumn</strong>: The target column.<br><strong>destinationPanel</strong>: The panel the target column lives.</p> |
| Move Column After   | <p><strong>type</strong>: <mark style="color:red;">column-after</mark>.<br><strong>movedColumns</strong>: The source column.<br><strong>afterColumn</strong>: The target column.<br><strong>destinationPanel</strong>: The panel the target column lives.</p>   |
| Column to panel     | <p><strong>type</strong>: <mark style="color:red;">columns-to-panel</mark>.<br><strong>movedColumns</strong>: The source columns or all panel columns.<br><strong>destinationPanel</strong>. The provided panel is the destination panel.</p>                   |

{% hint style="success" %}
You can open the **dev console** for the live demo and see the emitted **event**.
{% endhint %}

## Summary

Before defining which columns will be movable, you must allow this action by providing a property named <mark style="color:orange;">`allowColumnDragging`</mark> at the grid scope. To move a column, you must define a column as **draggable**. You can **interchange** columns only from the **Content panels**, and you can only add **data columns** to the **group panel**. You can move columns using the [Column Context Menu](https://docs.dikesoft.com/fundamentals/grid-structure/column-context-menu) as well.

### Complete code for this section

{% tabs %}
{% tab title="column-moving.component.html" %}

```markup
<form [formGroup]="moveColumnsForm"
    class="mt-2 flex flex-row flex-wrap items-center justify-around">
    <mat-form-field appearance="fill"
        class="flex-none w-56 m-2">
        <mat-label>Source</mat-label>
        <mat-select formControlName="source" required
            (selectionChange)="onSourceSelectionChange($event)">
            <mat-option *ngFor="let column of gridColumns" [value]="column" [disabled]="!column.draggable || column.locked">
                {{ column.headerText }}
            </mat-option>
            <mat-option *ngFor="let panel of gridPanels" [value]="panel">
                {{ panel }}
            </mat-option>
        </mat-select>
    </mat-form-field>

    <mat-form-field appearance="fill"
        class="flex-none w-56 m-2">
        <mat-label>Destination</mat-label>
        <mat-select formControlName="destination" required
            (selectionChange)="onDestinationSelectionChange($event)">
            <mat-option *ngFor="let column of destinationColumns" [value]="column" [disabled]="!column.draggable || column.locked">
                {{ column.headerText }}
            </mat-option>
            <mat-option *ngFor="let panel of destinationPanels" [value]="panel">
                {{ panel }}
            </mat-option>
        </mat-select>
    </mat-form-field>

    <mat-radio-group class="flex-none w-40 m-2 flex flex-col"
        #radioMethods="matRadioGroup" formControlName="method" required>
        <mat-radio-button class="my-2" value="swap-columns">swap-columns</mat-radio-button>
        <mat-radio-button class="my-2" value="column-after">column-after</mat-radio-button>
        <mat-radio-button class="my-2" value="column-before">column-before</mat-radio-button>
    </mat-radio-group>

    <div class="flex-none w-56 flex flex-col m-2 items-center">
        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            [disabled]="radioMethods.disabled || !moveColumnsForm.valid"
            (click)="onMoveColumns()">Move column(s)
        </button>

        <button mat-raised-button
            class="flex-none w-56 my-2"
            color="primary"
            [disabled]="!radioMethods.disabled"
            (click)="onMoveColumnsToPanel()">Move column(s) to Panel
        </button>
    </div>
</form>

<dike-grid id="grid-col-moving" height="650px" #grid="dkgGrid"
    [displayRowId]="gridProperties.displayRowId"
    [gridElevation]="gridProperties.matElevation"
    [gridElevationValue]="gridProperties.elevationValue"
    [striped]="gridProperties.stripeRows"
    [verticalRowLines]="gridProperties.verticalRowLines"

    (columnMove)="onColumnMove($event)"

    [allowColumnDragging]="gridProperties.allowColumnDragging"
    allowRowGrouping

    [datasource]="dkgDataSource">

    <dike-grid-column
        fieldName="employeeId"
        headerText="Employee Id"
        dataType="Text"
        width="350"
        order="0"
        draggable>
    </dike-grid-column>

    <dike-grid-column
        fieldName="firstName"
        headerText="Name"
        dataType="Text"
        width="150"
        order="3">
    </dike-grid-column>

    <dike-grid-column
        fieldName="lastName"
        headerText="Surname"
        dataType="Text"
        width="150"
        minWidth="50"
        maxWidth="300"
        order="2"
        resizable
        draggable
        groupable>
    </dike-grid-column>

    <dike-grid-column
        fieldName="personalInfoGroup"
        headerText="Personal Info"
        order="1"
        resizable
        draggable>
        <dike-grid-column
            fieldName="completeNameGroup"
            headerText="Complete Name"
            draggable>
            <dike-grid-column
                fieldName="firstName"
                headerText="Name"
                dataType="Text"
                width="150"
                minWidth="50"
                maxWidth="300"
                resizable>
            </dike-grid-column>

            <dike-grid-column
                fieldName="lastName"
                headerText="Surname"
                dataType="Text"
                width="150"
                minWidth="50"
                maxWidth="300"
                resizable>
            </dike-grid-column>
        </dike-grid-column>

        <dike-grid-column
            fieldName="gender"
            headerText="Gender"
            dataType="Binary"
            width="110"
            minWidth="50"
            maxWidth="200"
            resizable
            draggable
            groupable>
        </dike-grid-column>

        <dike-grid-column
            fieldName="age"
            headerText="Age"
            dataType="Numeric"
            contentAlign="center"
            width="85"
            minWidth="50"
            maxWidth="120"
            resizable
            draggable
            groupable>
        </dike-grid-column>
    </dike-grid-column>

    <dike-grid-column
        fieldName="hireDate"
        headerText="Hire Date"
        dataType="Date"
        width="125"
        order="4"
        draggable
        groupable
        panel="rightPanel">
    </dike-grid-column>
</dike-grid>
```

{% endtab %}

{% tab title="column-moving.component.ts" %}

```typescript
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { MatSelectChange } from '@angular/material/select';

import { asapScheduler, Subscription } from 'rxjs';
import { map, observeOn } from 'rxjs/operators';

import { DikeColumnDef, DikeGridComponent, DikeGridDataSourceInput, isDikeGroupColumnDef, DikeGridPanel, DikeColumnMoveEvent } from '@dikesoft/angular-data-grid';
import { Employee } from 'app/mock-api/common/employees/data.model';
import { DikeGridProperties } from 'app/core/config/dike-grid.properties';

import { DikeGridConfig } from 'app/services/dike-grid.config.service';
import { SampleData } from 'app/services/sample-data.service';

@Component({
  selector: 'column-moving',
  templateUrl: './column-moving.component.html',
  styleUrls: ['./column-moving.component.scss'],

  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ColumnMovingComponent implements OnInit, AfterViewInit, OnDestroy {
  // Retrieve the DikeGridComponent<T> instance from the view:
  @ViewChild('grid') dikeGrid: DikeGridComponent<Employee>;

  dkgDataSource: DikeGridDataSourceInput<Employee>;
  gridProperties: DikeGridProperties;

  gridColumns: DikeColumnDef[];
  gridPanels: DikeGridPanel[];
  destinationColumns: DikeColumnDef[];
  destinationPanels: DikeGridPanel[];

  disableMethods: boolean;
  moveColumnsForm: FormGroup;

  private changeGridColumnsSubscription: Subscription = Subscription.EMPTY;
  private changeGridPropertiesSubscription: Subscription = Subscription.EMPTY;

  constructor(
    private cdr: ChangeDetectorRef,
    private gridConfig: DikeGridConfig,
    private sampleData: SampleData) {

    this.gridPanels = ['groupPanel', 'leftPanel', 'centerPanel', 'rightPanel'];
  }

  ngOnInit(): void {
    this.dkgDataSource = this.sampleData.getEmployees(1000);
    // Listening to any config property change:
    this.setChangeGridPropertiesSubscription();
    this.createForm();
  }

  ngAfterViewInit(): void {
    // We listen the columnsChange observable after the DikeGrid instance is ready:
    this.setChangeGridColumnsSubscription();
  }

  ngOnDestroy(): void {
    this.changeGridPropertiesSubscription.unsubscribe();
    this.changeGridColumnsSubscription.unsubscribe();
  }

  onSourceSelectionChange(data: MatSelectChange): void {
    const source = data.value;
    let sourcePanel: DikeGridPanel;

    this.destinationColumns = null;
    this.moveColumnsForm.patchValue({ destination: null, method: '' });
    this.moveColumnsForm.get('method').enable();

    if (source instanceof DikeColumnDef) {
      // We get only those columns in the same group:
      this.destinationColumns = this.gridColumns.filter(column => column !== source &&
        column.belongToGroup === source.belongToGroup);

      sourcePanel = source.panel;

    } else {
      sourcePanel = source as DikeGridPanel;
    }

    // We take the panels different from the source selection:
    this.destinationPanels = this.gridPanels.filter(panel => sourcePanel !== panel);
  }

  onDestinationSelectionChange(data: MatSelectChange): void {
    const destination = data.value;

    if (!(destination instanceof DikeColumnDef)) {
      this.moveColumnsForm.patchValue({ method: '' });
      this.moveColumnsForm.get('method').disable();

    } else {
      this.moveColumnsForm.get('method').enable();
    }
  }

  onMoveColumns(): void {
    if (this.moveColumnsForm.valid) {
      // Take the columns from the form:
      const sourceColumn = this.moveColumnsForm.get('source').value as DikeColumnDef;
      const destinationColumn = this.moveColumnsForm.get('destination').value as DikeColumnDef;
      // Take the method to be invoked:
      const method = this.moveColumnsForm.get('method').value as string;

      switch (method) {
        case 'swap-columns':
          this.dikeGrid.columnDef.swapColumns(sourceColumn, destinationColumn);
          break;

        case 'column-after':
          this.dikeGrid.columnDef.moveColumnAfter(sourceColumn, destinationColumn);
          break;

        case 'column-before':
          this.dikeGrid.columnDef.moveColumnBefore(sourceColumn, destinationColumn);
          break;
      }
    }
  }

  onMoveColumnsToPanel(): void {
    const source = this.moveColumnsForm.get('source').value;
    const destinationPanel = this.moveColumnsForm.get('destination').value as DikeGridPanel;

    if (!!source && !!destinationPanel) {
      if (source instanceof DikeColumnDef) {
        // Move the selected column to the destination panel:
        this.dikeGrid.columnDef.moveColumnIntoPanel(source, destinationPanel);

      } else {
        // Move all columns from the source panel to the destnation panel:
        this.dikeGrid.columnDef.movePanelColumns(source as DikeGridPanel, destinationPanel);
      }
    }
  }

  onColumnMove(movementData: DikeColumnMoveEvent): void {
    console.log('Column movement: ', movementData);
  }

  private createForm(): void {
    this.moveColumnsForm = new FormGroup({
      source: new FormControl(null, Validators.required),
      destination: new FormControl(null, Validators.required),
      method: new FormControl({ value: '', disabled: false }, Validators.required),
    });
  }

  private flatColumns(columns: DikeColumnDef[]): DikeColumnDef[] {
    return columns.reduce((accum, column) => {
      if (isDikeGroupColumnDef(column) && !!column.children && column.children.length > 0) {
        return [ ...accum, column, ...this.flatColumns(column.children) ];
      }

      return [ ...accum, column ];
    }, [ ]);
  }

  private setChangeGridColumnsSubscription(): void {
    this.changeGridColumnsSubscription.unsubscribe();
    this.changeGridColumnsSubscription = this.dikeGrid.columnDef.columnsChange.pipe(
      map((columns: DikeColumnDef[]) => this.flatColumns(columns)),
      observeOn(asapScheduler)

    ).subscribe((columns) => {
      this.destinationColumns = null;
      this.destinationPanels = null;
      this.moveColumnsForm.patchValue({ source: null, destination: null, method: '' });
      this.moveColumnsForm.get('method').enable();
      this.gridColumns = columns;
    });
  }

  private setChangeGridPropertiesSubscription(): void {
    this.changeGridPropertiesSubscription.unsubscribe();
    this.changeGridPropertiesSubscription = this.gridConfig.configChange.subscribe((props: DikeGridProperties) => {
      this.gridProperties = props;
      this.cdr.markForCheck();
    });
  }
}

```

{% endtab %}
{% endtabs %}
