bminer / node-blade

Blade - HTML Template Compiler, inspired by Jade & Haml
Other
320 stars 28 forks source link

Meteor: Included templates still use the context of the parent #103

Closed bminer closed 11 years ago

bminer commented 12 years ago

When you include a template using include "foo.blade" the subtemplate uses the data context of the current template.

VanCoding commented 12 years ago

Thanks for creating the issue. I'm so glad you're working on it!

Great work! :)

bminer commented 11 years ago

@VanCoding - has this been fixed? Can you confirm? Thanks!

bminer commented 11 years ago

Can someone please confirm that this bug has been fixed? Thanks!

bminer commented 11 years ago

This issue has been fixed. Included templates inherit their parent's locals and view helpers, but they can be overwritten. Issue #141 discusses the possibility of preventing included views from inheriting their parent's locals by default.

brianephraim commented 11 years ago

I'm having the following issue:

Within the file parent.blade, there is the following dynamic include:

include dynamicTemplateVaraible exposing someDataVariable

Here, someVariable is not available within the template we assigned to dynamicTemplateVaraible. Instead, dynamicTemplateVaraible has the same locals as parent.blade.

-=-=-=-==-

However, in non-dynamic includes things behave as expected, as in:

include "nonDynamic.blade" exposing someDataVariable

Here, someDataVariable is available to the included template, and the parent locals are not available to the child.

======= UPDATE

I found a pretty clean workaround.

Create a dynamicInclude.blade file. That file should contain only this: include dynamicIncludeName

Then when you want to use a dynamic include in a parent template, write it like this: -var dynamicIncludeName = variableDerivedFromLocalOrWhatever; include 'dynamicInclude' exposing dynamicIncludeName, whateverOtherVariable, anotherVariableEtc

What happens is dynamicInclude.blade will receive the exposed variables and use them as locals, as in this part, it is a static include and static includes do fine with receiving exposed variables. dynamicInclude.blade uses the variable dynamicIncludeName to dynamically include the desired dynamic template. Because this is a dynamic include, exposing variables doesn't work, and it receives the local variables of its parent, and those local variables (whateverOtherVariable,anotherVariableEtc) are the ones we intended to reach the desired dynamic template.

bminer commented 11 years ago

That's some weird behavior... I'll have to track down the issue as time permits. Thanks for the bug report!

brianephraim commented 11 years ago

Looks like my workaround doesn't work in Safari. I'm getting a nasty error:

TypeError: setting a property that has only a getter at /Users/username/meteortest/groop3/views/characterList.blade:2:1

1 | -var dynamicIncludeName = nestedViewItem.includeName + 'Panel'; 2 > include dynamicIncludeName

bminer commented 11 years ago

Could you post the full stack trace, please?

bminer commented 11 years ago

@defualt - I cannot replicate your bug. I believe that this issue is now closed. Try upgrading to the latest version of Blade and Meteor 0.6.2.

brianephraim commented 11 years ago

I've updated and after updating, I've created new meteor/mrt/blade projects to be sure I'm working with the most up to date and the error persists. I think my particular exception is a result of workarounds for some bugs in meteor or blade, but I think the root of the issue is that dynamic includes are not exposing specified variables.

I made this repository to demonstrate the bug. You will find instructions for adding and removing commenting to show meaningful errors if you mrt it. https://github.com/defualt/bladebug

And this is the project I am working on where you can see the exception in Safari. https://github.com/defualt/Peanuts

Here is the stack trace from my Peanuts project in safari:

(anonymous function)() at characterListPanel.js:52 (anonymous function)() at deftemplate.js:138 (anonymous function)() at spark.js:846 (anonymous function)() at deps.js:129 (anonymous function)() at deps.js:64 (anonymous function)() at deps.js:255 (anonymous function)() at spark.js:844 (anonymous function)() at deftemplate.js:135 (anonymous function)() at spark.js:1183 (anonymous function)() at deftemplate.js:116 (anonymous function)() at spark.js:1114 (anonymous function)() at deftemplate.js:115 (anonymous function)() at runtime-meteor.js:45 (anonymous function)() at spark.js:1114 (anonymous function)() at runtime-meteor.js:44 anonymous() at characterList.js:15 (anonymous function)() at characterList.js:25 (anonymous function)() at deftemplate.js:138 (anonymous function)() at spark.js:846 (anonymous function)() at deps.js:129 (anonymous function)() at deps.js:64 (anonymous function)() at deps.js:255 (anonymous function)() at spark.js:844 (anonymous function)() at deftemplate.js:135 (anonymous function)() at spark.js:1183 (anonymous function)() at deftemplate.js:116 (anonymous function)() at spark.js:1114 (anonymous function)() at deftemplate.js:115 (anonymous function)() at runtime-meteor.js:45 (anonymous function)() at spark.js:1114 (anonymous function)() at runtime-meteor.js:44 anonymous() at dynamicInclude.js:15 (anonymous function)() at dynamicInclude.js:25 (anonymous function)() at deftemplate.js:138 (anonymous function)() at spark.js:846 (anonymous function)() at deps.js:129 (anonymous function)() at deps.js:64 (anonymous function)() at deps.js:255 (anonymous function)() at spark.js:844 (anonymous function)() at deftemplate.js:135 (anonymous function)() at spark.js:1183 (anonymous function)() at deftemplate.js:116 (anonymous function)() at spark.js:1114 (anonymous function)() at deftemplate.js:115 (anonymous function)() at runtime-meteor.js:45 (anonymous function)() at spark.js:1114 (anonymous function)() at runtime-meteor.js:44 (anonymous function)() at rootView.js:39 (anonymous function)() at runtime.js:512 wrapper() at runtime.js:462isolateWrapper() at runtime.js:467 (anonymous function)() at runtime.js:510 (anonymous function)() at spark.js:1114 itemFuncWrapper() at runtime.js:509 (anonymous function)() at runtime.js:533 anonymous() at rootView.js:31 (anonymous function)() at rootView.js:57 (anonymous function)() at deftemplate.js:138 (anonymous function)() at spark.js:846 (anonymous function)() at deps.js:129 (anonymous function)() at deps.js:64 (anonymous function)() at deps.js:255 (anonymous function)() at spark.js:844 (anonymous function)() at deftemplate.js:135 (anonymous function)() at spark.js:1183 (anonymous function)() at deftemplate.js:116 (anonymous function)() at spark.js:1114 (anonymous function)() at deftemplate.js:115 (anonymous function)() at peanuts.js:17 (anonymous function)() at spark.js:846 (anonymous function)() at deps.js:129 (anonymous function)() at deps.js:64 (anonymous function)() at deps.js:255 (anonymous function)() at spark.js:844 (anonymous function)() at convenience.js:3 (anonymous function)() at spark.js:39 (anonymous function)() at spark.js:211 (anonymous function)() at spark.js:411 (anonymous function)() at convenience.js:2 (anonymous function)() at peanuts.js:14 (anonymous function)() at bladestest.js:230 (anonymous function)() at bladestest.js:229 (anonymous function)() at startup_client.js:8

Finally, the Blade documentation about includes is somewhat misleading. Notice that you are expressing a global variable , which you are then exposing to a child template.

- header = "Header: 1, 2, 3"

  • text = "This is some text: 1, 2, 3"
  • for(var i = 0; i < 10; i++)    include "foobar" exposing i, text

"text" is available in the included template and everywhere else because it's global. In this example, you are including "foobar.blade" non-dynamically. If you were to include it dynamically, and if you expressed "text" with a "var" keyword, then "text" would not be available to the child. This tripped me up while trying to figure out this bug because I used this as an example and it appeared that my dynamic include/exposing was working, but this was only because the global variable was making it into my child template due to it's being global, not due its being exposed.

Thanks for your work on this.

bminer commented 11 years ago

@defualt - I can now duplicate your bug, and you are correct. I will correct this shortly.

brianephraim commented 11 years ago

Since updating, variables will only be passed into an included template if you use "exposing". If you omit "exposing [variables]" then no local variables get passed into the included template.

This behavior does not match the documentation. "By default, Blade will pass the parent's local variables to the included template; however, when using the exposing keyword, you can specify exactly which variables are to be exposed to the included template."

I've updated https://github.com/defualt/bladebug to demonstrate the issue.


Also, I can confirm that exposing variables in a dynamic include effectively passes those variables into the included template. So now dynamic and non-dynamic includes that use "exposing" function as expected.

bminer commented 11 years ago

Sorry, @defualt - I should clarify the documentation. Blade will pass view locals to included (child) templates. It will not automatically pass local variables declared using the var keyword. It only passes the properties of the locals Object.

bminer commented 11 years ago

@defualt - Thank you very much for your help. I believe that the documentation and the implementation should now be consistent with one another. If not, please feel free to post back here.

Thanks again!