Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Object.defineProperty outside a JS scope



  • Hi,

    I'm trying to add dynamically properties to Rectangle objects.

    My code works fine except one point: I'm not able to access to my new created properties outside a Javascrip scope.

    Here is my code:

    Window
    {
    	visible: true
    	width: 1300
    	height: 800
    	title: qsTr("Tests")
    
    	id: component
    
    	Column
    	{
    		spacing: 3
    		Label { text: rectA.myValue ? rectA.myValue : "value not found" } // display "value not found"
    		Label { text: rectB.myValue ? rectB.myValue : "value not found" } // display "value not found"
    		Button
    		{
    			text: "check a"
    			onClicked: console.log(rectA.myValue) // display "This is a test"
    		}
    	}
    
    	Rectangle { id: rectA }
    	Rectangle { id: rectB }
    
    	property var objects: [rectA, rectB]
    
    	Component.onCompleted:
    	{
    		objects.forEach( (o) =>
    		{
    			let obj = Object.defineProperty(o, "myValue",
    			{
    				enumerable: true,
    				configurable: true,
    				writable: true,
    				value: "This is a test"
    			})
    			console.log(o.myValue) // display "This is a test"
    		})
    	}
    }
    

    Did I make a mistake or it's impossible to dynamically add a property to an object and read it outside a JS scope ?

    Thanks a lot ! ^^



  • This is because it is not an QML property. This means when it is set - nothing changed for your binding at label text. Sad story, but since it is not an QML property, you cannot call o.myValueChanged();.
    But you can do another trick. Add another dummy property to yor rectangles:

    Rectangle { id: rectA; property string dummy: "" }
    

    Then add this property to label text:

    Label { text: (rectA.myValue ? rectA.myValue : "value not found") + rectA.dummy }
    

    Notify about value changed:

                let obj = Object.defineProperty(o, "myValue",
                {
                    enumerable: true,
                    configurable: true,
                    writable: true,
                    value: "This is a test"
                })
                o.dummyChanged();
    

    Not sure if it is a good idea. but it works. Personally, I prefer to add one var property to a Rectangle and extend it as simple JS object. But in this case you should also notify that this property changed:

        Column
        {
            spacing: 3
            Label { text: rectA.props.myValue || "value not found" }
            Label { text: rectB.props.myValue || "value not found" }
        }
    
        Rectangle { id: rectA; property var props: ({}) }
        Rectangle { id: rectB; property var props: ({}) }
    
        property var objects: [rectA, rectB]
    
        Component.onCompleted:
        {
            objects.forEach( (o) =>
            {
                o.props["myValue"] = "This is a test";
                o.propsChanged();
            })
        }
    


  • Oh, well, it's make sens. Thank you for your answer and your solution. =D


Log in to reply