General developer forum

Renderer & html_writer vs render_from_template

 
Picture of Richard Jones
Renderer & html_writer vs render_from_template
Particularly helpful MoodlersPlugin developersTesters

I'm really happy with the way Mustache templates work in Moodle and am considering not using html_writer for any new code.

I don't really understand how that will impact theme developers though.  Currently if I write renderer display code, using html_writer and creating divs which are then styled in styles.css, the themer can change the look and feel of my plugin - move elements around even - by changing the styles.

Not using styles but putting Bootstrap 4 classes directly into the mustache template will reduce bloat but does that also limit the ability of themers?  

I mean, they can go in and change the templates but won't the changes be over-written on upgrade?  Passing css classes to mustache templates will permit them to once again change the styles if they want to but then we are back to bloat again.

I am one confused little bunny.  What do developers advise?

 
Average of ratings: -
Picture of Andrew Nicols
Re: Renderer & html_writer vs render_from_template
Core developersMoodle HQParticularly helpful MoodlersPlugin developersTesters

Hi Richard,

Not using styles but putting Bootstrap 4 classes directly into the mustache template will reduce bloat but does that also limit the ability of themers?  
Not at all. In fact, quite the opposite. It's unbelievably easy for themers to override a specific template, however by using bootstrap 4 classes you will be giving them a better starting point in the first place. As long as you design your UI for the User Experience, and using common bootstrap elements, you should be creating interfaces which need little-to-no changes by themers anyway.

We need to get away from the idea that custom-css is a good thing. It should be an exception only to be used when necessary.

I mean, they can go in and change the templates but won't the changes be over-written on upgrade? 
They can change the templates, but an upgrade won't overwrite a themer's template if it is in the theme. Of course, they will have to look for any changes you have made to your templates, and apply them to their theme, but that's no different to the current override methods (though it does sound like you may not be aware that themes can override a template by creating a new version of the template in theme/[themename]/templates/[component_name]/[template].mustache).
Passing css classes to mustache templates will permit them to once again change the styles if they want to but then we are back to bloat again.

Don't do it smile Take a look at what most of the core templates do.

You should not pass classes in from the PHP to the mustache. It is up to the UI designer to decide upon classes and look and feel, based upon the content. Rather than passing a CSS class value from the PHP into the template to mean something like "selected", you should pass a new boolean attribute to each element to give that meaning. The theme designer can then do something like:

<ul class="list-group">
{{#fruit}}
  <li class="list-group-item{{#selected}} active{{/selected}}">{{name}}</li>
{{/fruit}}
</ul>


I am one confused little bunny.  What do developers advise?

I'd advise seeing what we do in core - ideally look at more recent templates like within the Calendar. But separate your concerns:

  • PHP should be used to generate the template context with the data values. It should not know anything about the display of that content
  • Templates should be where you turn the template context into meaningful output. It should act upon data rather than an opinion of that data (i.e. CSS classes)
  • Remember that templates, and renderers can be overridden in the theme correctly without anyone having to modify your code.

Andrew

 
Average of ratings: Useful (2)
Picture of Richard Jones
Re: Renderer & html_writer vs render_from_template
Particularly helpful MoodlersPlugin developersTesters

Thanks Andrew

No I did not realize that themers could override my mustache templates, that's good to know.  

One specific issue was floating an index div to the right of the main content but now I see I should just write that in to the template using the appropriate B4 class rather than create a custom style to do it.  Makes perfect sense.

The calendar example is interesting.  There's quite a bit of programming logic in the renderer before its calls to render_from_template.  I thought this was frowned upon (fake_block_threemonths is a good example).

I've been moving such logic into classes to do data preparation and return an object (your first bullet point) and then use render_from_template in the browser-facing page.  I''m not completely sure about your use of "context" in that point - do you mean like knowing I'm a pix icon and therefore I have three values to send to the template?

Should the browser facing page call like this:

  • data = some data prep class function (in say classes/local)
  • renderer->some renderer class that takes the data and calls the template renderer
Or can I (should I) bypass the call from browser-facing to renderer altogether?

It's quite hard to find relevant examples in the current activity modules.

Richard

 
Average of ratings: -
Picture of Andrew Nicols
Re: Renderer & html_writer vs render_from_template
Core developersMoodle HQParticularly helpful MoodlersPlugin developersTesters

Yeah - the threemonth stuff is a little interesting. It's a vast improvement on the code prior to Moodle 3.4, but there is still scope for improvement.

Importantly though the only confusion there is that we get the previous and next month timestamps, and then use those to create the calendar views. Whilst not ideal, we are still only using these to get the data which will be exported.

Really the renderable should only bring things together with the renderer converting them into the context (the object passed to render_from_template).

Whilst not complete, and not wholly correct, this may help: https://tracker.moodle.org/browse/MDL-62675

It's a bit of a mess at the moment and I'm having to move parts over gradually to keep things working as I go, but the end goal is to move everything to a set of output classes which implement the renderable and templatable interfaces and move the logic out of the renderer entirely.

 
Average of ratings: -
Picture of Richard Jones
Re: Renderer & html_writer vs render_from_template
Particularly helpful MoodlersPlugin developersTesters

There is one point I'm still not clear on.  Assuming I have a template and the data for it all prepared, can I just use:

$OUTPUT->render_from_template(mod/template, $data);

As $OUTPUT itself is an instance of core_renderer (?).

or

Should I prefer to implement a custom renderer function that takes the data and sends it to the template.

In other words can I (should I) cut out the middle man?

 
Average of ratings: -
Tim at Lone Pine Koala Sanctuary
Re: Renderer & html_writer vs render_from_template
Core developersDocumentation writersParticularly helpful MoodlersPlugin developers

You should always make a custom renderer function. Some types of output override are more safely implemented by overriding a renderer method, and doing a small tweak before or after calling parent::render_xxx() instead of copying and editing a whole template. Making the renderer method definitely makes it easier for themers.

However, since Moodle 3.5, you don't acutally need to create the renderer method in the common case where the renderer method would just look like:

    render(mywidget $widget) {
        $data = $widget->export_for_template($this);
        return $this->render_from_template('mywidget', $data);
    }

See MDL-61869 for details, and thank Mark Johnson for implementing it.

 
Average of ratings: -
Picture of Richard Jones
Re: Renderer & html_writer vs render_from_template
Particularly helpful MoodlersPlugin developersTesters

Thank you Tim and Mark - and David for the example code in the tracker issue. 

 

 
Average of ratings: -