jet icon indicating copy to clipboard operation
jet copied to clipboard

Importing Jet Template does not bring Variables

Open JesseRyan opened this issue 6 years ago • 10 comments

Consider the following:

Params.jet ->
{{ param1 := 1 }}
{{ param2 := 2 }}
{{ param3 := 3 }}
{{ param4 := 4 }}

then import Params.jet in another template.

SomeJetTemplate.jet ->
{{ import "Params.jet" }}
{{ "This is a string needing to use parameters : " + param1 }}

This throws a block level scope failure that param1 does not exist in the scope of the block... Is there a way to load parameter configurations like this into other jet templates? Seems like this should work...

I do of course understand that parameters can be added to vars and imported into templates from compiled go code. However, we would like to remain dynamic and maintain the essence of Jet templates in that we could change the text i.e. the parameters on the fly without having to recompile go code.

JesseRyan avatar Oct 17 '18 20:10 JesseRyan

Can you try include instead of import?

Import is used for making block definitions available for use, include evaluates the templates.

On Oct 17, 2018, at 10:25 PM, JesseRyan [email protected] wrote:

Consider the following:

Params.jet -> {{ param1 := 1 }} {{ param2 := 2 }} {{ param3 := 3 }} {{ param4 := 4 }} then import Params.jet in another template.

SomeJetTemplate.jet -> {{ import "Params.jet" }} {{ "This is a string needing to use parameters : " + param1 }} This throws a block level scope failure that param1 does not exist in the scope of the block... Is there a way to load parameter configurations like this into other jet templates? Seems like this should work...

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or mute the thread.

annismckenzie avatar Oct 17 '18 22:10 annismckenzie

Did that help?

annismckenzie avatar Oct 19 '18 18:10 annismckenzie

Hey thank you for attention again,

Unfortunately this did not work. Is this intended to work? Perhaps I need to test this in a block for evaluation? Right now its just included in the template.

Do you have a working example? It would be really great if this would work. JET is already heroic by the way.

JesseRyan avatar Oct 23 '18 21:10 JesseRyan

having the same issue, +1 for feature request.

voidhaze avatar May 13 '19 09:05 voidhaze

found a work around; {{ var = value }} seems to declare with global scope

voidhaze avatar May 13 '19 12:05 voidhaze

You have to pass data as third parameter like this,

 {{ include "Params.jet" .  }} // Here '.' means value of data passed to scope
 {{ include "Params.jet" [some variable]  }} // Here '.' means value of data passed to scope

Example,

Main Html Template https://github.com/mchampaneri/MarchCMS/blob/master/themes/shortshot/pages/main.html

Partial Template https://github.com/mchampaneri/MarchCMS/blob/master/themes/shortshot/pages/partials/singlePost.html

mchampaneri avatar Aug 04 '19 03:08 mchampaneri

found a work around; {{ var = value }} seems to declare with global scope

You don't need to declare in global scope.

mchampaneri avatar Aug 04 '19 04:08 mchampaneri

found a work around; {{ var = value }} seems to declare with global scope

That was actually a bug and fixed in https://github.com/CloudyKit/jet/commit/16fe51250caa1c7e875d58b2dcd01e33e85b2e0e, so this won't work as a "workaround" anymore.

I'll look into importing variables as well was blocks, but I'm not sure it's something you'd want. Would you expect a variable "foo" from an imported template to overwrite a variable "foo" in your current template scope?

sauerbraten avatar Jul 01 '20 20:07 sauerbraten

@sauerbraten actually, in some cases this would be quite handy. Imagine you have set of templates that should be able to derive the same set of variables/attributes from what was provided to them.

For example:

  • let's asume you use jet to generate source codes for data warehouse transformations
  • let's assume that you have groups of databases serviced by different "ETL engines"
  • let's assume that you do not want to hardcode logic into the generating application

In this situation, it would be most useful to be able to include a template which contains the common logic and provides metadata to other templates. Imagine it as a subroutine.

Workaround:

  • in my solution I use a custom function which creates a map[string]string, included template stores metadata into it, and this allows the "parent" template reuse them.

This solution is "good from far", but far from good, I am afraid. But in my case it works.

Please note that I am posting this only to show that the case for this functionality is probably there, not to offer any solution. For my case, it would be best if this was provided "out of the box", but I am afraid my knowledge of Jet internals is insufficcient for such a task.

Example use case

Please not that the example uses custom delimiters.

Consumer of the "common" logic

// include "globals"
<%- include "../COMMON/trf_commons.jet" map("database", o.GetTable().Database) %>

// later in the template .... access metadata prepared by trf_commons.jet
<%- pmrootdir := stashGet("pmRootDir")  %>

Provider of the "common" logic" (trf_commons.jet)

PLease note that this is a contrived and incomplete example. But it shows the idea.

<%- stashReset(false) %>
<%- database  := upper(.["database"])      %>
<%- if 
        database == "EP_MREP"       
     || database == "EP_MREP_WRK"
     || database == "EP_MREPADJ"
     || database == "EP_IPTV"
     || database == "EP_IPTV_WRK"           %>
     <%- engineId   = "21"                  %>
     <%- pmRootDir  = "PMRootDir_E21"       %>
     <%- streamINITName  = "START_021"      %>
     <%- streamFINALName = "FINAL_021"      %>
     <%- jobCategory     = "COMMAND_E21"    %>
<% end %>

<%- stashSet("engineId",     engineId)   %>
<%- stashSet("pmRootDir",    pmRootDir)  %>
<%- stashSet("auditRunID",   auditRunID) %>
<%- stashSet("pdc.streamINITName" , streamINITName  )  %>
<%- stashSet("pdc.streamFINALName", streamFINALName )  %>
<%- stashSet("pdc.jobCategory"    , jobCategory     )  %>

Snippet of code

// stashReset creates an empty global stash. The global stash is mutex protected map[string]string, which can
// later on be accessed via stashSet and stashGet functions.
// The function takes one oprional parameter. If the value provided is string "true", then stashGet WILL panic
// if you attempt to access key which was not yet stored using stashSet.
func stashReset(a jet.Arguments) reflect.Value {
	a.RequireNumOfArguments("stashReset", 0, 1)
	canPanic := strings.ToLower(jetGetParam(a, 0)) == "true"
	globalStash.m.Lock()
	globalStash.stash = make(map[string]string)
	globalStash.canPanic = canPanic
	globalStash.m.Unlock()
	return reflect.ValueOf("")
}

// stashSet stores a string value in the stash, and returns an empty string.
func stashSet(a jet.Arguments) reflect.Value {
	a.RequireNumOfArguments("stashSet", 2, 2)
	key := jetGetParam(a, 0)
	val := jetGetParam(a, 1)
	globalStash.m.Lock()
	globalStash.stash[key] = val
	globalStash.m.Unlock()
	return reflect.ValueOf("")
}

// stashGet retrieves string from global stash.
func stashGet(a jet.Arguments) reflect.Value {
	a.RequireNumOfArguments("stashGet", 1, 1)
	key := jetGetParam(a, 0)
	globalStash.m.Lock()
	val, ok := globalStash.stash[key]
	globalStash.m.Unlock()
	if !ok {
		if globalStash.canPanic {
			a.Panicf("stashGet: key not in stash: %s", key)
		}
	}
	r := reflect.ValueOf(val)
	return r
}

jan-herout avatar Jul 01 '21 14:07 jan-herout

It sounds like you could use extends for your use case: https://github.com/CloudyKit/jet/blob/master/docs/syntax.md#extends

Have a base template defining all the "global" vars you want, then make different "consuming" templates that extend from it. Since code outside of blocks doesn't run in the "consumer" (extending) templates, you'd have to define something like a main block and yield that in the base, as described in the docs.

Would this not solve the problem you're having?

sauerbraten avatar Jul 13 '21 18:07 sauerbraten