Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Native Development

Reply
Highlighted
New Developer
Posts: 11
Registered: ‎12-27-2012
My Device: Blackberry Dev Alpha
My Carrier: Vodafone
Accepted Solution

Q_Invokable not working with a qmlRegisterType added class

I have a problem with calling a C++ function from a Javascript in QML.

 

I created a QVariantListDataModel subclass in C++ called MovieListModel. And in this class I have a function declared as 

Q_INVOKABLE void reload(const QString& a);

 

This class is exported in c++ in the application constructor as 

qmlRegisterType<movie::MovieListModel>("me.movie", 1, 0, "MovieListModel"); 

 

And in my QML file I can create a new component with MovieListMode {}. 

 

So this all follows the example of Exposing C++ objects to QML in the C++ and QML integration sample and the MovieListModel seems to work well. 

 

Except for an issue I'm having with calling the reload function in MovieListModel in the QML javascript. 

 

Does anyone know what I'm missing? 

Developer
Posts: 1,524
Registered: ‎12-18-2012
My Device: Z30, Z10 LE, DevAlpha C, PlayBook

Re: Q_Invokable not working with a qmlRegisterType added class

Hi,

Please post the QML file. Are you specifying the id of the object?

objectId.reload('somestring')

Is there any errors in logs?

Andrey Fidrya, @zmeyc on twitter
Developer
Posts: 71
Registered: ‎09-19-2012
My Device: Z10 very soon
My Carrier: Play

Re: Q_Invokable not working with a qmlRegisterType added class

yes. you need to provide some qml's 

and why UI (QML/JS) needs to reload model ? 

New Developer
Posts: 11
Registered: ‎12-27-2012
My Device: Blackberry Dev Alpha
My Carrier: Vodafone

Re: Q_Invokable not working with a qmlRegisterType added class

[ Edited ]

Below is the QML I'm using it on. This QML is called from another QML as a component, which isn't really relevant to the issue. The Javascript reload function here calls the reload method in the C++ created MovieListModel class.

 

The reason why the MovieListModel has a reload function is because the source for the data list model comes from a remote JSON source and needs to be updated when the user presses the refresh button.

 

 

import bb.cascades 1.0
import me.movie 1.0
import com.labsquare 1.0
import "jslibs/homepagehandlers.js" as Handlers

Container {
    id: homePageList
    property string listTitle
    property string listType
    
    
    signal loadingDone()

    Label {
        text: listTitle
        textStyle.base: textStyleBoldTitle.style
    }
    ListView {
        id: movieListView
                        
        dataModel: movieListModel

        listItemComponents: [

            ListItemComponent {
                type: "item"
				Container {
				    id: movieItem

                    rightMargin: 20
                    WebImageView {
                        id: itemImage
                        scalingMethod: ScalingMethod.AspectFit
                        preferredWidth: 160
                		url: (function (){ 
                            if (ListItemData.poster_path) {
    	                        return "http://someImageurl/w342" + ListItemData.poster_path;
    	                    } else {
    	                        return "asset:///images/star.png";
    	                    }
                        })()
                    }

				}
            }
            
        ]

        // Item type-mapping
        function itemType (data, indexPath) {
            console.log('Indexpath: ' + indexPath.length);

            return 'item';    
        }
        
        attachedObjects: [
            
            MovieListModel {
                id: movieListModel
                //listType: listType
                onModelLoaded: {
                    loadingDone();
                }
            }
            
        ]
        
        layout: StackListLayout {
            orientation: LayoutOrientation.LeftToRight
            
            headerMode: ListHeaderMode.Overlay
        }
        
        onTriggered: {
            Handlers.handleTrigger(dataModel, indexPath);
        }
    }
    
    onCreationCompleted: {
        movieListModel.listType = listType
    }

    attachedObjects: [
        TextStyleDefinition {
            id: textStyleBoldTitle
            base: SystemDefaults.TextStyles.TitleText
            fontWeight: FontWeight.Bold
            color: Color.Black
        }
    ]

    function reload() {
        movieListModel.reload('boo');
    }
}

 

Developer
Posts: 71
Registered: ‎09-19-2012
My Device: Z10 very soon
My Carrier: Play

Re: Q_Invokable not working with a qmlRegisterType added class

from where reload() JS is called ? can also post qml ?
Developer
Posts: 71
Registered: ‎09-19-2012
My Device: Z10 very soon
My Carrier: Play

Re: Q_Invokable not working with a qmlRegisterType added class

If my guess is correct you should do following

 

1. move reload function to ListView


function reload() {
movieListModel.reload('boo');
}

 

2. when you call reload from ListItemComponent do following

 

onClicked: {
    movieItem.ListItem.view.reload();
}

New Developer
Posts: 11
Registered: ‎12-27-2012
My Device: Blackberry Dev Alpha
My Carrier: Vodafone

Re: Q_Invokable not working with a qmlRegisterType added class

The reload function is called from the parent QML. When I set a breakpoint in the QML's reload(), it correctly hits the movieListModel.reload() line. But the c++ code is never hit. 

 

Here is the parent QML. HomePageList is the QML component from my previous reply. 

 

import bb.cascades 1.0
import me.kahwah 1.0
import com.labsquare 1.0
import "jslibs/homepagehandlers.js" as Handlers

NavigationPane {
    id: homePagePane
    
    Page {
        id: homeTab
        
        Container {

            layout: DockLayout {
                  
            }
            
            Container {

                HomePageList {
                    id: popularList
                    
                    listTitle: 'Popular Movies'
                    listType: 'Popular'
                    
                }
                
                HomePageList {
                    listTitle: 'Now Playing'
                    listType: 'NowPlaying'
                }
                
                HomePageList {
                    listTitle: 'Upcoming Movies'
                    listType: 'Upcoming'
                }
        
            }
            
            
        }
        actions: [
            ActionItem {
                id: refresh
                title: "Refresh"
                onTriggered: {
                    popularList.reload();
                }

            }
        ]
    }
}

 

New Developer
Posts: 11
Registered: ‎12-27-2012
My Device: Blackberry Dev Alpha
My Carrier: Vodafone

Re: Q_Invokable not working with a qmlRegisterType added class

Thanks for your help. The reload function in Javascript is working fine. It's supposed to be at the root, because it is called from the parent QML. The javascript reload function gets hit just as it should. However setting a breakpoint in the MovieListModel reload method doesn't get hit at all.
Developer
Posts: 1,524
Registered: ‎12-18-2012
My Device: Z30, Z10 LE, DevAlpha C, PlayBook

Re: Q_Invokable not working with a qmlRegisterType added class

[ Edited ]

Please check that you are calling qmlRegisterType before loading the qml file in main.cpp.

Doing this in constructor may be too late.

Have you checked the device logs? There should be an error message there.


Andrey Fidrya, @zmeyc on twitter
Developer
Posts: 71
Registered: ‎09-19-2012
My Device: Z10 very soon
My Carrier: Play

Re: Q_Invokable not working with a qmlRegisterType added class

OK. Now I see the issue

 

You should move you data model from UI to some cpp class and expose data model as property. 

 

Q_PROPERTY(bb::cascades::GroupDataModel *getDataModel READ getDataModel CONSTANT);

 

in c++  setContextProperty to your class that manage data model. 

 

qml->setContextProperty("_myClass",this);

 

ListView{

 dataModel: _myClass.getDataModel

}

 

Create Q_INVOKABLE reload (QString) method in MyClass.

 

ActionItem {
   id: refresh
   title: "Refresh"
    onTriggered: {
       _myClass.reload("boo");
     }

}

 

above should work fine. I did that many times already.