πŸ‡ΊπŸ‡¦ We stand with Ukraine! πŸ‡ΊπŸ‡¦

Could not bind view model SettingsViewModel to target #settings_dialog : click@

Hello,
I'm a newbie and I spent 3 days on this problem, triying to make a button to trigger a click event and process it in __init__.py. I read the refererece for the functions and also spent a lot of time reading sources on GitHub. No success !

Here's what I'm doing :

in the jinja file (among other data controls that all work fine) :

  <div class="control-group">
    <div class="controls">
      <button class="btn" data-bind="click: test"> {{ _('Test') }} </button>
    </div>
  </div>

in the js file :

$(function () {
    function marlinmodeViewModel(parameters) {
        var self = this;

        self.test = function (data) {
            OctoPrint.simpleApiCommand("marlinmode", "testMessage");
        }
    }

    OCTOPRINT_VIEWMODELS.push({
        construct: marlinmodeViewModel,
        dependencies: ["settingsViewModel"],
        elements: ["#settings_plugin_marlinmode"]
    });
});

and in __init__.py :

# -*- coding: utf-8 -*-

from __future__ import absolute_import, unicode_literals

import octoprint.plugin
import logging
import flask


TOP_LEFT		=	0
TOP_CENTER		=	1
TOP_RIGHT		=	2
CENTER_LEFT		=	3
CENTER_CENTER	=	4
CENTER_RIGHT	=	5
BOTTOM_LEFT		=	6
BOTTOM_CENTER	=	7
BOTTOM_RIGHT	=	8


class MarlinModePlugin(octoprint.plugin.StartupPlugin,
                       octoprint.plugin.TemplatePlugin,
                       octoprint.plugin.AssetPlugin,
                       octoprint.plugin.SimpleApiPlugin,
                       octoprint.plugin.SettingsPlugin):

    def on_after_startup(self):
        self._logger.info("********************* on_after_startup() *******************")

    def get_settings_defaults(self):
        self._logger.info("******************** get_settings_defaults() *******************")
        return dict(
                        full_screen         = "true",
                        size                = 50,
                        alignment           = CENTER_CENTER,
                        viewport_opacity    = 100,
                        fgnd_color          = "#ffffff",	# white
                        fgnd_opacity        = 100,
                        bkgnd_color         = "#0000ff",	# blue
                        bkgnd_opacity       = 100,

                        spi_speed           = 8,
                        debounce_time       = 300,
                        show_at_boot        = "true",
                        dtovl_shtdn         = "true",
                        disable_HID         = "true"
        )

    def __init__(self):
        self.dummy=0

    def get_template_configs(self):
        return [
            dict(type="settings", custom_bindings=False)
        ]

    def get_api_commands(self):
        return dict(
            testMessage = []
        )

    def on_api_command(self, command, data):
        if command == "testMessage":
            self._logger.info("****************** !!!!!!!!!!!! testMessage !!!!!!!!!!!!!!!!! *******************")

    def get_assets(self):
        return dict(
            js=["js/marlinmode.js"],
        )

__plugin_name__ = "Marlin Mode"
__plugin_version__ = "1.0.0"
__plugin_description__ = "Marlin Mode service Configurator"
__plugin_pythoncompat__ = ">=2.7,<4"
__plugin_implementation__ = MarlinModePlugin()

I always get this error in the Firefox console :

Could not bind view model SettingsViewModel to target #settings_dialog : click@http://192.168.0.32/static/webassets/packed_libs.js?1fe9f29c line 131 > Function:3:58

Whatever I do.
Whith the spinning Save button of the death.

You put here:

custom_bindings as false. Then you have tried to have a custom binding, so it does not work. If you change this to true, it will work.

Chromium based browsers give more helpful/complete error messages for knockout bindings, which may be useful to debug them.

Many thanks for your quick answer !
Yes, doing this, I get the notification in the log file, but still no luck : OctoPrint wants to bind to the next control (a checkbox) that does not have events defined ! (simple data linked to config.yaml)

Here's the begining of the html/jinja file :

<!-- BEGIN : Settings page title -->
<!-- 
<h4>'Marlin UI Classic' settings</h4>
-->
<!-- END : Settings page title -->

<!-- BEGIN : form -->
<form class="form-horizontal">


  <!--
  <div class="control-group">
    <div class="controls">
      <button class="btn btn-primary"> {{ _('Test') }} </button>
    </div>
  </div>
-->


  <div class="control-group">
    <div class="controls">
      <button class="btn" data-bind="click: test"> {{ _('Test') }} </button>
    </div>
  </div>



  <ul class="nav nav-pills">

    <li class="active">
      <a data-toggle="tab" href="#appearance">{{ _('Appearance') }}</a>
    </li>

    <li>
      <a data-toggle="tab" href="system">{{ _('System') }}</a>
    </li>
  </ul>

<!-- BEGIN : TAB CONTENT -->
<div class="tab-content">

  <!-- BEGIN : PANE : APPEARANCE -->
  <div class="tab-pane active" id="appearance">

    <!-- *************************************** APPEARANCE ******************************** -->

    <!-- BEGIN : Full screen : check box -->
    <div class="control-group">
      <div class="controls">
        <label class="checkbox">
          <input  type="checkbox"
                  data-toggle="tooltip"
                  data-bind="checked: settings.plugins.marlinmode.full_screen, tooltip: {}"
                  title="{{ _('Full screen') }}" /> {{ _('Full screen') }}
        </label>
        <div class="help-block_full_sreen">{{ _('') }}</div>
      </div>
    </div>
    <!-- END : Start with Marlin UI : check box -->

I have no idea why...

I downloaded Chromium ; more information, but doesn't help meuch...

Ok, so now you are using custom bindings you can't use the settings viewmodel directly. You have to do everything through your custom viewmodel in the JavaScript file.

You have already added a dependency on the settings viewmodel, so add a reference to this at the top:

$(function () {
    function marlinmodeViewModel(parameters) {
        var self = this;

        self.settingsViewModel = parameters[0]

        self.test = function (data) {
            OctoPrint.simpleApiCommand("marlinmode", "testMessage");
        }
    }

    OCTOPRINT_VIEWMODELS.push({
        construct: marlinmodeViewModel,
        dependencies: ["settingsViewModel"],
        elements: ["#settings_plugin_marlinmode"]
    });
});

Then you can change your binding to be in this scope:

data-bind="checked: settingsViewModel.settings.plugins.marlinmode.full_screen, tooltip: {}"

Of course, you could choose a shorter name than settingsViewModel in both if you would like, I chose it to make it clear for the description.

Great !

Now works as expected. But I feel like a script kiddie...

Thanks again !