Set user preference(s) with javascript

Set user preference(s) with javascript

by Julien Chambon -
Number of replies: 8

Hey there,

I'm trying to get past the use of the use of M.util.set_user_preference() through javascript but i'm getting an error wich i can't wrap my head around.

Up until now i used the function like this : 

M.util.set_user_preference('theme_celene4boost_mode', 'dark');

Which, up to moodle 4.1 worked fine. 

So, in my attempt to update it, i declare my function likewise :

//on top of the script
import {setUserPreference} from 'core_user/repository';

//inside my function

setUserPreference('theme_celene4boost_mode', 'dark');

The function is recognized but, for some strange reason it always results into this error in console : Uncaught (in promise) Error: Invalid parameter value detected (Invalid preference 'theme_celene4boost_mode')

The rest of the script works like a charm and the error ain't blocking anything, but i can't save the user preference none the less.

I get the feeling the error should be self explanatory in itself but i can't seem to understand. Since it's a preference and since it's not supposed to already exists, it shouldn't be a problem. The only thing i may think is that i pass a string for both the parameters... But if not that, what type should i pass?

I'd love to have an opinion, (and revere anyone who could come up with an explanation slash solution ^^), on this matter.

Average of ratings: -
In reply to Julien Chambon

Re: Set user preference(s) with javascript

by Davo Smith -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
Did you call: user_preference_allow_ajax_update('theme_celene4boost_mode', PARAM_ALPHA); somewhere in the code that set up the page in question?
 
Without that, Moodle won't allow you to set the preference via Javascript (it's a mechanism to prevent Javascript from being able to store arbitrary values into the user preferences).
Average of ratings:Useful (1)
In reply to Davo Smith

Re: Set user preference(s) with javascript

by Julien Chambon -
I must admit i didn't. But isn't it deprecated since 4.3 ? (i'm on 4.4).
Do i still have to use it then ?
 
(thanks for the quick reply btw)
In reply to Julien Chambon

Re: Set user preference(s) with javascript

by Julien Chambon -
Edit : I reinstated the previous user_preference_allow_ajax_update('theme_celene4boost_mode', PARAM_ALPHA); in my code and it, indeed, triggers a deprecated warning on my page, (which i can live with), but also completely breaks the js code ><
 
EDIT2 :
Ok, my bad, i had to do a permission callback like in the boost theme!
In reply to Julien Chambon

Re: Set user preference(s) with javascript

by Davo Smith -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
OK - I had an older copy of Moodle in front of me (and haven't messed around with user preferences for a while), so wasn't aware of the deprecation.

Sounds like you managed to figure out the answer anyway (and it's been a good prompt to get me to have a quick look at how it is handled in recent Moodle code).

Unfortunately, the API documentation ( https://moodledev.io/docs/apis/core/preference ) currently only seems to cover what is needed directly in the PHP code, not how to set preferences via Javascript.
 
In case anyone else is looking - theme_boost has a function theme_boost_user_preferences(), which defines the preferences that can be updated via JavaScript (and the permissions checks needed to do so).
In reply to Julien Chambon

Re: Set user preference(s) with javascript

by Ashish Pondit -

I dont know how to use the permission callback. Can you help?

I am having permission issue.

You are not allowed to change the preference theme_customtheme_status for user 2

In reply to Ashish Pondit

Re: Set user preference(s) with javascript

by Julien Chambon -
Is it a preference for your own user or for another ? I don't think you should be able to do it for another user unless you have sufficient permission, (and reason to do so).
Otherwise, the work around isn't quite difficult. I more or less did like it was done on the boost theme :

On my lib.php file i added a callback function :
<?=
function theme_celene4boost_user_preferences(): array {
    return [
        'theme_celene4boost_mode' => [
            'type' => PARAM_ALPHA,
            'null' => NULL_NOT_ALLOWED,
            'default' => false,
            'permissioncallback' => [core_user::class, 'is_current_user'],
        ]
    ];
}

I removed those calls on drawer.php :

<?=
// user_preference_allow_ajax_update('theme_celene4boost_mode', PARAM_ALPHA);
// $this->user->ajax_updatable_user_prefs["theme_celene4boost_mode"] = PARAM_TEXT;
// user_preference_allow_ajax_update("theme_celene4boost_mode", PARAM_ALPHA);

Finally on the JS file where i want to initialize different option such as dark mode :

import {setUserPreference} from 'core_user/repository';

const letThereBeLight = (e) =>{
    e.preventDefault();
    let userPref = (UserRepository)=>{UserRepository.getUserPreferences()};
    console.log(userPref);
    const navbar = document.getElementsByClassName('navbar-light');
    const htmlElement = document.getElementsByTagName("html")[0];

    let prefValue;
    const preference = "theme_celene4boost_mode";

    if (htmlElement.classList.contains('dark')) {
        htmlElement.classList.remove('dark');
        for (let i = 0; i < navbar.length; i++) {
            if (navbar[i] && navbar[i].classList.contains('bg-dark')) {
                navbar[i].classList.remove('bg-dark');
            }
            navbar[i].classList.add('bg-white');
        }
        prefValue="";
    } else {
        htmlElement.classList.add('dark');
        for (let i = 0; i < navbar.length; i++) {
            if (navbar[i] && !navbar[i].classList.contains('bg-dark')) {
                if (navbar[i].classList.contains('bg-white')) {
                    navbar[i].classList.remove('bg-white');
                }
                navbar[i].classList.add('bg-dark');
            }
        }
        prefValue = "dark";
    }
    return setUserPreference(preference, prefValue);
};
Average of ratings:Useful (1)
In reply to Julien Chambon

Re: Set user preference(s) with javascript

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
Note that M.util.set_user_preference is old and deprecated.

These days you should use the core_user/repository JS module:

import {setUserPreference} from 'core_user/repository';

setUserPreference('preference_name', status);

(Bear in mind that is an async function.)
Average of ratings:Useful (1)