xslate / p5-Text-Xslate

Scalable template engine for Perl5
https://metacpan.org/release/Text-Xslate
Other
121 stars 47 forks source link

Question/Suggestion #29

Closed forwardever closed 13 years ago

forwardever commented 13 years ago

I would like to create some tag helpers for use in templates, e.g. creating a text_field, I use <% text_field('title', size => 40, maxlength => 33) %>

It works already quite well.

The problem is that I have to recreate the code refs for each request, to get updated controller data into the code ref. (e.g. for automatic form refill in case of error)

I would like to pass a code ref to Xslate, and Xslate would than make sure that the first parameter is e.g. always my controller object.

e.g., I have the following code ref:

my $link_to = sub {
    my $c = shift;
    my $name = shift;
    my $route_name = shift;
    my $route_params = shift;

    my $path = $c->app->routes->build_path($route_name, %$route_params);

    my $rel_url = '/'.$path;

    return qq|<a href="$rel_url">$name</a>|;

};

I can than say: <% link_to($c, 'Delete' => 'posts_destroy' => { id => $post.id }) %>

which is not very nice, so I would like to just call <% link_to('Delete' => 'posts_destroy' => { id => $post.id }) %>

Is there a way to do this already?

Just found function => \%functions so far. Maybe, somethink like methdo => \%methods, self => $self

would make sense? Or are there already ways to do this?

gfx commented 13 years ago

You are already able to invoke methods for objects. Why do you add methods to the controller class?

forwardever commented 13 years ago

thanks for your reply. I will try to explain again what I want to do, maybe my first message was a bit confusing:

e.g. I have included the following code in Xslate template (I use <% instead of <: ) <% text_field('title', size => 40, maxlength => 33) %> to display a text field (html form)

In order to do this, I just pass a code ref: function => {text_field => coderef} using html_builder

Now, I want to read existing values from a database and fill the text field with these values, so the code ref needs access to my controller object (that temporarily holds this data).

In order to do this, I have to say in Xslate template:

<% text_field($controller, 'title', size => 40, maxlength => 33) %>

and my code ref then gets the controller as the first argument, so it can access the required data.

The problem is just that I have to explicitly pass $controller as the first argument everytime I include a new tag helper, and my question is whether there is a better way to give my code ref access to the controller object, so that I can just say

<% text_field('title', size => 40, maxlength => 33) %>

(nicer API)

and the text_field code ref still has access to the controller instance?

The goal is to create Mojolicious like tag helpers. Wasn't able to find a nice solution so far (just a workaround which requires to create a new Xslate instance with each request, create new code ref for each request and pass them to the Xslate instance).

Hope this message doesn't make it even harder to understand the issue :)

gfx commented 13 years ago

Well, I understand what you want.

So I suggest function parameters:

my $controller = ...;
my $link_to = sub {  text_field($controller, @_) };

$tx->render_string('<: $link_to(...) :>', { link_to => $link_to });

What do you think of it?

forwardever commented 13 years ago

your solution works, still not sure I like calling functions using $helper()

I will create another code ref around the code ref provided by html_builder for now:

my $code_ref = html_builder(\&{$helpers->{$name}});

my $new_code_ref = sub {$code_ref->($c, @_)};

this will cost performance, as I have to create a new Xslate instance per request, but at least, it works and there are no leaks

I will switch to your solution in case the template becomes the bottleneck

thanks for your help