Error in Moodle Messaging 4.1.1+ (Build: 20230210)

Error in Moodle Messaging 4.1.1+ (Build: 20230210)

by Andrés Elpeza -
Number of replies: 5

Hello everyone, I hope you are well.

Recently, a problem started occurring with the messaging sidebar in Moodle. Below, I describe the problem and provide the error that appears in the console along with the line where the error originates.

Clarifications:
Last week, the company that provides the server to my workplace updated the PHP version, which caused problems with TTL, preventing access to the platform. It is assumed that this issue has been resolved.

I should also clarify that at no point this year have I updated Moodle's configuration or modified any file on the server.

The theme I use in Moodle is Move, which we have not updated at any time, nor have we updated any other plugin installed on the platform.

The company providing the server says it is a problem with our Moodle, not their issue.

Problem Description:
The problem is that when clicking on the chat bubble to open messaging, the sidebar that should unfold on the right does not appear, and the error is resolved by refreshing the page with Ctrl+F5.

It is also worth mentioning that this error does not always occur; sometimes it works perfectly on the first try from certain devices.

The messaging service works perfectly. If I go directly to the page "myDomain/message/index.php", I can send messages without any issues.

Error printed in the console:

Uncaught TypeError: Cannot read properties of null (reading 'attr')
    at first.js:1878:2423
    at show (first.js:1878:2444)
    at String.changeRoute (first.js:2037:1181)
    at Object.go (first.js:2037:1864)
    at show (first.js:1894:3054)
    at first.js:1894:5436
    at first.js:734:684
    at Array.forEach (<anonymous>)
    at _exports.publish (first.js:734:656)
    at HTMLAnchorElement.<anonymous> (first.js:1957:725)

Line where the error originates:

var fromPanel = header.attr("data-in-panel") ? "frompanel" : null;
            getSearchInput(header).val("");
            var loggedInUserId = function(body) {
                return body.attr("data-user-id") -Line 1878 where the error originates-
            }(body)
              , allCounts = function(loggedInUserId) {
                return null === loadAllCountsPromise && (loadAllCountsPromise = MessageRepository.getAllConversationCounts(loggedInUserId)),
                loadAllCountsPromise
            }(loggedInUserId)

Attempts to Resolve:
Based on my research, it might be related to the PHP update error and/or the cache. I purged all Moodle caches, but the problem persists, and I cleared all data from my browsers, but that didn't work either.

If anyone has encountered this error or could guide me on how to resolve it, I would greatly appreciate it.

Average of ratings: -
In reply to Andrés Elpeza

Re: Error in Moodle Messaging 4.1.1+ (Build: 20230210)

by Ken Task -
Picture of Particularly helpful Moodlers

"updated the PHP version"

What is the version of PHP now?

"theme I use in Moodle is Move"

Theme is called moove.
Please see:
https://moodle.org/plugins/theme_moove
and
https://moodle.org/plugins/theme_moove/versions for specific versions of moove that match your core version 4.1.1+

Strongly suggest, editing config.php file for your moodle
and forcing the theme to boost by adding a line:

$CFG->theme='boost';

Just above the comments - last lines with // in front of them
at the end of config.php

No need to restart anything ... just access the site as normal.

Does the issue go away when forcing theme to boost?

'SoS', Ken

Average of ratings: Useful (1)
In reply to Ken Task

Re: Error in Moodle Messaging 4.1.1+ (Build: 20230210)

by Andrés Elpeza -
They told me they updated from version 8 to 8.1
I checked the Moove repository, and I have the latest version of the plugin for my Moodle version.
Now I’m going to try what you suggested about modifying the config.php. I really appreciate your help.
Average of ratings: Useful (1)
In reply to Ken Task

Re: Error in Moodle Messaging 4.1.1+ (Build: 20230210)

by Alex Hird -

"updated the PHP version"

What is the version of PHP now?

"theme I use in Moodle is Move"

Theme is called moove.
Please see:
https://moodle.org/plugins/theme_moove
and
https://moodle.org/plugins/theme_moove/versions for specific versions of moove that match your core version 4.1.1+

Strongly suggest, editing config.php file for your moodle...

Thanks so much, Ken! Switching to the Boost theme using the config.php edit worked perfectly—issue is gone now. Really appreciate your clear instructions and quick help!

In reply to Andrés Elpeza

Re: Error in Moodle Messaging 4.1.1+ (Build: 20230210)

by Sebastián da Costa -
Hi, in a Moodle that I manage we started to have the same problem, were you able to solve it?
In reply to Andrés Elpeza

Error in Moodle Messaging 4.1.1+ (Build: 20230210)

by Mike Young -
Hi Andrés and @Sebastián da Costa and anyone else who might be working on an old Moodle instance with a Boost-derived theme (or Boost itself, where this error also pops up). I finally managed to squash this.

As a disclaimer, this is by no means the only or even the correct way to fix this. It's just the way that worked for me. Ymmv and all that.

I never figured out why this only occurs occasionally, but basically, as far as I could tell: in Moodle 4.1.x with Boost or Boost child themes, Moodle’s JS would sometimes init the Messages drawer before the HTML finished loading. The overview controller (core_message/message_drawer_view_overview.show()) was therefore handed a null body and crashed with “Cannot read properties of null" on body.attr("data-user-id").

So I wrote a script to insert into the head.mustache of our theme. The script hooks into RequireJS’s onResourceLoad callback, which runs the moment each module is defined. When the overview module appears, it wraps its show() method. If that method is called too early (header or body still null), the wrapper re-queries the drawer’s root for the right nodes and hands them to the original function.

Here's the script! It goes below {{{ output.standard_head_html }}}. And yes, it would probably be better to do this as an AMD module.

<script>
    (function () {

        /* wait until RequireJS is on the page */
        function whenReq(cb){
            if (window.requirejs) { cb(); }
            else { setTimeout(function () { whenReq(cb); }, 10); }
        }

        whenReq(function () {

            /* preserve any existing onResourceLoad handler */
            const prevHandler = requirejs.onResourceLoad || function () {};

            requirejs.onResourceLoad = function (context, map) {

                /* call earlier handler first (if any) */
                prevHandler.apply(this, arguments);

                if (map.name !== 'core_message/message_drawer_view_overview') { return; }

                const View = context.defined[map.name];
                if (!View || View.__guarded) { return; }     /* already wrapped */

                const $    = context.defined['jquery'];
                const orig = View.show;

                View.show = function (namespace, header, body) {

                  /* if header/body are already valid, run as normal */
                  if (header && header.length && body && body.length) {
                      return orig.apply(this, arguments);
                  }

                  /* try to discover header/body inside this namespace root */
                  try {
                      const $root = $('#message-drawer-' + namespace);

                      const $header = $root
                          .find('[data-region="header-container"]')
                          .find('[data-region="view-overview"]');

                      const $body   = $root
                          .find('[data-region="body-container"]')
                          .find('[data-region="view-overview"]');

                      if ($header.length && $body.length) {
                          /* call the real show() with the freshly-found nodes */
                          console.log('message drawer route repaired');
                          return orig.call(this, namespace, $header, $body);
                      }

                  } catch (e) {
                      /* fall through to no-op below if anything goes wrong */
                      console.warn('ViewOverview auto-repair failed', e);
                  }

                  /* final fallback: skip call, means still broke tho */
                  return $.Deferred().resolve().promise();
                };

                View.__guarded = true;
            };
        });
    })();
    </script>