################
Creating viewers
################

We will now use the data returned to us from our application server to create and start a WebViewer in our browser. You will notice that our current implementation of ``createNewViewer`` in *index.html* waits for a response from the server before simply echoing out the data it receives. We would like to now put that data to use. We will do that by performing the following steps:

#. Instantiate an HTML template to create required DOM elements for our viewer.
#. Create and start a :doc:`Communicator.WebViewer </api_ref/viewing/classes/Communicator.WebViewer>` object referencing a container we created in step 1.
#. Save the newly created WebViewer in a map so we can access it later.

Start by creating a Map to hold our WebViewers outside of the ``createNewViewer`` function:

.. code-block:: js

	const viewerMap = new Map();

Next, replace the console log statement in ``createNewViewer`` with its actual implementation:
	
.. code-block:: js

	let templateText = $("#viewer-template").html();
	$("#viewers").append(templateText.replace(/{{id}}/g, data.id));

	const rendererType = data.rendererType === "csr" ? Communicator.RendererType.Client : Communicator.RendererType.Server;

	const viewer = new Communicator.WebViewer({
	  containerId: `viewer-${data.id}`,
	  endpointUri: data.endpoint,
	  model: "helloworld",
	  rendererType: rendererType
	});

	viewer.start();

	viewerMap.set(data.id, viewer);

We first reference the template that is provided in the HTML and instantiate it by performing a string replace with the ID of our newly created viewer. We will be adding support for Server Side Rendering in a later section of the tutorial, so for now, ``data.rendererType`` will always have the value ``csr``. Next, our :doc:`Communicator.WebViewer </api_ref/viewing/classes/Communicator.WebViewer>` is created and started. The endpoint is plugged in directly from the response of our application server. We are assured that when our request to spawn an instance returns, that the application is ready to connect and no race condition at connect time will occur.  Finally, we save the WebViewer object in our Map, keyed on its Id. This will come in handy later in the tutorial when we add support for removing viewers.

.. note::
	
	In a production environment, you generally do not want to have traffic to your *ts3d_sc_server* instances going over non-standard ports. This is due to many networks restricting traffic on such ports. It is recommended to use a reverse proxy to ensure that all traffic is going over standard, trusted ports. Please refer to the Communicator documentation on this topic for additional information.

At this point, clicking the remove button will throw a JavaScript error since we have not implemented the ``removeViewer`` method yet. We will fix that in the next section.
