Importing external javascript files when using Qt resource



  • Hello all,

    I'm currently updating a project to pull the various qml files we use into a Qt resource file. This all works fine however here is the catch, I have a QML file that imports a javascript file (ex import "my.js" as MyJS). Since pulling the QML files into the resource file the application is now looking for the javascript file in the resource and can't find it.

    In this particular scenario it is not possible to just add the javascript file to the resource because it is purposely placed outside of the resource structure as it's a shared file with some other projects. I thought I could add the following:

    @viewer.rootContext()->setContextProperty("installPath", "file://" + QCoreApplication::applicationDirPath() + "/");
    @

    to my QDeclarativeView and all would be good but no such luck.

    Any suggestions?



  • This is because any relative import is relative to the baseUrl of the Component. There are a couple of ways you can make this work, but the best way is to define a module which exports the JavaScript resource directly with a qualifier, then import the type namespace / module identifier, rather than a relative import.



  • Thanks Chriadam,

    I understand that the import is relative to the base url of the component but in that case does it mean I cannot use a path like "../../location/MyJS.js" to reference a file outside of the the components base location?



  • Chriadam,

    Can you elaborate on your suggestion to define a module that exports the JavaScript resource?

    Specifically the JavaScript file I'm loading is a collection of helper methods that are to be shared with other projects, thus the reason they are independent of the main source tree for this project. The paths I'm working with are along these lines:

    @RootDir

    • SDK
      • Javascript
    • QmlApp
      • Src
        • qml@

    So the qml files in question are located in QmlApp/Src/qml and of course the shared javascript file is located in SDK/Javascript.

    Best regards,
    Chris.



  • Hi,

    It sounds exactly like you want to create a module. I assume you're using Qt5 / QtQuick2 - if not, you won't be able to do this (as JavaScript resources weren't supported in modules in Qt4.x / QtQuick1).

    In Qt5, a module is specified by a qmldir with the following format:

    @
    module ModuleName
    plugin myplugin #optional plugin specification
    MyType 1.0 MyType.qml #optional QML document defined type specification
    MyJs 1.0 myjavascript.js #optional JavaScript resource specification
    @

    If you install that module into the QML import path, you can then do:

    @
    import ModuleName 1.0

    MyType {
    Component.onCompleted: {
    MyJs.someFunction();
    }
    }
    @

    etc.

    Cheers,
    Chris.



  • Thanks Chris,

    I finally found some of this information today while trolling through many google searches. I'm currently not using Qt5 however that is the target, just waiting for the beta build to be available before making the jump.

    Some of the information I read seemed to indicate this might work with Qt 4.8.1 however thus far I haven't been successful.

    Thanks again for the assistance.
    Chris.



  • For Qt 5, the docs regarding modules are currently being updated. A new snapshot should appear soon at http://doc-snapshot.qt-project.org/5.0/qtqml-modules-topic.html (the current content is outdated) and certainly it'll be updated in the upcoming beta.

    Cheers,
    Chris.



  • Hello CLarge,

    what if you need two distinct instances of your javascript file?

    @ module ModuleName
    MyJs 1.0 myjavascript.js #optional JavaScript resource specification
    @

    @ import ModuleName 1.0

    MyType {
        Component.onCompleted: {
            MyJs1.someFunction();
            MyJs2.someOtherFunction();
        }
    }
    

    @

    Where can I indicate to QML that I would like to get two separate instance of the same script?



  • As long as the script is not a shared-context (.pragma library) script, each time you import the script it will have a unique context. To do so, you need to provide a unique qualifier (either for the script itself, if it's an out-of-module script resource import, or for the module which provides the script resource).

    eg,

    @
    import "SomeFile.js" as MyJs1
    import "SomeFile.js" as MyJs2

    MyType {
    Component.onCompleted: {
    MyJs1.someFunction();
    MyJs2.someFunction(); // evaluated in separate context to the one above
    }
    }
    @

    OR

    @
    import ModuleName 1.0 as one
    import ModuleName 1.0 as two

    MyType {
    Component.onCompleted: {
    one.MyJs.someFunction();
    two.MyJs.someFunction(); // evaluated in separate context to the one above
    }
    }
    @

    I agree that this second form is suboptimal, and it would be nice to have a way to specify what the context of an imported script should be, at import time. There is a bug open in the bug tracker (which is currently scheduled for Qt 5.1 timeframe) to address this issue.

    Cheers,
    Chris.



  • Hello Chrisadams,

    i am working for a Qt 4.8.1 project. And I need to have my javascript file stored as a module.
    I tried your second proposal, but having lowercase for the initial of your qualifiers one and two is leading to an error.
    I changed them to One and Two. Then in QtCreator, I have access to the MyJS.someFunction() autocompletion. BUT when running the application I've got an error:

    TypeError: Result of expression 'One.MyJS.someFunction' [undefined] is not an object.

    So I am still stuck!
    Bill



  • Hi,

    I thought that adding JavaScript resources to QML modules was only implemented in QtQuick2. What is the result of One.MyJS ? I would expect it to be undefined in QtQuick1, which might cause the error you're seeing (attempting to look up the property "someFunction" on One.MyJS which is [undefined]).

    When you say "I need to have my javascript file stored as a module" - is that strictly true? If you can simply deploy the js files and import them directly as a local js file import, you will avoid a lot of issues related to QtQuick1 QML module imports.

    Basically, in QtQuick1 the whole concept of a "QML module" was very fuzzy (is it a concrete set of types and resources provided by a single provider? Or is it a namespace into which types are installed (and therefore, doesn't include javascript resources)? Or is it the set of types which are installed into a namespace (which can be different to the previous definition, depending on which 3rd party plugins are available; again, this definition wouldn't include JavaScript resources)? or...). In QtQuick2, we cleaned this up a lot and made it far clearer and stricter, and gave nicer semantics to both users and module developers. But to avoid breaking existing QtQuick1 applications, I don't think many of those changes were backported to QtQuick1.

    Cheers,
    Chris.



  • Hello Chrisadams,

    I basically am working on a large project with lots of different Qt applications, each will use the exact same javaScript file. I want to find a way to deploy this JavaScript file in a unique way let's say, and using a module is the only thing I am able to think of. I don't want to rely on hard coded path. These applications must run on Linux PC as well as an embedded system, and sadly I don't know how to make the import instruction depending on the target I am currently running the applications on.
    But sadly the module option doesn't seem to work, even though it seems fine at design time, with autocompletion working alright...

    i can not use QtQuick 2 with a Qt4.8.1 release, right? Then I don't see an alternative except distributing several time the same javascript file.

    Cheers,
    Bill



  • Hi,

    Unfortunately you can't use QtQuick2 with Qt4.8.1 since QtQuick2 is part of Qt5.
    It does sound like you want to use a module, but unfortunately it sounds like the functionality you want was only added to QML modules in QtQuick2 :-(

    I think you're right, and distributing the same JavaScript file with each application, seems like the only solution for you currently. Note that you can import the same JavaScript file multiple times (providing a different qualifier each time) from within a single QML file, and each import will have its own context (as I previously mentioned) but this doesn't solve the deployment issue at all.

    Cheers,
    Chris.



  • Hey Chrisadams,
    I sadly came to the same conclusion. Fortunately our project is supposed to move to a Qt5 release soon, and then I will be able to change the whole thing to a module import, hopefully!

    Thank you,
    Regards,
    Bill


Log in to reply
 

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