Ngx-drag-scroll: Question: How to use it with ng-bootstrap's tabset?

Created on 19 Jun 2017  ·  17Comments  ·  Source: bfwg/ngx-drag-scroll

Hello, just found this plugin from google.

I found it really useful for the site navigation menu which is very long. However, the menu is built with ngb-tabset (one of the ng-bootstrap's components) and I am not sure how to inject your plugin into the tabset component.

It would be really good if can give me some advice! Thanks a lot!

All 17 comments

Hi @tommykamkcm, I'd love to do what ever I can for help, can you provide some of your code?

Thanks for your prompt response! First of all, I only have some experience on Angular1 and I am a newbie to Angular2. So I am not sure what I'm trying to do is possible or not:

So below is the HTML code for generating the ng-bootstrap's Tabset component: https://ng-bootstrap.github.io/#/components/tabs

<ngb-tabset>
    <ngb-tab *ngFor="let group of groups" [id]="group.id">
        <template ngbTabTitle>{{group.name}}</template>
        <template ngbTabContent>
            ...
        </template>
    </ngb-tab>
</ngb-tabset>

and eventually it becomes

<ngb-tabset _ngcontent-43="">
   <div class="longTabMenu">
    <ul role="tablist" ng-reflect-class-name="nav nav-tabs justify-content-start" class="nav nav-tabs justify-content-start">
        <li class="nav-item">
            <a href="" role="tab" ng-reflect-ng-style="[object Object]" ng-reflect-id="Themes" id="Themes" ng-reflect-class-name="nav-link nav-link-Themes" class="nav-link nav-link-Themes active" aria-controls="Themes-panel" aria-expanded="true" style="border-color: blanchedalmond;">
                Tab 1
            </a>
        </li>
        ...
        </ul>
    </div> 
    <div class="tab-content">
      ...
    </div>
  </ngb-tabset>

So what I've tried to do is adding drag-scroll to the <div class="longTabMenu"> in the ng-bootstrap.js
image

And as expected, it does not work probably because the <div class="longTabMenu" drag-scroll ...> does not get rendered.

Since the first try does not seem to work, I am now thinking if we can inject the DragScroll component into ngOnInit / ngAfterViewInit of the host component so that I can manually initialize the DragScroll on <div ... >
e.g.

@Component({
    selector: 'wd-shows',
    templateUrl: 'app/shows/shows.component.html',
    styleUrls: ['app/shows/shows.component.css'],
    providers: [ShowService, JobService],
})

export class ShowsComponent implements OnInit, AfterViewInit {
...
ngAfterViewInit(): void {
        console.log('AfterViewInit');
        console.log(this.elTablistHolder);
        this.elTablistHolder = this.element.nativeElement.querySelector('.longTabMenu');
        this.renderer.setElementAttribute(this.elTablistHolder, 'drag-scroll', null);
        this.renderer.setElementAttribute(this.elTablistHolder, 'drag-scroll-y-disabled', 'true');
        this.renderer.setElementAttribute(this.elTablistHolder, 'scrollbar-hidden', 'true');
        **// Not sure what's next, still googling**
    }
...
}

That's all the info so far I've got. Thank you very much for your time!

Hello @bfwg, Finally got it working! Basically, I need to manually

  • define the attrs available in API
  • call ngOnChanges()
  • bind all the mouse events using renderer.listen() & renderer.listenGlobal()
export class BlahComponent implements OnInit {
...
dragScrollDom: any;
dragScrollRef: ElementRef;
dragScroll: DragScroll;

constructor(...) {}
ngOnInit(): void {
...
        // At the end of the ngOnInit()
        this.dragScrollDom = this.element.nativeElement.querySelector('.longTabMenu');
        this.dragScrollRef = new ElementRef(this.dragScrollDom );
        this.dragScroll = new DragScroll(this.dragScrollRef, this.renderer);
        this.dragScroll.disabled = false;
        this.dragScroll.scrollbarHidden = true;
        this.dragScroll.yDisabled = true;
        this.dragScroll.xDisabled = false;
        this.dragScroll.ngOnChanges();
        this.renderer.listen(this.dragScrollDo , 'mousedown', (event) => {
            this.dragScroll.onMouseDown(event);
        });
        this.renderer.listenGlobal('document', 'mousemove', (event) => {
            this.dragScroll.onMouseMove(event);
        });
        this.renderer.listenGlobal('document', 'mouseup', (event) => {
            this.dragScroll.onMouseUp(event);
        });
}
...
}

I also have a little suggestion (though I'm not sure if it is a good idea or not): use Angular2's renderer.listen() & renderer.listenGlobal() instead of document.addEventListener() & document.removeEventListener()
By making this change, the source code will probably be written in pure Angular2, not mixed with vanilla JS

Finally, appreciate your effort and hopefully my findings / suggestion are useful!

@tommykamkcm Thanks for reporting this, I have updated the library to use renderer.listenGlobal(). Let me know if you notice anything else.

hello @bfwg, sorry for being annoying but I just found that what I've done yesterday is actually affecting other components e.g. .

What I suggest to do is: bind mouseup mousemove on el.nativeElement instead of document in the constructor

this.mouseMoveListener = renderer.listen(el.nativeElement, 'mousemove', this.onMouseMoveHandler);
this.mouseUpListener = renderer.listen(el.nativeElement, 'mouseup', this.onMouseUpHandler);

After doing this, only 2 steps are required for the initialisation:

  • define the attrs available in API
  • call ngOnChanges()
  • ~bind all the mouse events using renderer.listen() & renderer.listenGlobal()~

constructor(...) {}
ngOnInit(): void {
...
// At the end of the ngOnInit()
this.dragScrollDom = this.element.nativeElement.querySelector('.longTabMenu');
this.dragScrollRef = new ElementRef(this.dragScrollDom );
this.dragScroll = new DragScroll(this.dragScrollRef, this.renderer);
this.dragScroll.disabled = false;
this.dragScroll.scrollbarHidden = true;
this.dragScroll.yDisabled = true;
this.dragScroll.xDisabled = false;
this.dragScroll.ngOnChanges();
this.renderer.listen(this.dragScrollDo , 'mousedown', (event) => {
this.dragScroll.onMouseDown(event);
});
~this.renderer.listenGlobal('document', 'mousemove', (event) => {
this.dragScroll.onMouseMove(event);
});
this.renderer.listenGlobal('document', 'mouseup', (event) => {
this.dragScroll.onMouseUp(event);
});~
}

Finally, it would be really good if you could compile the source code and make it available for npm install. Thank you very much!

Ah, I see what you mean. I will update the source some time today and upload to npm, thanks again for reporting this.

Hey @tommykamkcm , I just realized mouseup and mousemove has to be on document, otherwise the content will stop moving if you press down the mouse and drag to outside of the component.
Any ideas? If you like you can put up a pull request and I can merge it.

hello @bfwg, maybe let's take a step back and think about different use cases.

My use case is to make a long horizontal menu drag-scrollable by mouse or finger. Everything was going well until I dragged on an HTML5 slider, which is mousemove sensitive. I could click and drag, but not release the handle after it reached the correct position.

So to me what I expect are a) user. always drag inside the drag zone i.e. the menu b) other components on the page should not be affected by the plugin.

and your use case probably is as long as users hold and move the mouse, they should be able to drag and see a certain part of the content easily (drag zone = document)

I'm sure that there will be more and more use cases and I reckon making drag zone configurable [self|default:document] will probably be the way to go.

Hi @tommykamkcm , I think we can definitely fix this. I'm going to test with ng-bootstrap's tabset and see if I can reproduce.
Thanks again for being patient with me 😄 .

Hi @tommykamkcm, I have put the below code in the demo app html template.

    <ngb-tabset>
      <ngb-tab title="Simple">
        <ng-template ngbTabContent>
          <p>Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth
          master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh
          dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum
          iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.</p>
        </ng-template>
      </ngb-tab>
      <ngb-tab>
        <ng-template ngbTabTitle><b>Fancy</b> title</ng-template>
        <ng-template ngbTabContent>Food truck fixie locavore, accusamus mcsweeney's marfa nulla single-origin coffee squid.
          <div class="demo-one" drag-scroll drag-scroll-y-disabled="true" scrollbar-hidden="true" >
            <img *ngFor="let image of imagelist" [src]="'assets/img/' + image" />
          </div>
        </ng-template>
      </ngb-tab>
    </ngb-tabset>

The drag list worked as expected. Can you provide more detail about your html code please?

hello @bfwg sorry for the long silence.

What I'm trying to do is actually apply the plugin to the <ngb-tab>, which will later be replaced by a <ul role="tablist" ... >
image

No worries @tommykamkcm , I see, you are trying to append the directive after the component is rendered. Let me try that tomorrow and I'll get back to you as soon as I can.

@tommykamkcm Sorry for the delay response. I have played with ng-tab a bit and I can't make it work without using some hack, like in your previous implementation.

No worries @bfwg, everyone should relax as long as there is a hack and it works.

It would be also good if we could have a method that does the hack, in other words, dynamically apply the plugin to a DOM element!

Anyway, thanks again for your support! Really appreciate it!

Hey @tommykamkcm , I'm working the attach() method in the plugin that does what you want:

"dynamically apply the plugin to a DOM element"

It is almost done, would you like to review the Pull request once it is ready?
Sorry for the huge delay. 😞

Hello @bfwg no worries, I really appreciate your help! Just read your code and everything looks good! Thanks again!

Hi @tommykamkcm / @bfwg Can you please drop the Demo for ngb-tabs with scroll

Thanks

Was this page helpful?
0 / 5 - 0 ratings

Related issues

leogilardi6 picture leogilardi6  ·  8Comments

BovineEnthusiast picture BovineEnthusiast  ·  5Comments

Andi1990 picture Andi1990  ·  7Comments

CrackerakiUA picture CrackerakiUA  ·  25Comments

bfwg picture bfwg  ·  13Comments