You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

gwt-javascript.asciidoc 8.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. ---
  2. title: Integrating JavaScript Components and Extensions
  3. order: 13
  4. layout: page
  5. ---
  6. [[gwt.javascript]]
  7. = Integrating JavaScript Components and Extensions
  8. ((("JavaScript integration", id="term.gwt.javascript", range="startofrange")))
  9. Vaadin allows simplified integration of pure JavaScript components, as well as
  10. component and UI extensions. The JavaScript connector code is published from the
  11. server-side. As the JavaScript integration does not involve GWT programming, no
  12. widget set compilation is needed.
  13. [[gwt.javascript.example]]
  14. == Example JavaScript Library
  15. There are many kinds of component libraries for JavaScript. In the following, we
  16. present a simple library that provides one object-oriented JavaScript component.
  17. We use this example later to show how to integrate it with a server-side Vaadin
  18. component.
  19. The example library includes a single [classname]#MyComponent# component,
  20. defined in [filename]#mylibrary.js#.
  21. [source,javascript]
  22. ----
  23. // Define the namespace
  24. var mylibrary = mylibrary || {};
  25. mylibrary.MyComponent = function (element) {
  26. element.innerHTML =
  27. "<div class='caption'>Hello, world!</div>" +
  28. "<div class='textinput'>Enter a value: " +
  29. "<input type='text' name='value'/>" +
  30. "<input type='button' value='Click'/>" +
  31. "</div>";
  32. // Style it
  33. element.style.border = "thin solid red";
  34. element.style.display = "inline-block";
  35. // Getter and setter for the value property
  36. this.getValue = function () {
  37. return element.
  38. getElementsByTagName("input")[0].value;
  39. };
  40. this.setValue = function (value) {
  41. element.getElementsByTagName("input")[0].value =
  42. value;
  43. };
  44. // Default implementation of the click handler
  45. this.click = function () {
  46. alert("Error: Must implement click() method");
  47. };
  48. // Set up button click
  49. var button = element.getElementsByTagName("input")[1];
  50. var self = this; // Can't use this inside the function
  51. button.onclick = function () {
  52. self.click();
  53. };
  54. };
  55. ----
  56. When used in an HTML page, the library would be included with the following
  57. definition:
  58. [source,html]
  59. ----
  60. <script type="text/javascript"
  61. src="mylibrary.js"></script>
  62. ----
  63. You could then use it anywhere in the HTML document as follows:
  64. [source,html]
  65. ----
  66. <!-- Placeholder for the component -->
  67. <div id="foo"></div>
  68. <!-- Create the component and bind it to the placeholder -->
  69. <script type="text/javascript">
  70. window.foo = new mylibrary.MyComponent(
  71. document.getElementById("foo"));
  72. window.foo.click = function () {
  73. alert("Value is " + this.getValue());
  74. }
  75. </script>
  76. ----
  77. [[figure.gwt.javascript.example]]
  78. .A JavaScript Component Example
  79. image::img/javascript-component.png[]
  80. You could interact with the component with JavaScript for example as follows:
  81. [source,html]
  82. ----
  83. <a href="javascript:foo.setValue('New value')">Click here</a>
  84. ----
  85. [[gwt.javascript.server-side]]
  86. == A Server-Side API for a JavaScript Component
  87. To begin integrating such a JavaScript component, you would need to sketch a bit
  88. how it would be used from a server-side Vaadin application. The component should
  89. support writing the value as well as listening for changes to it.
  90. [source,java]
  91. ----
  92. final MyComponent mycomponent = new MyComponent();
  93. // Set the value from server-side
  94. mycomponent.setValue("Server-side value");
  95. // Process a value input by the user from the client-side
  96. mycomponent.addValueChangeListener(
  97. new MyComponent.ValueChangeListener() {
  98. @Override
  99. public void valueChange() {
  100. Notification.show("Value: " + mycomponent.getValue());
  101. }
  102. });
  103. layout.addComponent(mycomponent);
  104. ----
  105. [[gwt.javascript.server-side.component]]
  106. === Basic Server-Side Component
  107. A JavaScript component extends the [classname]#AbstractJavaScriptComponent#,
  108. which handles the shared state and RPC for the component.
  109. [source,java]
  110. ----
  111. package com.vaadin.book.examples.client.js;
  112. @JavaScript({"mylibrary.js", "mycomponent-connector.js"})
  113. public class MyComponent extends AbstractJavaScriptComponent {
  114. public interface ValueChangeListener extends Serializable {
  115. void valueChange();
  116. }
  117. ArrayList<ValueChangeListener> listeners =
  118. new ArrayList<ValueChangeListener>();
  119. public void addValueChangeListener(
  120. ValueChangeListener listener) {
  121. listeners.add(listener);
  122. }
  123. public void setValue(String value) {
  124. getState().value = value;
  125. }
  126. public String getValue() {
  127. return getState().value;
  128. }
  129. @Override
  130. protected MyComponentState getState() {
  131. return (MyComponentState) super.getState();
  132. }
  133. }
  134. ----
  135. Notice later when creating the JavaScript connector that its name must match the
  136. package name of this server-side class.
  137. The shared state of the component is as follows:
  138. [source,java]
  139. ----
  140. public class MyComponentState extends JavaScriptComponentState {
  141. public String value;
  142. }
  143. ----
  144. If the member variables are private, you need to have public setters and getters
  145. for them, which you can use in the component.
  146. [[gwt.javascript.connector]]
  147. == Defining a JavaScript Connector
  148. A JavaScript connector is a function that initializes the JavaScript component
  149. and handles communication between the server-side and the JavaScript code.
  150. //TODO Clarify - code?
  151. A connector is defined as a connector initializer function that is added to the
  152. [literal]#++window++# object. The name of the function must match the
  153. server-side class name, with the full package path. Instead of the Java dot
  154. notation for the package name, underscores need to be used as separators.
  155. The Vaadin client-side framework adds a number of methods to the connector
  156. function. The [methodname]#this.getElement()# method returns the HTML DOM
  157. element of the component. The [methodname]#this.getState()# returns a shared
  158. state object with the current state as synchronized from the server-side.
  159. [source,javascript]
  160. ----
  161. window.com_vaadin_book_examples_client_js_MyComponent =
  162. function() {
  163. // Create the component
  164. var mycomponent =
  165. new mylibrary.MyComponent(this.getElement());
  166. // Handle changes from the server-side
  167. this.onStateChange = function() {
  168. mycomponent.setValue(this.getState().value);
  169. };
  170. // Pass user interaction to the server-side
  171. var self = this;
  172. mycomponent.click = function() {
  173. self.onClick(mycomponent.getValue());
  174. };
  175. };
  176. ----
  177. In the above example, we pass user interaction using the JavaScript RPC
  178. mechanism, as described in the next section.
  179. [[gwt.javascript.rpc]]
  180. == RPC from JavaScript to Server-Side
  181. User interaction with the JavaScript component has to be passed to the
  182. server-side using an RPC (Remote Procedure Call) mechanism. The JavaScript RPC
  183. mechanism is almost equal to regular client-side widgets, as described in
  184. <<gwt-rpc#gwt.rpc,"RPC Calls Between Client- and
  185. Server-Side">>.
  186. [[gwt.javascript.rpc.handling]]
  187. === Handling RPC Calls on the Server-Side
  188. Let us begin with the RPC function registration on the server-side. RPC calls
  189. are handled on the server-side in function handlers that implement the
  190. [interfacename]#JavaScriptFunction# interface. A server-side function handler is
  191. registered with the [methodname]#addFunction()# method in
  192. [classname]#AbstractJavaScriptComponent#. The server-side registration actually
  193. defines a JavaScript method that is available in the client-side connector
  194. object.
  195. Continuing from the server-side [classname]#MyComponent# example we defined
  196. earlier, we add a constructor to it that registers the function.
  197. [source,java]
  198. ----
  199. public MyComponent() {
  200. addFunction("onClick", new JavaScriptFunction() {
  201. @Override
  202. public void call(JsonArray arguments) {
  203. getState().setValue(arguments.getString(0));
  204. for (ValueChangeListener listener: listeners)
  205. listener.valueChange();
  206. }
  207. });
  208. }
  209. ----
  210. [[gwt.javascript.rpc.calling]]
  211. === Making an RPC Call from JavaScript
  212. An RPC call is made simply by calling the RPC method in the connector. In the
  213. constructor function of the JavaScript connector, you could write as follows
  214. (the complete connector code was given earlier):
  215. [source,javascript]
  216. ----
  217. window.com_vaadin_book_examples_gwt_js_MyComponent =
  218. function() {
  219. ...
  220. var connector = this;
  221. mycomponent.click = function() {
  222. connector.onClick(mycomponent.getValue());
  223. };
  224. };
  225. ----
  226. Here, the [literal]#++mycomponent.click++# is a function in the example
  227. JavaScript library, as described in <<gwt.javascript.example>>. The
  228. [methodname]#onClick()# is the method we defined on the server-side. We pass a
  229. simple string parameter in the call.
  230. You can pass anything that is valid in JSON notation in the parameters.
  231. (((range="endofrange", startref="term.gwt.javascript")))