Revision control
++ // Copyright (C) 2017 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
++
++ /*!
++ \page qtqml-javascript-dynamicobjectcreation.html
++ \meta {keywords} {qmltopic}
++ \title Dynamic QML Object Creation from JavaScript
++ \brief instantiating and managing QML objects from JavaScript.
++
++ QML supports the dynamic creation of objects from within JavaScript. This is
++ useful to delay instantiation of objects until necessary, thereby improving
++ application startup time. It also allows visual objects to be dynamically
++ created and added to the scene in reaction to user input or other events.
++
++ \warning Objects should not be dynamically created from untrusted sources. The
++ limitations \l{Qt Qml and JavaScript Sources}{for static QML sources} apply
++ equally to dynamic object creation.
++
++ \section1 Creating Objects Dynamically
++
++ There are two ways to create objects dynamically from JavaScript. You can
++ either call \l {QtQml::Qt::createComponent()}{Qt.createComponent()} to
++ dynamically create a \l Component object, or use \l{QtQml::Qt::createQmlObject()}
++ {Qt.createQmlObject()} to create an object from a string of QML. Creating a
++ component is better if you have an existing component defined in a QML document
++ and you want to dynamically create instances of that component. Otherwise,
++ creating an object from a string of QML is useful when the object QML itself is
++ generated at runtime.
++
++
++ \section2 Creating a Component Dynamically
++
++ To dynamically load a component defined in a QML file, call the
++ \l {QtQml::Qt::createComponent()}{Qt.createComponent()} function in the
++ \l {QmlGlobalQtObject}{Qt object}.
++ This function takes the URL of the QML file as its only argument and creates
++ a \l Component object from this URL.
++
++ Once you have a \l Component, you can call its \l {Component::createObject()}
++ {createObject()} method to create an instance of the component. This function
++ can take one or two arguments:
++ \list
++ \li The first is the parent for the new object. The parent can be a graphical
++ object (i.e. of the \l Item type) or non-graphical object (i.e. of the
++ \l QtObject or C++ QObject type). Only graphical objects with graphical
++ parent objects will be rendered to the \l {Qt Quick} visual canvas. If you wish
++ to set the parent later you can safely pass \c null to this function.
++ \li The second is optional and is a map of property-value pairs that define
++ initial any property values for the object. Property values specified by
++ this argument are applied to the object before its creation is finalized,
++ avoiding binding errors that may occur if particular properties must be
++ initialized to enable other property bindings. Additionally, there are
++ small performance benefits when compared to defining property values and
++ bindings after the object is created.
++ \endlist
++
++ Here is an example. First there is \c Sprite.qml, which defines a simple QML component:
++
++ \snippet qml/Sprite.qml 0
++
++ Our main application file, \c main.qml, imports a \c componentCreation.js
++ JavaScript file that will create \c Sprite objects:
++
++ \snippet qml/createComponent.qml 0
++
++ Here is \c componentCreation.js. Notice it checks whether the component
++ \l{Component::status}{status} is \c Component.Ready before calling
++ \l {Component::createObject()}{createObject()} in case the QML file is loaded
++ over a network and thus is not ready immediately.
++
++ \snippet qml/componentCreation.js vars
++ \codeline
++ \snippet qml/componentCreation.js func
++ \snippet qml/componentCreation.js remote
++ \snippet qml/componentCreation.js func-end
++ \codeline
++ \snippet qml/componentCreation.js finishCreation
++
++ If you are certain the QML file to be loaded is a local file, you could omit
++ the \c finishCreation() function and call \l {Component::createObject()}
++ {createObject()} immediately:
++
++ \snippet qml/componentCreation.js func
++ \snippet qml/componentCreation.js local
++ \snippet qml/componentCreation.js func-end
++
++ Notice in both instances, \l {Component::createObject()}{createObject()} is
++ called with \c appWindow passed as the parent argument, since the dynamically
++ created object is a visual (Qt Quick) object. The created object will become a
++ child of the \c appWindow object in \c main.qml, and appear in the scene.
++
++ When using files with relative paths, the path should
++ be relative to the file where \l {QtQml::Qt::createComponent()}
++ {Qt.createComponent()} is executed.
++
++ To connect signals to (or receive signals from) dynamically created objects,
++ use the signal \c connect() method. See
++ \l{Signal and Handler Event System#Connecting Signals to Methods and Signals}
++ {Connecting Signals to Methods and Signals} for more information.
++
++ It is also possible to instantiate components without blocking via the
++ \l {Component::incubateObject()}{incubateObject()} function.
++
++ \section2 Creating an Object from a String of QML
++
++ \warning Creating objects from a string of QML is extremely slow since the engine has to compile the
++ passed QML string every time you do it. Furthermore, it's very easy to produce invalid QML when
++ programmatically constructing QML code. It's much better to keep your QML components as separate
++ files and add properties and methods to customize their behavior than to produce new components by
++ string manipulation.
++
++ If the QML is not defined until runtime, you can create a QML object from
++ a string of QML using the \l{QtQml::Qt::createQmlObject()}{Qt.createQmlObject()}
++ function, as in the following example:
++
++ \snippet qml/createQmlObject.qml 0
++
++ The first argument is the string of QML to create. Just like in a new file,
++ you will need to import any types you wish to use. The second argument is the
++ parent object for the new object, and the parent argument semantics which apply
++ to components are similarly applicable for \c createQmlObject().
++ The third argument is the file path to associate with the new object; this is
++ used for error reporting.
++
++ If the string of QML imports files using relative paths, the path should be
++ relative to the file in which the parent object (the second argument to the
++ method) is defined.
++
++ \important When building static QML applications,
++ QML files are scanned to detect import dependencies. That way, all
++ necessary plugins and resources are resolved at compile time.
++ However, only explicit import statements are considered (those found at
++ the top of a QML file), and not import statements enclosed within string literals.
++ To support static builds, you therefore need to ensure that QML files
++ using \l{QtQml::Qt::createQmlObject()}{Qt.createQmlObject()},
++ explicitly contain all necessary imports at the top of the file in addition
++ to inside the string literals.
++
++ \section1 Maintaining Dynamically Created Objects
++
++ When managing dynamically created objects, you must ensure the creation context
++ outlives the created object. Otherwise, if the creation context is destroyed
++ first, the bindings and signal handlers in the dynamic object will no longer work.
++
++ The actual creation context depends on how an object is created:
++
++ \list
++ \li If \l {QtQml::Qt::createComponent()}{Qt.createComponent()} is used, the
++ creation context is the QQmlContext in which this method is called
++ \li If \l{QtQml::Qt::createQmlObject()}{Qt.createQmlObject()} is called, the
++ creation context is the context of the parent object passed to this method
++ \li If a \c {Component{}} object is defined and \l {Component::createObject()}
++ {createObject()} or \l {Component::incubateObject()}{incubateObject()} is
++ called on that object, the creation context is the context in which the
++ \c Component is defined
++ \endlist
++
++ Also, note that while dynamically created objects may be used the same as other
++ objects, they do not have an id in QML.
++
++
++ \section1 Deleting Objects Dynamically
++
++ In many user interfaces, it is sufficient to set a visual object's opacity to 0
++ or to move the visual object off the screen instead of deleting it. If you have
++ lots of dynamically created objects, however, you may receive a worthwhile
++ performance benefit if unused objects are deleted.
++
++ Note that you should never manually delete objects that were dynamically
++ created by convenience QML object factories (such as \l Loader and
++ \l Repeater). Also, you should avoid deleting objects that you did not
++ dynamically create yourself.
++
++ Items can be deleted using the \c destroy() method. This method has an optional
++ argument (which defaults to 0) that specifies the approximate delay in
++ milliseconds before the object is to be destroyed.
++
++ Here is an example. The \c application.qml creates five instances of the
++ \c SelfDestroyingRect.qml component. Each instance runs a NumberAnimation,
++ and when the animation has finished, calls \c destroy() on its root object to
++ destroy itself:
++
++ \table
++ \row
++ \li \c application.qml
++ \li \snippet qml/dynamicObjects-destroy.qml 0
++
++ \row
++ \li \c SelfDestroyingRect.qml
++ \li \snippet qml/SelfDestroyingRect.qml 0
++
++ \endtable
++
++ Alternatively, the \c application.qml could have destroyed the created object
++ by calling \c object.destroy().
++
++ Note that it is safe to call destroy() on an object within that object. Objects
++ are not destroyed the instant destroy() is called, but are cleaned up sometime
++ between the end of that script block and the next frame (unless you specified a
++ non-zero delay).
++
++ Note also that if a \c SelfDestroyingRect instance was created statically like
++ this:
++
++ \qml
++ Item {
++ SelfDestroyingRect {
++ // ...
++ }
++ }
++ \endqml
++
++ This would result in an error, since objects can only be dynamically
++ destroyed if they were dynamically created.
++
++ Objects created with \l{QtQml::Qt::createQmlObject()}{Qt.createQmlObject()}
++ can similarly be destroyed using \c destroy():
++
++ \snippet qml/createQmlObject.qml 0
++ \snippet qml/createQmlObject.qml destroy
++
++ */