What namespace gets from the .js files to .jinja2?

I'm experimenting with writing these plugins, still quite new to it.
How do I get variables from the JavaScript files into the Jinja templates?
Specifically, to a data-bind.
If there are better ways to do this, please let me know. I'm quite new to the front end of things here.

I can get the python parts of my code working fine, buttons responding and connecting how I want. When it reads a button, I can get it to put the button's state into a variable but it seems that is only loaded when the page is hard-refreshed. I did this with the double curley brackets {{plugin_pluginName_variable}}.
I'm learning about data-bind methods now as it seems this is the intended way to get things to instantly update. From the tutorial, I can get variables set in the settings tab to update with settings.settings.plugins.pluginName.variable.
As I understand it, I should be able to use (my plugin is still called HelloWorld) helloworld.js in the static folder to write a javascript method that updates onDataUpdaterPluginMessage and writes to the ko.observable variable I make. This function is running properly, as it spits out console messages as expected.
If this is the way to go, what namespace do I call in the jinja to reference this variable?

Important parts of my code:
helloworld.js:

$(function() {
    function HelloworldViewModel(parameters) {
        var self = this;
		console.log("this much is working");

		self.moreWords = ko.observable("something");

        // TODO: Implement your plugin's view model here.
		self.onDataUpdaterPluginMessage = function(plugin, data) {
			if (plugin != "helloworld") {
				return;
			}
			console.log("a message from helloworld");
			if (data == "PRESS!!") {
				self.moreWords = "press";
				console.log("thing happened");
			}

^and all the closing curleys are there too. This code is running fine.

helloworld_navbar.jinja2:

<a href="https://isitchristmas.com" data-bind="text: settings.settings.plugins.helloworld.words"></a>
<span>{{ plugin_helloworld_test }}</span>
<span data-bind="text: helloworld.moreWords"></span>

^The first two lines are working, the last one is the error. What namespace do I use?

My full code is avaialbe here on gitHub:

Thank you for any help. Or pointing to a "level 2" tutorial.

There's two ways that variables can be displayed in the UI, I'll detail them both and then explain which you should use for this situation.

First is Jinja2 template variables, these are rendered in the UI on the server-side using the double curly brackets like {{ user.name }} for example. In OctoPrint these values are collected with a get_template_vars function in your plugin. I don't recommend using these for variables that will change since the server starts - as changing them requires the whole UI to be re-rendered on the server, and OctoPrint implements heavy (pre-emptive) caching to avoid really long load times, especially on lower end hardware.

The second way is using Knockout JS to get your variables from JavaScript viewmodels to the markup rendered in the browser. This is now client side, and so by this point your Jinja templates have been rendered into the browser and can't be changed again, so forget about Jinja at this point, forget about Python. The only way you can now change anything is using HTTP or websocket communication.

The documentation for KnockoutJS is good to reference (Knockout : Introduction (knockoutjs.com)) to learn how the viewmodels work.


In order to bind your view model to the templates you need a list of container IDs here:

And you also need to remove the custom_bindings=False line from below if you want it to bind to them:

Otherwise OctoPrint will not allow you to bind the viewmodel you created in JavaScript to apply to your UI elements.

Then, the data-bind 'namespace' in the frontend will be your viewmodel. If you create a variable like self.moreWords = ko.observable("something"), then you would use data-bind="text: moreWords".

3 Likes

You are a gentleman and a scholar. Thank you very much!

2 Likes