Home > Mobile >  In QML, could a component property be the component itself?
In QML, could a component property be the component itself?

Time:01-19

I'm trying to assing a Component itself to one of its property, and then passing that property to a function inside an external file (import "Scripts.js" as Scripts)

The first thing that came to my mind was (in my opinion) the most obvious method:

//MyComponent.qml

Item {
    id: comp
    
    // property var target: comp
    // doesn't work either
    property var target: this

    ...

    onActiveFocusChanged: {
        // Scripts.foo(this)
        // and Scripts.foo(tf)
        // don't work either
        if(this.activeFocus) {
            Scripts.foo(target)
        }
    }
}

But that doesn't work (the window crashes after giving activeFocus to the Component).

So, I assigned undefined to the target as default:

...
property var target: undefined
...

and then assigned the Component itself when declared:

MyComponent {
    id: myComponent
    ...
    target: this
    // target: myComponent
    // also works
    ...
}

When the activeFocus is triggered, everything works fine. Can someone tell me why / what I'm doing wrong?

It's impossible to assing to a component property the component itself?

And why it's not impossible to do this after declared?

CodePudding user response:

As folibis already commented you should use ids instead of this keyword. Have a look at the following SO post.

import QtQuick

Window {
    id: root
    width: 800
    height: 600
    visible: true
    title: qsTr("Hello Component")

    function foo(parameter) { console.log(parameter) }

    component MyComponent : Item {
        id: component

        property var target: component

        Component.onCompleted: {
            root.foo(component.target)
            root.foo(component)
        }
    }

    MyComponent {}
    MyComponent { target: root }
}

This works without an issue.

import QtQuick

Window {
    id: root
    width: 800
    height: 600
    visible: true
    title: qsTr("Hello Component")

    function foo(parameter) { console.log(parameter) }

    component MyComponent : Item {
        id: component

        property var target: component

        onActiveFocusChanged: {
            if(component.activeFocus)
                root.foo(component.target)
        }
    }

    MyComponent { id: test }

    Component.onCompleted: test.forceActiveFocus()
}

CodePudding user response:

The this keyword has special meaning in Javascript and can change it's meaning depending on context. Since you declared it as target: this you made it property bind so that every change to this will trigger a new value in target. To work around that problem, you can ensure that you capture this exactly once with:

// MyComponent.qml
import QtQuick
import QtQuick.Controls

Item {
    property Item target
    Component.onCompleted: target = this
}

Alternatively, if you want to keep your code clean of imperative code, you can make use of parent in the following way:

// MyComponent.qml
import QtQuick
import QtQuick.Controls

Item {
    readonly property alias target: internal.target
    Item {
        id: internal
        property Item target: parent
    }
}

In the above, internal is clearly a subitem of Item and therefore, there can only be one meaning for parent which is your original item itself.

  • Related