Closed TimNZ closed 12 years ago
I think I understand the issue. To confirm, can you post a complete example? Or better, fork and add a failing test?
It's definitely an ejs-locals issue, since we handle path resolving ourselves in the include
and partial
functions.
Cool, I posted this in ejs issues but had decided it was ejs-locals.
The below directory hierarchy is impossible to support even though it seems to make sense to me.
views -> home.ejs -> account ------> accounthome.ejse -> inclues ------> header.ejs ------> defaultsidenav.ejs ------> sidelisting.ejs
I have <%- include includes/defaultsidenav %> in home.ejs I have <%- include includes/sidelisting.ejs %> in defaultsidenav.ejs I have <%- include ../includes/defaultsidenav %> in account/accounthome.ejs home.ejs will load fine account/accounthome will fail as includes/defaultsidenav will fail as it can't find includes/sidelisting.
Shouldn't includes/partials be relative to the current view as opposed to the original view? I should just be able to have <%- include ./sidelisting.ejs %> in defaultsidenav.ejs and it is always found regardless of parent.
Hopefully I'm just doing something wrong here as otherwise it looks like I have to store all views in one directory with one includes directory.
Alternative is to support /absolute path relative to engine views directory.
Man I really need to make an effort to learn JS properly if I'm going to be spending this much time trying to diagnose problems! :)
The issue is this: index.js - Line 84: options.locals.partial = partial.bind(options);
It is bound the initial options object, so filename is always the initial view.
Will test and do a pull request if everything works as expected.
I am also having this problem.
I have a partial included from two different views, which includes another partial This second level partial is looking in the wrong place. It is looking relative to the parent include, not the file that included it.
./views/index.ejs
loads partial: ./views/profile/person.ejs
./views/profile/index.ejs
loads partial: person.ejs
./views/profile/person.ejs
loads partial: button.ejs
it is looking for button.ejs in ./views when I use the partial in index.ejs and it finds it correctly in ./views/profile/ when I load it from profile/index.ejs
I dug around the code, but it seems the function partial() doesn't keep track of what called it. It always assumes the original caller, not a nested one.
Here's a stack trace.
Error: /home/ettinger/projects/wishd.me/wishd/views/index.ejs:21
19| <h2>Top members</h2>
20| <ul id="active-users" class="list">
>> 21| <% users.forEach(function(user){ %>
22| <%- partial('profile/person', { person: user }) %>
23| <!--
24| <li>
/home/ettinger/projects/wishd.me/wishd/views/profile/person.ejs:8
6| <div class="username"><%= person.username %></div>
7| </a>
>> 8| <small><%- partial('follow-button', { owner: person } ) %></small>
9| </div>
10| <div class="stats">
11| <p><a href="/<%= person.username %>/lists"><% include ../stats/lists %></a></p>
Could not find partial follow-button
at Object.partial (/home/ettinger/projects/wishd.me/wishd/node_modules/ejs-locals/index.js:312:11)
at eval (eval at <anonymous> (/home/ettinger/projects/wishd.me/wishd/node_modules/ejs/lib/ejs.js:234:12))
at exports.compile (/home/ettinger/projects/wishd.me/wishd/node_modules/ejs/lib/ejs.js:239:15)
at Object.exports.render (/home/ettinger/projects/wishd.me/wishd/node_modules/ejs/lib/ejs.js:277:13)
at render (/home/ettinger/projects/wishd.me/wishd/node_modules/ejs-locals/index.js:332:20)
at Object.partial (/home/ettinger/projects/wishd.me/wishd/node_modules/ejs-locals/index.js:374:12)
at eval (eval at <anonymous> (/home/ettinger/projects/wishd.me/wishd/node_modules/ejs/lib/ejs.js:234:12))
at Array.forEach (native)
at eval (eval at <anonymous> (/home/ettinger/projects/wishd.me/wishd/node_modules/ejs/lib/ejs.js:234:12))
at exports.compile (/home/ettinger/projects/wishd.me/wishd/node_modules/ejs/lib/ejs.js:239:15)
You can see its looking for follow-button relative to the index.ejs, not person.ejs I suspect a nested include will have same problem as partial, but I have not tested.
I think if there is a / preceding path name, we should look from the ./views/ directory, then it would work everywhere.
Correct read my earlier comment. It fixes partial so it works nested, I don't bother using include.
I don't see a fix anywhere, just that line 84 was the problem. Did you paste one?
Fair enough, I thought that was the replacement line.
options.locals.partial = partial; //.bind(options);
Can you submit a pull request? I'd like to get this into the official package if it works.
This did not work for me, it still couldn't find the 2nd partial relative to the 1st partial.
I just did a diff and that is definitely the only difference between my version and master.
It might be because you need to prepend ./ to views for relative paths to work
e.g. partial('./nestedview')
I just added a test for calling partials from sub directories (see /test/fixtures/blog
). To make it pass I had to fix the issue with partial.bind
- the partial
function itself now re-binds options so that they are correct when calling a partial from a partial. I hope this fixes the issue!
(Published as ejs-locals 1.0.1 - note that include
has been removed and you should use the include directive from ejs itself if you need that functionality... apologies for different syntax)
I have a similar issue that drives me crazy. See http://stackoverflow.com/questions/25438015/use-ejs-locals-partials-with-data-json-typeerror-converting-circular-structur
The path is random, sometimes based on the caller, sometimes based on the layout and it changes when i save the file. Is it possible to use a non-relative path?
The resolved paths of includes/partials inside a view that is itself an include/partial is relative to the original view and not the current rendering view.
I tried a quick debug trace and I'm not sure if it's ejs or ejs-locals