1

I am trying to build a filter function via dropdown menus for courses inside a Moodle block plugin. From what I've learned, the way to go would be to

  1. Use select element in template
  2. Handle select element's onchange event in js file
  3. Call PHP file with query param from event handler
  4. Use query param in PHP function

So far I have succeeded to implement this approach apart from step 3 and 4.

When calling the PHP file with the load function .load('/blocks/course_overview_page/block_course_overview_page.php?language=' + $('[data-action="language-select"]').val()), it does not redirect to that page, but it works when I directly open the URL in the browser.

To filter the courses I have written a controller.php file to handle database requests. The controller is required in my plugin base file. But when I call the base file it displays the error that it's missing the block_base class that it extends from.

Now I wonder if I made a mistake or if I even chose the wrong approach. Any help is appreciated.

I used this answer to help implement this.

Here is my code:

filter.mustache

<select name="language-select" data-action="language-select">
  {{#languages}}
    <option value="{{.}}">{{.}}</option>
  {{/languages}}
</select>

filter.js

window.onload = init;

function init() {

    /* load base plugin file and send language as query param */
    $('[data-action="language-select"]').change(function() {
        console.log($('[data-action="language-select"]').val());
        $('[data-action="language-select"]').load('/blocks/course_overview_page/block_course_overview_page.php?language=' + $('[data-action="language-select"]').val());
    });

}

block_course_overview_page.php

require_once(__DIR__ . '/db/controller.php');
require_once($CFG->libdir . '/pagelib.php');

class block_course_overview_page extends block_base {
  public function get_content() {
    global $CFG, $OUTPUT, $PAGE;

    if ($this->content !== null) {
      return $this->content;
    }

    $this->content = new stdClass();

    /* load js script to handle events */
    $PAGE->requires->js(new moodle_url('/blocks/course_overview_page/js/filter.js'));

    $languageoptions = get_languages();

    /* get language from query params */
    $selectedlanguage = optional_param('language',  0,  PARAM_INT);

    if ($selectedlanguage) {
      get_filtered_courses($selectedlanguage);
    }

    /* data object is necessary to wrap courses list for iteration inside template */
    $data = (object)[
      'courses' => array_values(get_all_courses_for_overview()),
      'languages' => $languageoptions
    ];

    /* render template and pass data */
    $this->content->text = $OUTPUT->render_from_template('block_course_overview_page/cards', $data);

    return $this->content;
  }
J. Unkrass
  • 730
  • 5
  • 16

1 Answers1

1

Use the Moodle Fragments API to call the php function from Mustache using JS. For more about fragments. Please read the official documention. https://docs.moodle.org/dev/Fragment

Here the example to call PHP function from Mustache in Moodle.

  1. Create a fragment output function in your component/plugin lib.php

Replace your component and function name.

function YOUR_COMPONENT_output_fragment_FUNCTIONNAME() {
   // Your function code goes here.
}

In your case, it should be

function block_course_overview_output_fragment_filter($args) {
  // Your code goes here.
  $language = $args['language];
}
  1. Call the fragment from your mustache. Included your js code from filter.js.

Fragment call from js or mustache.

Fragment.loadFragment("ComponentName", "PHPFunctionName", ContextID, args);

Add the below code to the bottom of your mustache file.

{{#js}}
require(['jquery', 'core/fragment'], function($, Fragment) {

    window.onload = init;

    function init() {
        /* load base plugin file and send language as query param */
        $('[data-action="language-select"]').change(function() {
            console.log($('[data-action="language-select"]').val());
            // Pass the system context id during the template render.
            var contextid = "{{contextid}}";
            var args = {
                "language": $('[data-action="language-select"]').val()
            };
            Fragment.loadFragment('block_course_overview', 'filter', contextid, args).then((html, js) => {
                // You can get the return data in variable "html"
                $('[data-action="language-select"]').html(html);
            })
        });
    }
})
{{/js}}
Prasanna T
  • 169
  • 6