Skip to content
This repository has been archived by the owner on Aug 7, 2021. It is now read-only.

List Items generated programmatically #75

Open
lanceschi opened this issue Dec 7, 2017 · 10 comments
Open

List Items generated programmatically #75

lanceschi opened this issue Dec 7, 2017 · 10 comments

Comments

@lanceschi
Copy link

Hi @makotot ,

first of all thanks for the beautiful component! I took a look at the issues unsuccessfully. I'd like to make react-scrollspy work together with programmatically generated list items. Could you plese provide me some info about the feasability. Thanks in advance. Here you'll find a reference code sample to give you a rough idea of what I'm talking:

const Parent = ({options}) => (
  <Scrollspy
    items={ ['news', 'mission', 'whatwedo', 'competences'] }
    currentClassName="active">
      {options.map((x, idx) => <Child item={x} key={idx}/>)}
  </Scrollspy>
);

const Child = ({item}) => (
  <li>
    <a href={item.anchor}>{item.label}</a>
  </li>
);
@lanceschi
Copy link
Author

What I came up with as a work-around is to intercept Scrollspy onUpdate method. I hook into the onUpdate method in order to update a newly created active attribute in the hash array of Scrollspy <ul> option list items.

I'll welcome a better approach.

Best,
Luca

@makotot
Copy link
Owner

makotot commented Dec 7, 2017

@lanceschi Sorry, I have no time at this weekday, so I'll check the issue at this weekend.

@makotot
Copy link
Owner

makotot commented Dec 10, 2017

I think using onUpdate is only way to accomplish your needs. Unfortunately, this lib is not thought about generated list items at least now.

  • With generated list items, currentClassName does not pass to target list element.

2017-12-10 21 58 47

  • With static list items, currentClassName definitely passes to target.

2017-12-10 21 59 36

@lanceschi
Copy link
Author

@makotot thanks! Got it. I guess you can close this issue now.

If you're planning on extending this lib in order to support programmatically generated option items, then let me know. I'd like to help and contribute.

Kind regards,
Luca

@gtwilliams03
Copy link

@lanceschi I am also trying to use this library with generated list items. Would you mind sharing how you implemented the work-around you mentioned above? I am trying to console.log the output of any variables in the onUpdate event, but I don't see anything...

@lanceschi
Copy link
Author

Hi @gtwilliams03 onUpdate is to deliver a parameter (object). Here you'll find some code in order to give you an idea of how I implemented the workaround:

Partial JSX markup within the component render function

<Scrollspy
  items={this.optionIdList}
  offset={-160}
  onUpdate={this.setActiveOption}
  currentClassName="active">
    {this
      .state
      .options
      .map((x, idx) => <MenuOption item={x} key={idx}/>)}  
</Scrollspy>

OnUpdate event handler function

I read and map the list of the menu options (array of objects) from this.props.options and eventually set the active flag and set as a state of the component. this.state.options is used to programmatically render the menu options as you can see in the above jsx snippet.

setActiveOption(e) {
  if (!e) return;
  const optHash = this
    .props
    .options
    .map(x => (x.anchor === `#${e.id}`)
      ? {
        ...x,
        active: true
      }
      : x);
  this.setState({opts: optHash});
}

I hope it'll help you!

Best,
Luca

@gtwilliams03
Copy link

gtwilliams03 commented Feb 5, 2018

@lanceschi Thank you for the note! I get undefined in the onUpdate handler when I write out e to the console (only when the component mounts, and handleScrollSpyChange is not called if the page is scrolled (I am sure I am making a basic mistake...):

    handleScrollSpyChange(e) {
        console.log(e)
    }

    render() {
        const { items } = this.props
        return (
            <div>                        
                <Scrollspy items={items.map(i => i.abbreviation)} offset={-100}
                    currentClassName='active' onUpdate={this.handleScrollSpyChange}>
                    {items.map(i => <li key={`${i.abbreviation}`}><a href={`#section-${i.abbreviation}`}>{i.abbreviation}</a></li>)}
                </Scrollspy>
            </div>
        )
    }

@lanceschi
Copy link
Author

@makotot can you:

  • further explicit what's inside items attribute of Scrollspy;
  • define your component constructor function? Do you bind that handleScrollSpyChange function?

Best,
L

@karltaylor
Copy link

karltaylor commented Feb 26, 2018

Was so stumped that my generated markup wasn't working. This would be good to put in the docs on how to use with programmatically created list objects.

I realised that it if you map through an array and return the JSX - not using a functional Component it works. I'm intrigued as to why this happens? 🤷‍♂️🤓

const items = ['section-1', 'section-2', 'section-3']

const links = items.map(link => {
  return <li><a href={link}>{link}</a></li>
})

...

<Scrollspy
  items={ ['section-1', 'section-2', 'section-3'] }
  currentClassName="is-current"
  className="c-side-nav__list nav-list"
  style={ {fontWeight: 300} }
  offset={ -20 }
  onUpdate={
    (el) => {
      console.log(el)
    }
  }
>
  {links}
</Scrollspy>

@thebarty
Copy link

thebarty commented Mar 7, 2019

Related to #96

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

No branches or pull requests

5 participants