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

Question: How to use it with ng-bootstrap's tabset? #10

Closed
tommykamkcm opened this issue Jun 19, 2017 · 17 comments
Closed

Question: How to use it with ng-bootstrap's tabset? #10

tommykamkcm opened this issue Jun 19, 2017 · 17 comments

Comments

@tommykamkcm
Copy link

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!

@bfwg
Copy link
Owner

bfwg commented Jun 19, 2017

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

@tommykamkcm
Copy link
Author

tommykamkcm commented Jun 20, 2017

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!

@tommykamkcm
Copy link
Author

tommykamkcm commented Jun 20, 2017

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!

@bfwg bfwg closed this as completed in e9a158f Jun 21, 2017
@bfwg
Copy link
Owner

bfwg commented Jun 21, 2017

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

@tommykamkcm
Copy link
Author

tommykamkcm commented Jun 21, 2017

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!

@bfwg
Copy link
Owner

bfwg commented Jun 21, 2017

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

@bfwg bfwg reopened this Jun 21, 2017
@bfwg
Copy link
Owner

bfwg commented Jun 22, 2017

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.

@tommykamkcm
Copy link
Author

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.

@bfwg
Copy link
Owner

bfwg commented Jun 22, 2017

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 😄 .

@bfwg
Copy link
Owner

bfwg commented Jun 23, 2017

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?

@tommykamkcm
Copy link
Author

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

@bfwg
Copy link
Owner

bfwg commented Jun 29, 2017

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.

@bfwg
Copy link
Owner

bfwg commented Jul 1, 2017

@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.

@tommykamkcm
Copy link
Author

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!

@bfwg
Copy link
Owner

bfwg commented Jul 17, 2017

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. 😞

@tommykamkcm
Copy link
Author

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

@bfwg bfwg closed this as completed in #22 Jul 28, 2017
@ajaybabum
Copy link

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

Thanks

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

4 participants
@tommykamkcm @bfwg @ajaybabum and others