Is Your AngularUI Router not Working with Pug/Jade Templates?


Oh web development...sometimes you make me very punchy, especially when you mysteriously refuse to work. I was recently doing some work using the angular-ui router along with Pug templates (previously known as Jade) and my embedded ui-view just didn't want to show up for some reason. About 20 minutes and a few choice words later I finally figured out what was going on.

TL;DR

If you're using Pug with ui-router and your ui-view is not showing up, try putting

at the top of the embedded pug file, even if the containing file already has it declared at the top.

Here is a fully working example that shows the issue and various solutions. If you don't want to download and run a node app, here is a plunk that shows the basics, but it doesn't use Pug.

Details

Turns out that the issue has to do with how Pug renders the div that contains the ui-view attribute and how picky ui-router is when it comes to that particular attribute. Here is a simple pug file that uses ui-view to embed a view.

Here is the included file, home.pug:

You'd probably expect this to display something like this:

Sadly for you, it will not. To understand why, you have to look at the HTML that pug is outputting. I'm going to truncate a few things for brevity, but the important stuff looks like this:

As you can see, the ui-view is in place but it's simply not being filled in with the content from the home.pug file. What you might not have noticed is that the ui-view attribute of the <div> that is supposed to contain that content has a value of "ui-view" (that is <div ui-view="ui-view">). This is not what the angular-ui router system expects to see. It expects to see <div ui-view>. That is, the attribute is not supposed to have a value. This is why it's not working!

So how do we fix this? Well as it turns out there are quite a few options available to us.

Solution 1

Put doctype html at the top of any file that includes an angular-ui container (that is, it has the line <div ui-view>).

By default, Pug templates do not support attributes without values. So if you do something like div(ui-view) it will silently stick a value of "ui-view" onto that attribute and give you <div ui-view="ui-view">. If you put doctype html at the top of the file, pug will stop adding in attribute values for you.

Since you really should be using doctype html anyway, this is the solution that I recommend. Keep in mind however, that you must put it inside of every file that contains a div(ui-view), even if that file is contained by another file that already declares doctype html. So, for example, if you have a nested view that has a div(ui-view) inside another div(ui-view) you must declare doctype html inside both files!

Solution 2

Tell the pug engine to use doctype html for every file. If you look here you'll see that when you are starting the pug engine on the server side you can pass it a doctype option which will prevent you from having to include it at the top over every file.

Solution 3

Write .ui-view, which compiles into <div class="ui-view"></div> instead of div(ui-view). AngularUI router is perfectly happy if you declare the view container using the class attribute rather than a non-standard attribute like ui-view. I don't use this syntax because it's just a little bit wordier than just having the ui-view attribute. Plus you really should be using doctype html anyway.

Solution 4

Write div(ui-view="") instead of div(ui-view).

This also works without having to declare a doctype html at the top. It seems a bit unintuitive because you might expect the resulting html to be <div ui-view=""> but that's not what Pug outputs. For some reason, it decides to output <div ui-view>. Kind of odd. I'm not as big a fan of this solution because what you right in pug is not what you get in your html.

Solution 5

Use raw html inside your pug template.

<div ui-view>You can also simply write inside your pug template. Here pug will output the HTML verbatim, which does work but seems like an unnecessary hack to me. Presumably you're using pug because you want to use the shorthand syntax and, like me, you view angle brackets and closing tags as an affront to your sensibilities.

Conclusion

So there you go. Be careful when using Pug templates with really picky ui frameworks! Hopefully you'll find this post before too much searching.

Here is a fully working example that shows the issue and various solutions. If you don't want to download and run a node app, here is a plunk that shows the basics, but it doesn't use Pug.

#angularjs #uirouter #jade #pug

Recent Posts
Archive