Reputation: 22346
If I have a simple Binding
object of the form:
Rectangle {
height: 400
width: 500
property var someObj: null
Binding on color {
when: someObj
value: someObj.color
}
}
Then I would expect that when someObj
is not null
, someObj
's color
property is bound to this object's color
property. What I actually get is a runtime error message:
TypeError: Cannot read property 'color' of null
Any reason why this doesn't work?
Doing the almost equivalent JavaScript expression:
color: {
if ( someObj != null ) {
return someObj.color;
} else {
return "black";
}
}
Works as expected.
Upvotes: 9
Views: 5652
Reputation: 3055
As mentioned in the comment by BaCaRoZzo, the minimal example given in the question does not work because it gives a ReferenceError: someObj is not defined
. However, after fixing this with an id
for the Rectangle
, then the example actually works despite the TypeError:
Rectangle {
id: rect
height: 400
width: 500
property var someObj: null
Binding on color {
when: rect.someObj
value: rect.someObj.color
}
}
This correctly sets the color as expected when rect.someObj
is set and contains a color
property.
The reason for the TypeError
is that the expression rect.someObj.color
is evaluated already when the Binding
is created (see QTBUG-22005).
So to prevent the TypeError
, one can simply check for rect.someObj
to be set in the value
expression of the Binding
:
Binding on color {
when: rect.someObj
value: rect.someObj ? rect.someObj.color : undefined
}
Upvotes: 2
Reputation: 379
I would do it in the following way:
import QtQuick 2.0
import QtQuick.Controls 1.4
Rectangle {
height: 400
width: 500
property var someObj
color: someObj ? someObj.color : "black"
Button {
id: buttonTest
text: "test"
onClicked: parent.someObj = test
}
Button {
id: buttonTest2
anchors.left: buttonTest.right
text: "test2"
onClicked: parent.someObj = test2
}
QtObject {
id: test
property color color: "red"
}
QtObject {
id: test2
property color color: "blue"
}
}
If someObj
is undefined the color of the rectangle is black, if someObj is defined, the Value of the color property is chosen.
Edit: I've seen to late, that that's only what mlvljr suggested in the comments, sorry.
Upvotes: 1
Reputation: 2296
The QML
syntax defines that curly braces on the right-hand-side of a property value initialization assignment denote a binding assignment. This can be confusing when initializing a var
property, as empty curly braces in JavaScript can denote either an expression block or an empty object declaration. If you wish to initialize a var
property to an empty object value, you should wrap the curly braces in parentheses.
For example:
Item {
property var first: {} // nothing = undefined
property var second: {{}} // empty expression block = undefined
property var third: ({}) // empty object
}
In the previous example, the first property is bound to an empty expression, whose result is undefined
. The second property is bound to an expression which contains a single, empty expression block ("{}")
, which similarly has an undefined
result. The third property is bound to an expression which is evaluated as an empty object declaration, and thus the property will be initialized with that empty object value.
Similarly, a colon in JavaScript can be either an object property value assignment, or a code label. Thus, initializing a var
property with an object declaration can also require parentheses:
Item {
property var first: { example: 'true' } // example is interpreted as a label
property var second: ({ example: 'true' }) // example is interpreted as a property
property var third: { 'example': 'true' } // example is interpreted as a property
Component.onCompleted: {
console.log(first.example) // prints 'undefined', as "first" was assigned a string
console.log(second.example) // prints 'true'
console.log(third.example) // prints 'true'
}
}
So the code should be as follow:
Rectangle {
height: 400
width: 500
property var someObj: ({color: ''})
Binding on color {
when: someObj.color
value: someObj.color
}
}
Upvotes: 0