¿Cuál es la forma correcta de conectar una señal a un método JavaScript?

¿Cuál es la forma correcta de conectar una señal a un método JavaScript?

En una aplicación de teléfono Ubuntu, necesito realizar cierta lógica cuando ocurre un evento. Como no quiero contaminar el QML con demasiadas líneas de JavaScript, creé una clase en un archivo externo y conecté la señal a uno de sus métodos:

Principal.qml

import QtQuick 2.0
import Ubuntu.Components 1.1
import "action.js" as ActionJs

MainView {
    objectName: "mainView"

    applicationName: "example.cos64"

    useDeprecatedToolbar: false

    width: units.gu(20)
    height: units.gu(20)

    Page {

        Button {
            id: clickMeButton

            text: "Click me"

            onClicked: {
                console.log('clicked');
            }

            Component.onCompleted: {
                var action = new ActionJs.Action();
                clickMeButton.clicked.connect(action.handleClick)
            }
        }
    }
}

acción.js

function Action() {

    this.handleClick = function() {
        console.log('handleClick');
        this.process();
    }

    this.process = function() {
        console.log('processing...')
    }
}

Funciona, pero no puedo llamar a ningún otro método desde la ranura:

Starting /usr/lib/x86_64-linux-gnu/qt5/bin/qmlscene...
qml: clicked
qml: handleClick
file:///home/co64/projects/ubuntu/Example/action.js:5: TypeError: Property 'process' of object [object Object] is not a function

¿Por qué no se reconoce el "proceso" como una función? ¿Estoy haciendo algo mal?

Respuesta1

Creo que el problema inmediato es que el contexto cambia dentro de las definiciones de funciones internas Action. El thisobjeto del interior Action.handleClick()lo es Action.handleClick, no Action.

Pero retrocedamos un poco: ¿por qué estás usando aquí el paradigma de función dentro de una función? Esto es común en el navegador Javascript, ya que no hay espacios de nombres en ese entorno. Para evitar pisotear otras funciones, falsificas un espacio de nombres creando un objeto que contenga todas tus funciones.

Sin embargo, QMLhacehacer espacios de nombres. Tenga en cuenta que tenía que hacer referencia Actiona ActionJS.Actionpartir del archivo QML. Por lo tanto, no es necesario implementar otro espacio de nombres para sus funciones; simplemente colóquelos en el nivel superior del archivo JS:

function handleClick() {
    console.log("handleClick");
    process();
}

function process() {
    console.log("processing...");
}

Luego en su archivo QML, haga

Component.onCompleted: {
    clickMeButton.clicked.connect(ActionJS.handleClick)
}

O solo

onClicked: ActionJS.handleClick()

Supongo que en realidad no necesitas un Actionobjeto para nada más que el espacio de nombres. Si lo haces, deberías aprender sobreprototipo. Quizás también quieras saber sobre.pragma library, si tiene intención de utilizar este archivo JS en varios archivos QML.

información relacionada