Help with using ember-bootstrap and breaking up template code into multiple components

#1

Hi all,

I’ve decided to start using ember-bootstrap and have begun migrating code to take advantage of its features. I’m currently to replace my navigation with the navbar component (https://www.ember-bootstrap.com/#/components/navbars).

As a simple example of what I’m trying to do, my current nav is split up into two components (there are actually more). One nav is loaded when the user is NOT authenticated, and the other is loaded when the user is authenticated. The reason for this is to keep the nav template small.

Trying to implement this same structure with the ember-bootstrap navbars component doesn’t seem to work.

In my parent template, I have

{{#bs-navbar type=type backgroundColor=bg collapsed=collapsed onCollapse=(action (mut collapsed) true) onExpand=(action (mut collapsed) false) as |navbar|}}

  {{#if session.authenticated }}
    {{nav/auth-nav}}
  {{else}}
    {{nav/unauth-nav}}
  {{/if}}
  
{{/bs-navbar}}

In each of the components, I have code like this:

{{#navbar.content}}
  {{#navbar.nav as |nav|}}
    {{#nav.item}}{{#nav.link-to "index"}}Home{{/nav.link-to}}{{/nav.item}}
    {{#nav.item}}{{#nav.link-to "demo.navbars"}}Navbars{{/nav.link-to}}{{/nav.item}}
  {{/navbar.nav}}
{{/navbar.content}}

It’s very simple (or so I thought). Neither of the components load properly. Looking at it through Ember Inspector, the component is registered in the list views, but the HTML is blank.

If I copy the template code directly into the parent, then it loads fine. I was wondering if what I’m trying to do is possible or am I just going to suck it up and manage a big nav template?

Thanks in advance!

0 Likes

#2

The problem is in your sub-components. You’re rendering this:

{{#navbar.content}}
  {{#navbar.nav as |nav|}}
    {{#nav.item}}{{#nav.link-to "index"}}Home{{/nav.link-to}}{{/nav.item}}
    {{#nav.item}}{{#nav.link-to "demo.navbars"}}Navbars{{/nav.link-to}}{{/nav.item}}
  {{/navbar.nav}}
{{/navbar.content}}

But “navbar” is being yielded from the parent bs-navbar, so inside the context of nav/auth-nav or nav/unauth-nav it doesn’t exist. Technically you should still be able to get this to work though… you’ll just need to invoke the content component with the full component name, which, based on the reexports in app is probably {{#bs-navbar/content}}...{{/bs-navbar/content}}

My personal recommendation though, would just be to do everything in one template and let a single navbar component respond to the authentication state by itself.

EDIT: you’ll also need to do the same for the nav, e.g. {{#bs-navbar/nav}}...{{/bs-navbar/nav}}

EDIT 2: based on the extra stuff that bs-navbar is adding to the yielded components before it yields them, the above might not work after all because it might break collapsing. You could potentially pass the same args down when you manually invoke the subcomponents but that is a lot of work considering there’s an extra layer (your custom auth/unauth components) in between

2 Likes

#4

I ended up going with your recommendation: a single template. Other attempts, as you mentioned, didn’t work. Thanks @dknutsen!

1 Like

#5

Awesome! Glad you got it working. Component hierarchies can be tricky sometimes.

1 Like