// 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
\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.

See the \l {QML Example - Dynamic Scene}{Dynamic Scene example} for a
demonstration of the concepts discussed on this page.


\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

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

*/
