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

Feature: Using a service from inside a component to scroll #10

Closed
HarelM opened this issue Jul 22, 2017 · 12 comments
Closed

Feature: Using a service from inside a component to scroll #10

HarelM opened this issue Jul 22, 2017 · 12 comments
Assignees

Comments

@HarelM
Copy link

HarelM commented Jul 22, 2017

I couldn't find it in the documentations - I would like to achieve the following:
I have a component that is a pop-up, and I want to scroll to the same location the user left it when it was closed.
So I need two functionalities

  1. The ability to smooth scroll to a position.
  2. The ability to receive scroll events to update a local variable that stores the current scroll position.
    Currently I'm using JQuery. I would like to remove this dependency if possible and I thought this library might do the trick.
    I also looked at smoothscroll-polyfill but I'm not sure it will do what I need.
    Thoughts are appreciated.
@HarelM
Copy link
Author

HarelM commented Jul 22, 2017

Basically this is the code I want to replace:

        let dialogElement = $(".dialog-content-for-scroll");
        dialogElement.delay(700)
            .animate({
                scrollTop: this.state.scrollPosition
            },
            "slow");
        dialogElement.on("scroll", () => {
            this.state.scrollPosition = dialogElement.scrollTop();
            this.sharedStorageService.set(OsmUserDialogComponent.OSM_USER_DIALOG_STATE_KEY, this.state);
        });

@nicky-lenaers
Copy link
Owner

Good point, scroll events are definitely a missing feature as of this moment. I'll create a seperate issue for implementation of scroll events. To stay in line with the way Angular Animation Callbacks work, I was thinking of the following set of events:

1. Start
Fired when the animation starts.
(ngx-scroll-to-on-start)="onScrollToStart($event, data)"

2. End
Fired when the animation is fully finished.
(ngx-scroll-to-on-end)="onScrollToEnd($event, data)"

3. Cancel
Fired when the animation is interrupted.
(ngx-scroll-to-on-cancel)="onScrollToCancel($event, data)"

Please note that the 3rd option has to do with this feature.

The $event will be the native event emitted by the browser. For data, I'm thinking something like:

interface ScrollToEventData {
  position: {
    fixed: number;
    dynamic: number;
  }
}

The difference in fixed and dynamic positioning is demonstrated in this example (make sure you open developer tools and check the console).

Please let know what you think and if this is applicable to your situation!

Thanks

@HarelM
Copy link
Author

HarelM commented Jul 22, 2017

I'm not sure I understand how this solves my issue - are these events generated from html that has a scroll-to directive on it?
I need the ability to scroll a position from within the component code written in typescript.
I must be missing something, can you provide a usage example?
See the code above - this is the code I need to replace with something like:

ctor(private scrollToService: ScrollToService) {
    this.scrollToService.scrollToPosition(element, offset);
}

@nicky-lenaers
Copy link
Owner

Ah I see. I had my solution mostly based on this line you wrote:

The ability to receive scroll events

Sorry for misunderstanding your question. I think you're solution to trigger scrolling from within a component is also a missing feature. I'll give this a go soon and give you a heads up when implemented.

@HarelM
Copy link
Author

HarelM commented Jul 22, 2017

I see, the main intensive here is that I removed all references of JQuery from my code and it seems angular doesn't have a good solution for smooth scrolling so I was looking for a solution as since it seems you are actively maintaining this library I thought it could be a good fit for a feature suggestion.
Let me know if and when you get to it, until then this particular scroll will be without animation in my app which is acceptable.

@nicky-lenaers
Copy link
Owner

Cool, I'll keep you posted! We want those animations, right! 😄

nicky-lenaers pushed a commit that referenced this issue Jul 27, 2017
- Needed for #10 to be able to trigger scrolls from insde a service
(a.k.a. skipping Directive)
@nicky-lenaers nicky-lenaers changed the title Using a service from inside a component to scroll Feature: Using a service from inside a component to scroll Jul 28, 2017
@nicky-lenaers nicky-lenaers self-assigned this Aug 3, 2017
@nicky-lenaers
Copy link
Owner

@HarelM This feature has been added to a new release. Please check the related section in the README.md for using an Angular Service for usage examples. Please let me know if your issue has been resolved or if you encounter any problems.

Thanks!

@HarelM
Copy link
Author

HarelM commented Aug 8, 2017

Thanks for the fast implementation!
I have a few questions:

  1. What happens if I don't have an event instance to pass to the scroll to function?
  2. Can I use the config object to specify an offset instead of target?
  3. How do I define which element to scroll (the "parent" not the target?

@nicky-lenaers
Copy link
Owner

@HarelM Good questions. Allow me to explain:

  1. What happens if I don't have an event instance to pass to the scroll to function?

That won't work. The event is coming from the HTML Element that fires the event. This HTML Element is needed to calculate the first scrollable parent. Without it, the plugin won't be able to find a scroll container (for now!). There is already an issue open to specify a custom scroll container, see the issue here, so this will be available in the near future. Because this is a somewhat different issue, I've created a seperate bug for this, see bug here.

  1. Can I use the config object to specify an offset instead of target?

I'm not sure I understand correctly, but I think a target is always required because that's where it's supposed to scroll to, right? You can, however, define the offset in the config object. You can see options in the source (they will be added to the README soon), but here's an example as well:

const config: ScrollToConfig = {
  target: 'destination',
  offset: 100
}
  1. How do I define which element to scroll (the "parent" not the target?

This is already answered in question 1. A custom scroll-container will be added in the near future, so hold on tight!

Thanks again for your issue submittance!

@HarelM
Copy link
Author

HarelM commented Aug 8, 2017

Thanks for your prompt response!
If you need to better understand what I want to accomplish you can use the snippet I provided above, here it is again, with some comment to help understand what I want to achieve:

// this is called when a dialog is opened using the ngAfterViewInit- there's no clear event here to use.
let dialogElement = $(".dialog-content-for-scroll"); // this is the element I want to scroll, I can provide ElementRef if the ScrollTo API would accept it.
        dialogElement.delay(700)
            .animate({
                scrollTop: this.state.scrollPosition // I don't want to scroll to another element but rather to a position offset in "dialogElement"
            },
            "slow");
        dialogElement.on("scroll", () => {
            this.state.scrollPosition = dialogElement.scrollTop(); // this is used to get the current position when this dialog scrolls so that next time I open it, it will open in the same scroll position.
            this.sharedStorageService.set(OsmUserDialogComponent.OSM_USER_DIALOG_STATE_KEY, this.state);
        });

So as far as I can tell, this implementation still doesn't cover my needs, so I'll wait for the other issues to be resolved and I'll try again.
Thanks a lot for being so responsive!

Here's my current implementation without JQuery:

class SomeComponenet {
...
@ViewChild("dialogContentForScroll") dialogContent: ElementRef;
...
public ngOnInit() {
...
        let dialogElement = this.dialogContent.nativeElement as HTMLElement;
        // the following is the code I want to replace with a service:
        setTimeout(() => dialogElement.scrollTop = this.state.scrollPosition, 700);
        // end, below code is fine as is.
        dialogElement.onscroll = () => {
            this.state.scrollPosition = dialogElement.scrollTop;
            this.sharedStorageService.set(OsmUserDialogComponent.OSM_USER_DIALOG_STATE_KEY, this.state);
        }
...

@nicky-lenaers
Copy link
Owner

I see, great thing you've provided the snippets. Do you mind putting these into a separate issue?
Because the current feature of service implementation is released (which closes this issue). That will really help me organize the issues better, so I can handle them separately. You can simply copy paste the above comment into the example section of a new issue.

Thanks a bunch, looking forward for the implementation!

@HarelM
Copy link
Author

HarelM commented Aug 9, 2017

See issue #28.
As a side note, this was the initial intention of this issue, but I don't mind opening another one that is almost the same...

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

2 participants