Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Angular ng2 dragula scroll not working properly #1093

Open
Virus35 opened this issue Jul 11, 2023 · 0 comments
Open

Angular ng2 dragula scroll not working properly #1093

Virus35 opened this issue Jul 11, 2023 · 0 comments

Comments

@Virus35
Copy link

Virus35 commented Jul 11, 2023

i am using ng2 dragula's COLUMNS feature of dragging and dropping and in that when the scroller comes, i am unable to scroll up/down while drag/drop.

.ts file:-

import { HttpErrorResponse } from '@angular/common/http';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { MenuAPI } from '@api/menu.api';
import { ViewAPI } from '@api/view.api';
import {
    AlertBoxRespone,
    CommonResp,
    EDITVIEWRES,
    Menu,
    SCREENTITLE,
    StatusCodeMessageAPIResponse,
    VIEWLIST
} from '@interface';
import { ALERTBOXOBJ, AlertBoxService, AlertID, AlertMessages } from '@service/alert-box.service';
import { ApiHandleService, LOADERSTATE, TOASTRTYPE } from '@service/api-handle.service';
import { CommonMethodsService } from '@service/common-methods.service';
import { ConstantService } from '@service/constant.service';
import { LoaderID, Routes, ToastrMessage } from '@service/string-constant';
import { DragulaService } from 'ng2-dragula';
import { Subscription, firstValueFrom, take } from 'rxjs';

@Component({
    selector: 'app-dashboard-beta',
    templateUrl: './dashboard-beta.component.html',
    styleUrls: ['./dashboard-beta.component.scss']
})
export class DashboardBetaComponent implements OnInit, OnDestroy {
    screenTitle: SCREENTITLE = {
        header: 'Dashboard Management',
        desc: ''
    };
    loaderId = LoaderID;
    Routes = Routes;
    subs = new Subscription();
    isCollapsed = false;
    flag: {
        editedViewName: string;
        editMode: boolean;
    } = {
        editedViewName: '',
        editMode: false
    };

    constructor(
        private dragulaService: DragulaService,
        private _menuAPI: MenuAPI,
        private _apiHandle: ApiHandleService,
        public _constant: ConstantService,
        private _viewAPI: ViewAPI,
        private _commonMethod: CommonMethodsService,
        private _alertBox: AlertBoxService,
        public DomSanitizationService: DomSanitizer
    ) {}

    ngOnInit(): void {
        this.dragulaService.createGroup('COLUMNS', {
            direction: 'horizontal',
            moves: (el, container, handle): any => {
                if (handle?.classList.contains('common-handle')) {
                    return false;
                }
                return true;
            }
        });

        this.subs.add(
            this.dragulaService.drop('COLUMNS').subscribe((value) => {
                console.log('dashboards are moving', value);
            })
        );
        let sourceDashboard: string; // Store the source dashboard
        let targetDashboard: string; // Store the target dashboard
        this.subs.add(
            this.dragulaService.drag('ITEMS').subscribe(({ el, source }) => {
                sourceDashboard = this.getDashboardFromElement(el.parentElement as HTMLElement);
            })
        );

        this.dragulaService.drop('ITEMS').subscribe((value) => {
            targetDashboard = this.getDashboardFromElement(value.el.parentElement as HTMLElement);
            if (sourceDashboard === targetDashboard) {
                console.log('views are moving within a dashboard');
            } else {
                console.log('views are moving across the dashboards');
            }
        });
        this.dragulaService.drag('ITEMS').subscribe(({ el }) => {
            el.classList.add('dragging');
          });
          
          this.dragulaService.dragend('ITEMS').subscribe(({ el }) => {
            el.classList.remove('dragging');
            console.log("vlvll");
          });
        this.getMenuList();
    }
    getDashboardFromElement(element: HTMLElement): string {
        const dashboardElement = element.closest('.container-1');
        if (dashboardElement) {
            const dashboardIndex = Array.from(
                dashboardElement.parentElement?.children || []
            ).indexOf(dashboardElement);
            return this._constant.menuList[dashboardIndex]?.group_menu_id || '';
        }
        return '';
    }
    async getMenuList(): Promise<void> {
        let arrayResponse: Menu[] = [];

        try {
            this._apiHandle.showStopLoader(
                LoaderID.DASHBOARD_MANAGEMENT_CENTRIC,
                LOADERSTATE.START
            );

            const res = await firstValueFrom(
                this._menuAPI.menu({
                    menus: '-1',
                    search_text: '-1'
                })
            );
            this._apiHandle.showStopLoader(LoaderID.DASHBOARD_MANAGEMENT_CENTRIC, LOADERSTATE.STOP);

            if (res?.status_code === 1) {
                arrayResponse = res.data.map((item) => {
                    const viewDetails = item.view_detail.map((view) => ({
                        ...view,
                        editView: false
                    }));
                    return { ...item, view_detail: viewDetails };
                });
                // O(n*m) // can be improved if backend can send an extra key
            } else {
                throw new Error(res?.msg || ToastrMessage.FAILED_FETCHING_DASHBOARD_LIST);
            }
            console.log(arrayResponse);
            this._constant.menuList = arrayResponse;
        } catch (err) {
            this._constant.menuList = [];
            this._apiHandle.APIErrorHandling(
                err as HttpErrorResponse,
                ToastrMessage.FAILED_FETCHING_DASHBOARD_LIST,
                LoaderID.DASHBOARD_MANAGEMENT_CENTRIC
            );
        }
    }

    ngOnDestroy(): void {
        this.dragulaService.destroy('COLUMNS');
        this.dragulaService.destroy('ITEMS');
        this.subs.unsubscribe();
    }

    clearFlags(view: VIEWLIST): void {
        this.flag.editedViewName = '';
        view.editView = false;
    }

    async editView(view: VIEWLIST, editView: boolean = false): Promise<void> {
        if (!view.view_name.trim() || (editView && !this.flag.editedViewName.trim())) {
            this._apiHandle.showNotification(ToastrMessage.VIEW_NAME_MISSING, TOASTRTYPE.WARNING);
            return;
        }

        const params = {
            view_name: this.flag.editedViewName || view.view_name.trim(),
            group_view_id: view.group_view_id,
            is_favourite: !view.is_favourite
        };

        this._apiHandle.showStopLoader(LoaderID.DASHBOARD_MANAGEMENT_CENTRIC, LOADERSTATE.START);

        try {
            const res: EDITVIEWRES = await firstValueFrom(this._viewAPI.editView(params));

            this._apiHandle.showStopLoader(LoaderID.DASHBOARD_MANAGEMENT_CENTRIC, LOADERSTATE.STOP);

            if (res.status_code === 1) {
                view.is_favourite = !view.is_favourite;

                if (!editView) {
                    view.is_favourite
                        ? this._apiHandle.showNotification(
                                ToastrMessage.VIEW_FAVOURITE_ADDED,
                                TOASTRTYPE.SUCCESS
                          )
                        : this._apiHandle.showNotification(
                                ToastrMessage.VIEW_FAVOURITE_REMOVED,
                                TOASTRTYPE.SUCCESS
                          );
                } else {
                    view.view_name = this.flag.editedViewName;
                }
            } else {
                this._apiHandle.APIErrorHandling(
                    new HttpErrorResponse({
                        error: { msg: res?.msg || ToastrMessage.VIEW_EDIT_FAIL }
                    }),
                    ToastrMessage.VIEW_EDIT_FAIL,
                    LoaderID.DASHBOARD_MANAGEMENT_CENTRIC
                );
            }

            this.clearFlags(view);
        } catch (err) {
            this.clearFlags(view);
            this._apiHandle.APIErrorHandling(
                err as HttpErrorResponse,
                ToastrMessage.VIEW_EDIT_FAIL,
                LoaderID.VIEW_CRUD
            );
        }
    }

    deleteView(view: VIEWLIST, dashboardIndex: number, viewIndex: number): void {
        this._alertBox.openAlert({
            ...ALERTBOXOBJ,
            message: AlertMessages.VIEW_DELETE(view.view_name),
            ID: AlertID['VIEW_DELETE']
        });
        this._alertBox.onClose
            .pipe(take(1))
            .subscribe(async (alertResponse: AlertBoxRespone): Promise<void> => {
                if (alertResponse.id !== AlertID['VIEW_DELETE'] || !alertResponse.response) {
                    return;
                }

                this._apiHandle.showStopLoader(
                    LoaderID.DASHBOARD_MANAGEMENT_CENTRIC,
                    LOADERSTATE.START
                );
                try {
                    const res: StatusCodeMessageAPIResponse = await firstValueFrom(
                        this._viewAPI.deleteView({ group_view_id: view.group_view_id })
                    );
                    if (res.status_code === 1) {
                        this._constant.menuList[dashboardIndex].view_detail.splice(viewIndex, 1);
                        this._apiHandle.showStopLoader(
                            LoaderID.DASHBOARD_MANAGEMENT_CENTRIC,
                            LOADERSTATE.STOP
                        );
                        this._apiHandle.showNotification(
                            res.msg || ToastrMessage.VIEW_DELETE_SUCCESS,
                            TOASTRTYPE.SUCCESS
                        );
                    } else {
                        throw new Error(res?.msg || ToastrMessage.VIEW_DELETE_FAIL);
                    }
                } catch (err) {
                    this._apiHandle.APIErrorHandling(
                        err as HttpErrorResponse,
                        ToastrMessage.VIEW_DELETE_FAIL,
                        LoaderID.DASHBOARD_MANAGEMENT_CENTRIC
                    );
                }
            });
    }

    deleteDashboard(menu: Menu): void {
        this._alertBox.openAlert({
            ...ALERTBOXOBJ,
            message: AlertMessages.MENU_DELETE(menu.is_favourite),
            ID: AlertID['MENU_DELETE']
        });
        this._alertBox.onClose
            .pipe(take(1))
            .subscribe(async (alertResponse: AlertBoxRespone): Promise<void> => {
                if (alertResponse.id !== AlertID['MENU_DELETE'] || !alertResponse.response) {
                    return;
                }
                this._apiHandle.showStopLoader(
                    LoaderID.DASHBOARD_MANAGEMENT_CENTRIC,
                    LOADERSTATE.START
                );
                try {
                    const res: CommonResp = await firstValueFrom(
                        this._menuAPI.deleteMenu(menu.group_menu_id)
                    );
                    if (res?.status_code !== 1) {
                        this._apiHandle.showNotification(
                            res?.msg || ToastrMessage.MENU_DELETE_SUCCESS,
                            TOASTRTYPE.SUCCESS
                        );
                        this._constant.menuUpdate.emit();
                        this._apiHandle.showStopLoader(
                            LoaderID.DASHBOARD_MANAGEMENT_CENTRIC,
                            LOADERSTATE.STOP
                        );
                    } else {
                        throw new Error(res?.msg || ToastrMessage.MENU_DELETE_FAIL);
                    }
                } catch (err) {
                    this._apiHandle.APIErrorHandling(
                        err as HttpErrorResponse,
                        ToastrMessage.MENU_DELETE_FAIL,
                        LoaderID.DASHBOARD_MANAGEMENT_CENTRIC
                    );
                }
            });
    }

    async toggleDashboardFav(menu: Menu, menuIndex: number): Promise<void> {
        if (menu.is_favourite) {
            return;
        }
        this._apiHandle.showStopLoader(LoaderID.DASHBOARD_MANAGEMENT_CENTRIC, LOADERSTATE.START);
        try {
            const res: CommonResp = await firstValueFrom(
                this._menuAPI.editMenu({ ...menu, is_favourite: true })
            );
            if (res?.status_code === 1) {
                this._apiHandle.showNotification(
                    res?.msg || ToastrMessage.SET_MENU_LANDING_SUCCESS,
                    TOASTRTYPE.SUCCESS
                );
                menu.is_favourite = true;
                this._constant.menuList.forEach((field, index) => {
                    if (index !== menuIndex) {
                        this._constant.menuList[index].is_favourite = false;
                    }
                });
                this._apiHandle.showStopLoader(
                    LoaderID.DASHBOARD_MANAGEMENT_CENTRIC,
                    LOADERSTATE.STOP
                );
            } else {
                throw new Error(res?.msg || ToastrMessage.SET_MENU_LANDING_FAIL);
            }
        } catch (err) {
            this._apiHandle.APIErrorHandling(
                err as HttpErrorResponse,
                ToastrMessage.SET_MENU_LANDING_FAIL,
                LoaderID.DASHBOARD_MANAGEMENT_CENTRIC
            );
        }
    }
    scrollTo():void{
        console.log("scroll");
    }
    
}
.wrapper {
    width: 100%;
    overflow: auto;
    max-height: 68vh;
    display: flex;
    font-size: 1.1rem;
    background: #fff;
    padding: 10px;
    position: relative;
}
.scroll-custom {
    cursor: all-scroll;
}
.container {
    // flex-grow: 1;
    max-height: 77vh;

    &.container-1 {
        border-radius: 10px;
        box-shadow: rgba(0, 0, 0, 0.35) 0px 3px 10px;
        min-width: 280px;
        overflow-y: hidden;
        margin: 10px;


        .group-handle {
            display: block;
            padding: 0.4em 0 0.4em 0;
            white-space: nowrap;
            text-overflow: ellipsis;
            overflow: hidden;
        }

        .custom-padding-right {
            padding-right: 1.2rem !important;
            margin-top: 1rem;
        }
        .pt-custom {
            padding-top: 1.3rem;
        }
        .max-custom-width {
            width: max-content;
        }
    }
    & div {
        padding: 0.5em;
        transition: opacity 0.4s ease-in-out;
        max-height: 80%;
        overflow-x: hidden;
    }
    &.container-2 {
        padding-top: 0.1em !important;
        overflow-y: auto;
    }
    &.container-3 {
        border-radius: 10px;
        box-shadow: rgba(0, 0, 0, 0.02) 0px 1px 3px 0px, rgba(27, 31, 35, 0.15) 0px 0px 0px 1px;
        background: var(--pxvz-bg-light);
        margin-bottom: 1.5rem;
        overflow-y: auto;
    }
    .flex-column-custom {
        display: flex;
        flex-direction: column;
        gap: 0.8rem;
    }
    .flex-row-custom {
        display: flex;
        flex-direction: row;
        align-items: center;
        // justify-content: space-between;
        gap: 0.7rem;

        .basis {
            flex-basis: 85%;
        }
        i {
            font-size: 1.05rem;
        }
    }

    // .flex-column-custom i {
    //     visibility: hidden;
    //     opacity: 0;
    //     transition: visibility 0s, opacity 0.2s;
    // }

    // .container:hover .flex-column-custom i {
    //     visibility: visible;
    //     opacity: 1;
    // }

    // .flex-column-custom i {
    //  visibility: hidden;
    //  opacity: 0;
    //  transition: visibility 0s, opacity 0.2s;
    // }

    // .flex-column-custom:hover i {
    //  visibility: visible;
    //  opacity: 1;
    // }
    .height-80 {
        height: 80%;
    }
    .fa-circle-xmark {
        position: absolute;
        top: 2px !important;
        right: 1px;
    }
}

.custom-one{
    overflow-y: auto !important;
    max-height: 80vh !important;
}
<div class="create-manage-form">
    <div class="header pb-0">
        {{ screenTitle.header }}
    </div>
    <div
        class="wrapper mb-0 pb-0 mt-3"
        dragula="COLUMNS"
        [(dragulaModel)]="_constant.menuList">
        <div
            class="container container-1 scroll-custom"
            
            *ngFor="let group of _constant.menuList; index as dashboardIndex">
            <div class="flex-row-custom justify-content-between ps-0 pb-2">
                <div class="d-flex flex-column basis pe-2 pt-custom">
                    <i
                        [ngClass]="{
                            'fa-toggle-on': group.is_favourite,
                            'fa-toggle-off': !group.is_favourite
                        }"
                        class="fa-icon fa-solid max-custom-width"
                        (click)="toggleDashboardFav(group, dashboardIndex)"></i>
                    <span class="group-handle">{{ group.menu_name }}</span>
                    <span class="text-ellipsis">Owner:- Bharat Bhashan</span>
                </div>
                <div class="flex-column-custom custom-padding-right pt-0">
                    <i
                        class="fa-solid fa-pen-to-square fa-icon"
                        [routerLink]="[Routes.MENU_MANAGEMENT + '/action/edit']"
                        [queryParams]="{ id: group.group_menu_id }"></i>
                    <i
                        class="fa-solid fa-trash fa-icon"
                        (click)="deleteDashboard(group)"></i>
                    <i
                        class="fa-solid fa-share-nodes fa-icon"
                        [routerLink]="[Routes.MENU_MANAGEMENT + '/action/share']"
                        [queryParams]="{ id: group.group_menu_id, name: group.menu_name }"></i>
                </div>
            </div>
            <div
                class="container container-2"
                dragula="ITEMS"
                
                [(dragulaModel)]="group.view_detail" (mousedown)
                ="scrollTo()">
                <ng-container *ngIf="group.view_detail.length === 0">
                    <div class="p-4 text-center paxviz-disabled">No Views Found!</div>
                </ng-container>
                <div
                    class="container container-3 scroll-custom common-handle"
                    
                    [ngClass]="{ 'height-80': !group.view_detail.length }"
                    *ngFor="let item of group.view_detail; index as viewIndex">
                    <div class="flex-row-custom justify-content-between p-0 common-handle custom-one" >
                        <div class="d-flex flex-column basis ps-0 common-handle" >
                            <div class="flex-row-custom gap-1 ps-0 common-handle">
                                <ng-container *ngIf="!item.editView; else EDITVIEW">
                                    <i
                                        class="fa-solid fa-star fa-icon"
                                        *ngIf="item.is_favourite"></i>
                                    <i
                                        class="fa-regular fa-star fa-icon"
                                        *ngIf="!item.is_favourite"></i>
                                    <span class="text-ellipsis common-handle">{{ item.view_name }}</span>
                                </ng-container>
                            </div>

                            <span class="text-ellipsis common-handle">Owner:- Vishal</span>
                        </div>

                        <div class="container-4 flex-column-custom pe-0">
                            <i
                                *ngIf="!item.editView"
                                class="fa-solid fa-pen-to-square fa-icon"
                                (click)="item.editView = !item.editView"></i>
                            <i
                                *ngIf="item.editView"
                                class="fa-icon fa-solid fa-check"
                                (click)="editView(item, true)">
                            </i>
                            <i
                                class="fa-solid fa-trash fa-icon"
                                (click)="deleteView(item, dashboardIndex, viewIndex)"></i>
                            <i
                                class="fa-solid fa-star fa-icon"
                                *ngIf="item.is_favourite"
                                (click)="editView(item)"></i>
                            <i
                                class="fa-regular fa-star fa-icon"
                                *ngIf="!item.is_favourite"
                                (click)="editView(item)"></i>
                        </div>
                    </div>
                    <ng-template #EDITVIEW>
                        <div
                            class="view-name-input input-with-icon w-100 ps-0"
                            *ngIf="item.editView">
                            <input
                                autofocus
                                autocomplete="off"
                                [id]="item.group_view_id + 'edit-name'"
                                class="paxviz-input bg-white ps-2 pe-4 w-100"
                                [placeholder]="item.view_name || 'Name...'"
                                [(ngModel)]="flag.editedViewName"
                                (keyup.enter)="editView(item, true)" />
                            <i
                                class="fa-icon-red fa-regular fa-circle-xmark"
                                (click)="clearFlags(item)"></i>
                        </div>
                    </ng-template>
                </div>
            </div>
        </div>
        <ngx-ui-loader [loaderId]="loaderId.DASHBOARD_MANAGEMENT_CENTRIC"></ngx-ui-loader>
    </div>
</div>

When the scroller comes and i try to drag the element from the top and try to drop it at the end, im unable to do so because im unable to scroll till down while dragging. Kindly help as soon as possible.

i am trying to scroll up and down while dragging but unable to do so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant