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 line text: listview.model.get(index).title2
    I also tried using title2() 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 delegate Text {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"))
        }
    }
    

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.