JS Async Function in QML



  • I'm wondering if it is possible to use an async function in QML.
    Like this:

    async function additem(clientName){
        myListModel.append({name:clientName});
    }
    

    Instead of using this:

    function additem(clientName){
        myListModel.append({name:clientName});
    }
    

    I've tried it and I get a syntax error: Expected token:'` and couldn't find any documentation about QML supporting JavaScript "async function".
    any idea why is that? or probably if there is any other way to do async in JS which can be used in QML?

    Note: I want to append data to my ListModel and I want to see it as its progress and I don't want whole application freeze until whole data appended to the model.

    Appreciate your time.


  • Moderators

    @Bernard-Rouhi said in JS Async Function in QML:

    I don't want whole application freeze until whole data appended to the model

    when your whole application freezes by just appending a single value to the model you must have done something wrong in your implementation.
    Even when you make this function asyncronous the application would freeze once it gets added anyway.
    So whats the actual problem by calling the method directly?



  • Hi,
    you can't write 'async function' in qml.
    What you need is QML "workerScript" to do your list initialisation in separated thread.

    WorkerScript doc : http://doc.qt.io/qt-4.8/qml-workerscript.html

    LA



  • @raven-worx said in JS Async Function in QML:

    @Bernard-Rouhi said in JS Async Function in QML:

    I don't want whole application freeze until whole data appended to the model

    when your whole application freezes by just appending a single value to the model you must have done something wrong in your implementation.
    Even when you make this function asyncronous the application would freeze once it gets added anyway.
    So whats the actual problem by calling the method directly?

    Thank you for the reply,
    okay, I have a ListView

    ListView {
        id: myList
        anchors.fill: parent
        model: myList
        delegate: myDelegate
    }
    

    and in my ListModel I have ListElement that contain an Array, and that Array contains multiple ListElement, one of the data is something like this:

    ListModel
    {
        id: myList
        ListElement{
            name: "Bernard"
            card: 100256
            books:[
                {value:"025684"},
                {value:"568956"},
                {value:"879256"},
                {value:"125793"},
                {value:"486257"}]
        }
    }
    

    you might wonder why list of ListElement for books, well, it's because ListElement and ListModel doesn't support simple Array (it's not documented if any), they only mentioned string and integer. so I have to use ListElement in such way.
    however, next I want to add the books to my ComboBox's model which is under Delegate:

    Component {
        id: myDelegate
        Rectangle
            {
             id: rowID
             width: 300
             height: 40
             color: "#323232"
             border.color: "white"
             Row
             {
                 anchors.fill: parent
                 anchors.leftMargin: 10
                 anchors.rightMargin: 10
                 Text{
                     id: nameID
                     text: name
                     font.pixelSize: 12
                     width: 50
                     wrapMode: Text.WrapAnywhere
                     color: "white"
                 }
    
                 Text{
                     text: "out:"
                     font.pixelSize: 12
                     color: "white"
                 }
    
                 ComboBox{
                     id: booksID
                     height: 20
                     width: 50
                     model: books
                 }
             }
        }
    }
    

    as you can see I'm feeding the name to Text (id: nameID) but I want to add the books to ComboBox model (id: booksID) too, which it doesn't do it.

    so the easiest way that I figured out is by adding onCompleted to ComboBox under Delegate and handling it like so:

    ComboBox{
        id: booksID
        height: 20
        width: 50
        model: []
        Component.onCompleted:{
            booksID.model = update_books(books);
            function update_books(data)
            {
                var booksArray = Array();
                for (var n=0; n < data.count ;n++){
                    booksArray.push(data.get(n).value);
                }
                return booksArray;
            }
        }
    }
    

    well, I know I shouldn't do that in Delegate, cause Delegate doesn't keep them and it should be done in Model, but I couldn't find a way to feed the books to ComboBox's model and I thought of doing async function to keep the performance, but not document regarding that too.

    Hope that is clear my intention of using Async Function, but feel free to correct me if you find any process that I'm doing wrong, thanks for your time.



  • @LeLev said in JS Async Function in QML:

    Hi,
    you can't write 'async function' in qml.
    What you need is QML "workerScript" to do your list initialisation in separated thread.

    WorkerScript doc : http://doc.qt.io/qt-4.8/qml-workerscript.html

    LA

    Hi @LeLev

    Thanks for the reply, yeah, I try using that, but since it separates itself from QML Libraries and I need ListView's id to append ListElement to it, it doesn't look alike workable in my case.
    Please look at my reply to Raven-worx question, I did explain why I need the async function. hope that gives a clear idea of my question.



  • Take a look on this exemple maybe... http://doc.qt.io/qt-5/qtquick-threading-example.html

    I hope it helps you.
    LA



  • @Bernard-Rouhi I believe you should be able to assign the books to the ComboBox model using modelData.

    Like so:

    ComboBox{
    id: booksID
    model: modelData.books
    }

    Also, you can use a plain JavaScript array for a model. Works fine. That's all I ever use, for all my models — arrays of strings, arrays of objects, etc.



  • @LeLev said in JS Async Function in QML:

    Take a look on this exemple maybe... http://doc.qt.io/qt-5/qtquick-threading-example.html

    I hope it helps you.
    LA

    Thanks for the reply, I found a solution by adding textRole to ComBox like so:

    ComboBox{
        id: booksID
        height: 20
        width: 50
        model: books
        textRole: "value"
    }
    

    but still, I'm looking for asyncing my javascript function, I could think of an existing similar idea called Ajax for web development in Restful API, but I want to do the same thing in QML with javascript functions.



  • @wpurvis said in JS Async Function in QML:

    @Bernard-Rouhi I believe you should be able to assign the books to the ComboBox model using modelData.

    Like so:

    ComboBox{
    id: booksID
    model: modelData.books
    }

    Also, you can use a plain JavaScript array for a model. Works fine. That's all I ever use, for all my models — arrays of strings, arrays of objects, etc.

    Hi @wpurvis , thanks for the reply, I didn't get the modelData, you mean ListModel id?
    also again I'm looking for a way to async my javascript functions, something similar to Ajax in Restful API but in QML without Restful API of course.



  • @LeLev said in JS Async Function in QML:

    Take a look on this exemple maybe... http://doc.qt.io/qt-5/qtquick-threading-example.html

    I hope it helps you.
    LA

    Hi @LeLev , thanks for the reply, yeah, I think the solution is to handle it on multi threads, I didn't get it at first but now I go through the documentations that make lots of sense.



  • @Bernard-Rouhi said in JS Async Function in QML:

    I didn't get the modelData, you mean ListModel id?

    No, I mean modelData, as described here.
    It's an alternative way for the delegate to refer to its model data, i.e., an alternative to using named roles.
    E.g., in your example, your delegate could refer to modelData.name, modelData.card, etc., and you should be able to set the ComboBox model to modelData.books. That's assuming you wanted to just use a plain JavaScript array of book values, rather than creating a bunch of ListElement entries.


Log in to reply
 

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