go-aah / aah

A secure, flexible, rapid Go web framework
https://aahframework.org
MIT License
690 stars 33 forks source link

Support for partials #217

Closed vcraescu closed 5 years ago

vcraescu commented 5 years ago

It will be good to have support for partial templates. As far as I can, at this moment, you can only include templates from "common" folder which is good but It's not enough in a large web application.

Need to be able to do something like this:

{{ partial("users/form.html") }}

Right now I'm just duplicating code because I don't want to put all the partials inside common folder since those templates only makes sense in user context and I will not use them anywhere else.

Thanks!


AugustHell commented 5 years ago

You can do this with template functions: https://docs.aahframework.org/v0.11/template-funcs.html#adding-your-custom-funcs-or-third-party-funcs

A simple example by only adding a way to include html files:

./app/init.go


import(
    "bytes"
    "html/template"
    "path/filepath"
)

    aah.AddTemplateFunc(template.FuncMap{
        "Partials": func(filename string) template.HTML {
            t := template.New(filename)
            templatepath, err := filepath.Abs(filename)
            if err != nil {
                // error handling
                return template.HTML("Error")
            }
            t, err = t.ParseFiles(templatepath)
            if err != nil {
                // error handling
                return template.HTML("Error")
            }
            var tbuffer bytes.Buffer
            t.Execute(&tbuffer, nil)
            return template.HTML(tbuffer.String())
        },
    })

To use this, add to your template: {{ Partials "./views/users/form.html" }}

Instead of writing an anonymous function in init.go like in this simple example, you can add a component function to better organize your code. I'm using this in an extended way thru defining some kind of page components, which I place in a app/components folder. These template functions allow to add parameters of any kind (like struct), which I can add to the "partial" template thru the controller with aah.Data.

vcraescu commented 5 years ago

@AugustHell I know I can add a function to include partials, but this is a feature request because I believe it's an important feature for a web framework.

jeevatkm commented 5 years ago

@vcraescu Thanks for bringing up use case, which would be beneficial to aah users.

@AugustHell Thanks for your inputs and helping aah community. I will take your inputs, generalize and add it aah view template functions in next release.

jeevatkm commented 5 years ago

@vcraescu @AugustHell I was implementing partials template func then I thought following idea. Have a look and please let me know your thoughts.

Existing feature:

Currently supported syntax of include:

Both syntax yield same results
---------------------------------
{{ include "sample/filename.html" . }}
{{ include "common/sample/filename.html" . }}

Both syntax yield same results
---------------------------------
{{ include "filename.html" . }}
{{ include "common/filename.html" . }}

So, add partials capability into func include retaining existing syntax support and new one.

E.g.: adding new syntax instead new tmpl func

Both syntax yield same results
---------------------------------
{{ include "/views/users/form.html" . }}
{{ include "/users/form.html" . }}
AugustHell commented 5 years ago

I very much like this:

{{ include "/views/users/form.html" . }} if the . dot is for passing by a data struct, its perfect. Then I can use it for a hmvc like structure with components à la "/components/form/newuser.html"

vcraescu commented 5 years ago

@jeevatkm I don't think it's a good idea to support both absolute and relative paths because it's confusing. Only relative paths to project root should be allowed.

{{ include "relative/path/to/file.html" }}

So only {{ include "views/users/form.html" . }} should be valid. This allows the flexibility to include any file from any folder.

jeevatkm commented 5 years ago

@AugustHell Yes, . dot (second param) is for passing data to template. Also I'm thinking of making second param optional too.

@vcraescu Yeah idea is to have ability to include template from anywhere under view/** directory. However I would like to mention why I thought of having root / approach - Directory views is the root directory for all view templates, typically it would make sense to call it as /views/**.

For e.g:

<!-- absolute path syntax -->
{{ include "/views/users/form.html" . }}
{{ include "/users/form.html" . }}

<!-- relative path syntax -->
{{ include "users/form.html" . }}

Also order of resolving relative path has crux in it. Example-

<!-- Load from respect to parent template (currently this principle is not fully exists 
because include only loads the template within directory-tree of common).
I would like to bring this capability into aah view engine -->
{{ include "users/form.html" . }}

<!-- Load from respect to view root directory. -->
{{ include "/views/users/form.html" . }}
{{ include "/users/form.html" . }}

We can advocate bring the same order of path resolve principle without beginning slash /. Check template exists in respect to parent template if yes use it otherwise fallback to view root template. (currently I'm discussing my thoughts. I'm not sure which is feasible or not, I will have to try the implementation. I'm fine with relative path reference everywhere and view engine figures out internally)

I hope I have explained it in detail about my thoughts.

vcraescu commented 5 years ago

@jeevatkm Makes sense what you're saying if BC is your concern. It might be a good idea to have the imports relative to views folder and not to project dir. I have in mind some cases where this might be handy.

But

{{ include "/views/users/form.html" . }}
{{ include "/users/form.html" . }}

these 2 are a big NO-NO from my point of view. 2 different paths that does same thing. Too much "magic" which is error prone and hard to maintain in long term.

So, if you want to keep existing functionality (importing from "common" directory) then I suggest just 2 cases:

<!-- include from views dir -->
{{ include "/users/form.html" . }}

<!-- include from common dir --> 
{{ include "users/form.html" . }}

Although, I would drop the include from common folder cause because it's so uncommon and I don't see any advantages having such a feature.

jeevatkm commented 5 years ago

@vcraescu Yes, I agree. Since new feature would satisfy including a files from common directory too.

I think, I will deprecated the existing behavior of include in v0.12.0 (if I'm able to add auto migrate for view files, then safely I can remove the existing behavior too. Let's what I can do) and introduce new include behavior.

jeevatkm commented 5 years ago

Done 😄