1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** All rights reserved.
|
---|
5 | ** Contact: Nokia Corporation ([email protected])
|
---|
6 | **
|
---|
7 | ** This file is part of the documentation of the Qt Toolkit.
|
---|
8 | **
|
---|
9 | ** $QT_BEGIN_LICENSE:FDL$
|
---|
10 | ** Commercial Usage
|
---|
11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
12 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
13 | ** Software or, alternatively, in accordance with the terms contained in a
|
---|
14 | ** written agreement between you and Nokia.
|
---|
15 | **
|
---|
16 | ** GNU Free Documentation License
|
---|
17 | ** Alternatively, this file may be used under the terms of the GNU Free
|
---|
18 | ** Documentation License version 1.3 as published by the Free Software
|
---|
19 | ** Foundation and appearing in the file included in the packaging of this
|
---|
20 | ** file.
|
---|
21 | **
|
---|
22 | ** If you have questions regarding the use of this file, please contact
|
---|
23 | ** Nokia at [email protected].
|
---|
24 | ** $QT_END_LICENSE$
|
---|
25 | **
|
---|
26 | ****************************************************************************/
|
---|
27 |
|
---|
28 | /*!
|
---|
29 | \page qdeclarativejavascript.html
|
---|
30 | \title Integrating JavaScript
|
---|
31 |
|
---|
32 | QML encourages building UIs declaratively, using \l {Property Binding} and the
|
---|
33 | composition of existing \l {QML Elements}. To allow the implementation of more
|
---|
34 | advanced behavior, QML integrates tightly with imperative JavaScript code.
|
---|
35 |
|
---|
36 | The JavaScript environment provided by QML is stricter than that in a web browser.
|
---|
37 | In QML you cannot add, or modify, members of the JavaScript global object. It
|
---|
38 | is possible to do this accidentally by using a variable without declaring it. In
|
---|
39 | QML this will throw an exception, so all local variables should be explicitly
|
---|
40 | declared.
|
---|
41 |
|
---|
42 | In addition to the standard JavaScript properties, the \l {QML Global Object}
|
---|
43 | includes a number of helper methods that simplify building UIs and interacting
|
---|
44 | with the QML environment.
|
---|
45 |
|
---|
46 | \section1 Inline JavaScript
|
---|
47 |
|
---|
48 | Small JavaScript functions can be written inline with other QML declarations.
|
---|
49 | These inline functions are added as methods to the QML element that contains
|
---|
50 | them.
|
---|
51 |
|
---|
52 | \code
|
---|
53 | Item {
|
---|
54 | function factorial(a) {
|
---|
55 | a = parseInt(a);
|
---|
56 | if (a <= 0)
|
---|
57 | return 1;
|
---|
58 | else
|
---|
59 | return a * factorial(a - 1);
|
---|
60 | }
|
---|
61 |
|
---|
62 | MouseArea {
|
---|
63 | anchors.fill: parent
|
---|
64 | onClicked: console.log(factorial(10))
|
---|
65 | }
|
---|
66 | }
|
---|
67 | \endcode
|
---|
68 |
|
---|
69 | As methods, inline functions on the root element in a QML component can be
|
---|
70 | invoked by callers outside the component. If this is not desired, the method
|
---|
71 | can be added to a non-root element or, preferably, written in an external
|
---|
72 | JavaScript file.
|
---|
73 |
|
---|
74 | \section1 Separate JavaScript files
|
---|
75 |
|
---|
76 | Large blocks of JavaScript should be written in separate files. These files
|
---|
77 | can be imported into QML files using an \c import statement, in the same way
|
---|
78 | that \l {Modules}{modules} are imported.
|
---|
79 |
|
---|
80 | For example, the \c {factorial()} method in the above example for \l {Inline JavaScript}
|
---|
81 | could be moved into an external file named \c factorial.js, and accessed like this:
|
---|
82 |
|
---|
83 | \code
|
---|
84 | import "factorial.js" as MathFunctions
|
---|
85 | Item {
|
---|
86 | MouseArea {
|
---|
87 | anchors.fill: parent
|
---|
88 | onClicked: console.log(MathFunctions.factorial(10))
|
---|
89 | }
|
---|
90 | }
|
---|
91 | \endcode
|
---|
92 |
|
---|
93 | Both relative and absolute JavaScript URLs can be imported. In the case of a
|
---|
94 | relative URL, the location is resolved relative to the location of the
|
---|
95 | \l {QML Document} that contains the import. If the script file is not accessible,
|
---|
96 | an error will occur. If the JavaScript needs to be fetched from a network
|
---|
97 | resource, the component's \l {QDeclarativeComponent::status()}{status} is set to
|
---|
98 | "Loading" until the script has been downloaded.
|
---|
99 |
|
---|
100 | Imported JavaScript files are always qualified using the "as" keyword. The
|
---|
101 | qualifier for JavaScript files must be unique, so there is always a one-to-one
|
---|
102 | mapping between qualifiers and JavaScript files. (This also means qualifiers cannot
|
---|
103 | be named the same as built-in JavaScript objects such as \c Date and \c Math).
|
---|
104 |
|
---|
105 |
|
---|
106 | \section2 Code-Behind Implementation Files
|
---|
107 |
|
---|
108 | Most JavaScript files imported into a QML file are stateful, logic implementations
|
---|
109 | for the QML file importing them. In these cases, for QML component instances to
|
---|
110 | behave correctly each instance requires a separate copy of the JavaScript objects
|
---|
111 | and state.
|
---|
112 |
|
---|
113 | The default behavior when importing JavaScript files is to provide a unique, isolated
|
---|
114 | copy for each QML component instance. The code runs in the same scope as the QML
|
---|
115 | component instance and consequently can can access and manipulate the objects and
|
---|
116 | properties declared.
|
---|
117 |
|
---|
118 | \section2 Stateless JavaScript libraries
|
---|
119 |
|
---|
120 | Some JavaScript files act more like libraries - they provide a set of stateless
|
---|
121 | helper functions that take input and compute output, but never manipulate QML
|
---|
122 | component instances directly.
|
---|
123 |
|
---|
124 | As it would be wasteful for each QML component instance to have a unique copy of
|
---|
125 | these libraries, the JavaScript programmer can indicate a particular file is a
|
---|
126 | stateless library through the use of a pragma, as shown in the following example.
|
---|
127 |
|
---|
128 | \code
|
---|
129 | // factorial.js
|
---|
130 | .pragma library
|
---|
131 |
|
---|
132 | function factorial(a) {
|
---|
133 | a = parseInt(a);
|
---|
134 | if (a <= 0)
|
---|
135 | return 1;
|
---|
136 | else
|
---|
137 | return a * factorial(a - 1);
|
---|
138 | }
|
---|
139 | \endcode
|
---|
140 |
|
---|
141 | The pragma declaration must appear before any JavaScript code excluding comments.
|
---|
142 |
|
---|
143 | As they are shared, stateless library files cannot access QML component instance
|
---|
144 | objects or properties directly, although QML values can be passed as function
|
---|
145 | parameters.
|
---|
146 |
|
---|
147 |
|
---|
148 | \section2 Importing One JavaScript File From Another
|
---|
149 |
|
---|
150 | If a JavaScript file needs to use functions defined inside another JavaScript file,
|
---|
151 | the other file can be imported using the \l {QML:Qt::include()}{Qt.include()}
|
---|
152 | function. This imports all functions from the other file into the current file's
|
---|
153 | namespace.
|
---|
154 |
|
---|
155 | For example, the QML code below left calls \c showCalculations() in \c script.js,
|
---|
156 | which in turn can call \c factorial() in \c factorial.js, as it has included
|
---|
157 | \c factorial.js using \l {QML:Qt::include()}{Qt.include()}.
|
---|
158 |
|
---|
159 | \table
|
---|
160 | \row
|
---|
161 | \o {1,2} \snippet doc/src/snippets/declarative/integrating-javascript/includejs/app.qml 0
|
---|
162 | \o \snippet doc/src/snippets/declarative/integrating-javascript/includejs/script.js 0
|
---|
163 | \row
|
---|
164 | \o \snippet doc/src/snippets/declarative/integrating-javascript/includejs/factorial.js 0
|
---|
165 | \endtable
|
---|
166 |
|
---|
167 | Notice that calling \l {QML:Qt::include()}{Qt.include()} imports all functions from
|
---|
168 | \c factorial.js into the \c MyScript namespace, which means the QML component can also
|
---|
169 | access \c factorial() directly as \c MyScript.factorial().
|
---|
170 |
|
---|
171 |
|
---|
172 | \section1 Running JavaScript at Startup
|
---|
173 |
|
---|
174 | It is occasionally necessary to run some imperative code at application (or
|
---|
175 | component instance) startup. While it is tempting to just include the startup
|
---|
176 | script as \e {global code} in an external script file, this can have severe limitations
|
---|
177 | as the QML environment may not have been fully established. For example, some objects
|
---|
178 | might not have been created or some \l {Property Binding}s may not have been run.
|
---|
179 | \l {QML JavaScript Restrictions} covers the exact limitations of global script code.
|
---|
180 |
|
---|
181 | The QML \l Component element provides an \e attached \c onCompleted property that
|
---|
182 | can be used to trigger the execution of script code at startup after the
|
---|
183 | QML environment has been completely established. For example:
|
---|
184 |
|
---|
185 | \code
|
---|
186 | Rectangle {
|
---|
187 | function startupFunction() {
|
---|
188 | // ... startup code
|
---|
189 | }
|
---|
190 |
|
---|
191 | Component.onCompleted: startupFunction();
|
---|
192 | }
|
---|
193 | \endcode
|
---|
194 |
|
---|
195 | Any element in a QML file - including nested elements and nested QML component
|
---|
196 | instances - can use this attached property. If there is more than one \c onCompleted()
|
---|
197 | handler to execute at startup, they are run sequentially in an undefined order.
|
---|
198 |
|
---|
199 | Likewise, the \l {Component::onDestruction} attached property is triggered on
|
---|
200 | component destruction.
|
---|
201 |
|
---|
202 |
|
---|
203 | \section1 Property Assignment vs Property Binding
|
---|
204 |
|
---|
205 | When working with both QML and JavaScript, it is important to differentiate between
|
---|
206 | QML \l {Property Binding} and JavaScript value assignment. In QML, a property
|
---|
207 | binding is created using the \e {property: value} syntax:
|
---|
208 |
|
---|
209 | \code
|
---|
210 | Rectangle {
|
---|
211 | width: otherItem.width
|
---|
212 | }
|
---|
213 | \endcode
|
---|
214 |
|
---|
215 | The \c width of the above \l Rectangle is updated whenever \c otherItem.width changes. On the other
|
---|
216 | hand, take the following JavaScript code snippet, that runs when the \l Rectangle is created:
|
---|
217 |
|
---|
218 | \code
|
---|
219 | Rectangle {
|
---|
220 |
|
---|
221 | Component.onCompleted: {
|
---|
222 | width = otherItem.width;
|
---|
223 | }
|
---|
224 | }
|
---|
225 | \endcode
|
---|
226 |
|
---|
227 | The \c width of this \l Rectangle is \e assigned the value of \c otherItem.width using the
|
---|
228 | \e {property = value} syntax in JavaScript. Unlike the QML \e {property: value} syntax, this
|
---|
229 | does not invoke QML property binding; the \c rectangle.width property is set to the value
|
---|
230 | of \c otherItem.width at the time of the assignment and will not be updated if that value
|
---|
231 | changes.
|
---|
232 |
|
---|
233 | See \l {Property Binding} for more information.
|
---|
234 |
|
---|
235 |
|
---|
236 | \section1 Receiving QML Signals in JavaScript
|
---|
237 |
|
---|
238 | To receive a QML signal, use the signal's \c connect() method to connect it to a JavaScript
|
---|
239 | function.
|
---|
240 |
|
---|
241 | For example, the following code connects the MouseArea \c clicked signal to the \c jsFunction()
|
---|
242 | in \c script.js:
|
---|
243 |
|
---|
244 | \table
|
---|
245 | \row
|
---|
246 | \o \snippet doc/src/snippets/declarative/integrating-javascript/connectjs.qml 0
|
---|
247 | \o \snippet doc/src/snippets/declarative/integrating-javascript/script.js 0
|
---|
248 | \endtable
|
---|
249 |
|
---|
250 | The \c jsFunction() will now be called whenever MouseArea's \c clicked signal is emitted.
|
---|
251 |
|
---|
252 | See \l {Connecting signals to methods and other signals} for more information.
|
---|
253 |
|
---|
254 |
|
---|
255 | \section1 QML JavaScript Restrictions
|
---|
256 |
|
---|
257 | QML executes standard JavaScript code, with the following restrictions:
|
---|
258 |
|
---|
259 | \list
|
---|
|
---|