Unable to assign QJSValue to QString
-
In my example application (see below) consisting of a main.qml and a simple WorkerScript re I run into the exception
Unable to assign QJSValue to QString
in the linetext: listview.model.get(index).title2
I also tried usingtitle2()
but this resulted in
TypeError: Property 'title2' of object ModelObject(0x7faa22cc83c0) is not a function
Is this caused by my lack of Javascript knowledge or is this a limitation of the QML/JS interface?
My main.qml is
import QtQuick 2.3 import QtQuick.Window 2.2 Window { visible: true width: 600 height: 360 ListView { id: listview anchors.fill: parent model: ListModel { id: channelList_model } delegate: Text { text: listview.model.get(index).title2 } } Component.onCompleted: { var msg = {'model': channelList_model}; worker.sendMessage(msg); } WorkerScript { id: worker source: "getObjects.js" } }
and my getObjects.js file looks like
function SomeObject(title){ this.title = title this.title2 = function() {return "another title";}; } WorkerScript.onMessage = function(msg) { var someObject = new SomeObject("SomeTitle") msg.model.append(someObject) msg.model.sync() }
-
I experimented a bit more and the issue is not related to WorkerScript but somehow seems to be related to ListView.
Below is one working and one not-working example.
Can somebody explain this to me?The following main.qml works just fine
import QtQuick 2.3 import QtQuick.Window 2.2 Window { visible: true width: 600 height: 360 property var someObject : makeSomeObject("SomeTitle") function makeSomeObject(title){ var obj = { title: title, title2: function() {return "another title";} }; return obj; } Text { text: someObject.title2() } }
while this one, using a ListView, results in the two errors I reported earlier
import QtQuick 2.3 import QtQuick.Window 2.2 Window { visible: true width: 600 height: 360 property var someObject : makeSomeObject("SomeTitle") function makeSomeObject(title){ var obj = { title: title, title2: function() {return "another title";} }; return obj; } ListView { anchors.fill: parent model: ListModel {id: list_model} delegate: Text {text: list_model.get(index).title2} } Component.onCompleted: { list_model.append(someObject) list_model.append(someObject) } }
-
Both should give you same problem. Here it is treated like function someObject.title2(). You should call it like someObject.title2. It should end up in same problem.
Instead of anonymous function I made it like the following and it works fine.
function callme() { return "another title" } var obj = { Title: Title, Title2 : callme() //Title2: function () {return "anotherTitle"; }
-
@dheerendra Thanks for your input.
This indeed works but there is a fundamental difference.In your solution, the function is evaluated when the object is created.
While I would like to only call the function when needed (ie when used in a ListView delegate)Suppose the model contains 100 objects whereof only 5 are visible: your solution will evaluate the function 100 times while I would like to have only 5 calls.
-
Confused. Your View is driven by the model. You need build model before you start displaying. So your function is called as many elements exist in the model ? Your function is called 100 times ?
-
@dheerendra When returning an object with
title2: function() {return "another title";}
, the function is created but not evaluated. So the model will contain 100 objects with a function.
The delegates are only created for the visible elements in the ListView and hence the delegateText {text: list_model.get(index).title2()}
is only created 5 times and hence also the call to title2() is only called 5 times.Does this make sense?
-
import QtQuick 2.3 import QtQuick.Window 2.2 Window { visible: true width: 600 height: 360 property var someObject : makeSomeObject("SomeTitle") function makeSomeObject(title){ var obj = { title: title, title2: Qt.binding( function() {return "another title";} ) }; return obj; } ListView { anchors.fill: parent model: ListModel {id: list_model} delegate: Text {text: list_model.get(index).title2} } Component.onCompleted: { list_model.append(someObject) list_model.append(someObject) } }
-
@Hamed.Masafi said:
title2: Qt.binding( function() {return "another title";} )
Thanks for the suggestion but this doesn't seem to work (at least not on my side). Does this work in your environment?
-
Yes and No.
This is an example. Qt.binding method will bind a value (not a literal) to object.
Binding will not work on this case else "another title" act as object, function, variable, ...
for example:title2: Qt.binding( function() {return another_object.title;} )
will works fine.
Another solutions is that get title (if features change is not needed) and pass it to title2, like this:var t2 = some_value_from_some_where; ... title2: t2
-
@Hamed.Masafi I see your point. However, the attempt below still fails.
The text in the Text element is shown correctly so there the title2() evaluates correctly (it also displays correctly when using a literal and/or when using no binding)
However, as the example below illustrates, when using the same objects through a model in ListView.delegate, I still get the same errors as reported initially.Your second proposal indeed works (and is similar to the proposal of dheerendra above). However, this implies that the function gets evaluated for every item in the model while I would like to only evaluate the function for every visible item (=> when used in the delegate)
import QtQuick 2.3 import QtQuick.Window 2.2 Window { visible: true width: 600 height: 360 property var someObject : makeSomeObject("SomeTitle1") function makeSomeObject(title){ var obj = { title: title, title2: Qt.binding (function() {return someObject.title}) }; return obj; } Text{ anchors.fill: parent text: someObject.title2() } ListView { anchors.fill: parent model: ListModel {id: list_model} delegate: Text {text: list_model.get(index).title2()} } Component.onCompleted: { list_model.append(makeSomeObject("SomeTitle2")) list_model.append(makeSomeObject("SomeTitle3")) } }