1

I have 2 components - 1 is container and 2 is navbar. Navbar is nested in container.

On my container component I have an array of completed sections.

My array looks like this:

["navitem1","navitem2","navitem3"]

On my "child" component, the navbar I have the following...

I have a lightning-vertical-navigation component with a lot of lightning-vertical-navigation-item-icon elements nested inside it.

The nav item has an attribute called icon-name, and I want to update the icons based on an array of completed items in my parent component.

And my nav items look like this:

<lightning-vertical-navigation-item-icon name="navitem1" icon-name="utility:routing_offline"></lightning-vertical-navigation-item-icon>
<lightning-vertical-navigation-item-icon name="navitem2" icon-name="utility:routing_offline"></lightning-vertical-navigation-item-icon>
<lightning-vertical-navigation-item-icon name="navitem3" icon-name="utility:routing_offline"></lightning-vertical-navigation-item-icon>

I want to update the icon-name attribute on the navigation items when the array is updated on the parent, something like:

for each item in array: (if name == arrayitem){ change icon to routing online. }

What is the best way to do this? Pass an array from the parent to the child nav with @api and iterate over?

1 Answer 1

2

There's lots of options. I'll share a few.


Set up an iteration, and have each item rendered from a public property:

<lightning-vertical-navigation-item-icon 
  for:each={navItems}
  for:item="nav"
  key={nav.name}
  name={nav.name}
  icon-name={nav.icon}>
</lightning-vertical-navigation-item-icon>

Now, in your child:

@api navItems;

And from the parent:

@track navItems = [
  { name: 'navitem1', icon: 'utility:routing_offline' },
  { name: 'navitem2', icon: 'utility:routing_offline' },
  { name: 'navitem3', icon: 'utility:routing_offline' },
];

When you want to set a new value:

this.navItems.find((item) => item.name === itemName).icon = 'utility:check';

Use a setter:

@api set completedItems(value) {
  const items = [...this.template.querySelectorAll('lightning-vertical-navigation-item-icon')];
  items.forEach((item) => {
    if(value.indexOf(item.name) > -1) {
      item.iconName = 'utility:check';
    } else {
      item.iconName = 'utility:routing_offline';
    }
  ]);
}
get completedItems() {
  return [...this.template.querySelectorAll('lightning-vertical-navigation-item-icon')]
    .filter((item) => item.iconName === 'utility:check')
    .map((item) => item.name);
}

You could make a public method:

@api completeItem(itemName) {
  this.template.querySelector(`[name="${itemName}"]`).iconName = 'utility:check';
}

Which you call from the parent:

this.template.querySelector('c-navbar').completeItem(itemName);

Each of these are slightly different in structure, but all essentially perform the same action. There's no "one right way" to do this, just pick an option and commit.

If you asked me directly, I'd probably suggest the first one, as it allows the parent to specify what icons exist in the first place, so you don't need to remember to update this list in multiple places.

1
  • Thank you once again @sfdcfox
    – Josiah
    Aug 22, 2022 at 21:49

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .