PDA

View Full Version : NonVisualTable - simple tutorial


Mone
12-01-2006, 11:53 AM
This post illustrates how to set up a simple web application that receives data from the classic StockList Data Adapter (i.e. the one that feeds the StockListDemos (http://www.lightstreamer.com/stockListDemo.htm) and is already deployed when you install a new Lightstreamer instance) through a NonVisualTable (http://www.lightstreamer.com/docs/client_web_jsdoc/NonVisualTable.html) and appends it to a div tag.

I will show 2 basic approaches. The first one is a generic approach using group and schema names. The other one uses item and field names and so requires that a LiteralBasedProvider is used as a Metadata Adapter (or another one that handles groups and schemas in the same way - for a better understanding of group/items schema/fields take a look at getItems (http://www.lightstreamer.com/docs/adapter_java_javadoc/com/lightstreamer/interfaces/metadata/MetadataProvider.html#getItems%28java.lang.String,%20java.lang.String%29) and getSchema (http://www.lightstreamer.com/docs/adapter_java_javadoc/com/lightstreamer/interfaces/metadata/MetadataProvider.html#getSchema%28java.lang.String,%20java.lang.String,%20java.lang.String%29) methods in the javadocs - btw no server-side programming is needed to complete this tutorial).
The main client-side difference is that with the first approach, on each update, to access data we have to use item and field indexes while with the other we are free to use item and field names.
Note that a mixture of the 2 ways is possible (ie use group name and field names).

Each application will consinst of one single HTML file.

First of all we have to put Lightstreamer Web Client's js files in the head section of the page. Note that library files are referenced as "/LS/file.js". This reflects our way to deploy a web application on a web server. We usually put a folder named "LS" - containing our web client lib - in the root of the web server. This way we can deploy several applications using one single web client library. To make this demo work you have to do the same (or change the demo's code).
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<script language="JavaScript" src="/LS/lscommons.js"></script>
<script language="JavaScript" src="/LS/lspushpage.js"></script>
</head> Then we put in the body of the page a simple div tag. We will append updates there:
<body>

<div id="container">
Updates:<br/>
</div>
Now we can start scripting :D
<script>
Configure PushPage (http://www.lightstreamer.com/docs/client_web_jsdoc/PushPage.html) and LightstreamerEngine (http://www.lightstreamer.com/docs/client_web_jsdoc/LightstreamerEngine.html) objects. We will use the createEngine (http://www.lightstreamer.com/docs/client_web_jsdoc/PushPage.html#createEngine) method and we will configure the LightstreamerEngine in the onEngineReady (http://www.lightstreamer.com/docs/client_web_jsdoc/PushPage.html#onEngineReady) method of the PushPage instance.
Since the LightstreamerEngine starts disconnected, we will explicitly set it to STREAMING; this demo is made to run on LS' internal web server so we will set domain, host and port to null; the Adapter name is the one of the StockListDemo;

var lsPage = new PushPage();
lsPage.context.setDomain(null);

lsPage.onEngineReady = function (lsEng) {
lsEng.connection.setLSHost(null);
lsEng.connection.setLSPort(null);
lsEng.connection.setAdapterName("STOCKLISTDEMO");
lsEng.changeStatus("STREAMING");
};

lsPage.bind();
lsPage.createEngine("SLEngine","/LS/","SHARE_SESSION");

Now there is the table-related code. This code is different for the two approaches.

Initialize two variables that will be passed to the NonVisualTable's constructor (http://www.lightstreamer.com/docs/client_web_jsdoc/NonVisualTable.html#NonVisualTable%28%29).

Approach 1:
Those variables will be two strings. For this demo those will be space-separated lists of items and fields. By the way the Client doesn't know about this and will interpret them as a group and a schema name (i.e. the Client doesn't know how many items/fields we are subscribing to).

var schema = "last_price time pct_change bid_quantity bid ask ask_quantity min max ref_price open_price stock_name";
var group = "item1 item16 item3";

Approach 2:
Those variables will be Arrays. Each array's element is an item/field name, so the web Client will exactly know how many and which items/fields we are subscribing to.

var schema = new Array("last_price","time","pct_change","bid_quantity","bid","ask","ask_quantity","min","max","ref_price","open_price","stock_name");
var group = new Array("item1","item16","item3");

Now we have to create the NonVisualTable object. We want a MERGE subscription and require the initial snapshot:

var myTable = new NonVisualTable(group,schema,"MERGE");
myTable.setSnapshotRequired(true);

It's time to handle updates implementing the onItemUpdate (http://www.lightstreamer.com/docs/client_web_jsdoc/Table.html#onItemUpdate) callback. We will append a single line to our div for each update. This line will contain the item index/name (1st approach/2nd approach) being updated and, if changed, the last_price field value (btw note that we are receiving all fields, not only the last_price, to receive only the last_price field we have to cut the schema string/array as you can easily imagine).

Approach 1:
As said before to handle updates for this table we must manage item/field indexes (the itemName parameter will be always null)

myTable.onItemUpdate = function(item, itemUpdate, itemName) {
var updateText = "updating item " + item + ". ";

if (itemUpdate.isValueChanged(1)) {
updateText += "New value for last_price: " + itemUpdate.getNewValue(1);
}

document.getElementById("container").innerHTML += updateText + "<br/>";
}


Approach 2:
Here we can use item/field names

myTable.onItemUpdate = function(item, itemUpdate, itemName) {
var updateText = "updating item " + itemName + ". ";

if (itemUpdate.isValueChanged("last_price")) {
updateText += "New value for last_price: " + itemUpdate.getNewValue("last_price");
}

document.getElementById("container").innerHTML += updateText + "<br/>";
}

Then add the table to the PushPage...

lsPage.addTable(myTable,"1");

...and close all open html tags...
</script>

</body>

</html> ...and we have finished! :cool:

You can find the complete sources attached to this post.

Approach 1 example output:

Updates:
updating item 1. New value for last_price: 3.16
updating item 2. New value for last_price: 12.82
updating item 3. New value for last_price: 7.59
updating item 3. New value for last_price: 7.55

Approach 2 example output (based on the same updates):

Updates:
updating item item1. New value for last_price: 3.16
updating item item16. New value for last_price: 12.82
updating item item3. New value for last_price: 7.59
updating item item3. New value for last_price: 7.55

-Mone

mlohbihler
10-13-2007, 04:46 AM
Hi Mone,

The getNewValue method works when i call it with a 1-based index, but not when i try to use the field name (e.g. "price", "time", "type", etc). Is there a way to get LS to recognize the field name instead?

Best regards,
Matthew

Mone
10-15-2007, 06:57 PM
Hi,

to let the web client recognize the item and field names just follow approach 2 as explained.
Check approach2.html in the zip file to see the complete source code.

mlohbihler
10-15-2007, 07:12 PM
Thanks, but i tried that, and never got any data. In my DataAdapter i am calling the smart update with a Map object as the fields, and using field names such as "value", "time", "type", and "index". But in the JS the method calls getNewValue(1), and getNewValue("1") work (as as well for other indices), but the calls getNewValue("value"), getNewValue("time"), etc do not.

I had assumed that leaving out the field names was maybe some kind of bandwidth performance setting. Might this be the case or am i doing something wrong?

Best regards,
Matthew

Mone
10-15-2007, 07:35 PM
Hi,

Are you using your own MetadataProvider (http://www.lightstreamer.com/docs/adapter_java_javadoc/com/lightstreamer/interfaces/metadata/MetadataProvider.html) or a given one (LiteralBasedProvider or similar is needed)?
Have you created your table using as schema an array of field names?

About bandwidth note that item/field names never go through the stream.


PS: I noticed that this tutorial use the loadEngineMinimal method. Please upgrade to the new createEngine (http://www.lightstreamer.com/docs/client_web_jsdoc/PushPage.html#createEngine)method as loadEngineMinimal is a deprecated method (I will update this tutorial as soon as possible)
PPS: Updated!

mlohbihler
10-22-2007, 09:07 PM
Hi Mone,

Yes, i created my own MetadataProvider. How would that affect things?

I create by table thus:
var newTable = new NonVisualTable("test6", "value time index", "DISTINCT");

Thanks,
Matthew

Mone
10-23-2007, 10:05 AM
There are two conditions to let you access data with item/field names:
You must create the Table (http://www.lightstreamer.com/docs/client_web_jsdoc/Table.html) object using as group/schema an array of strings. Each string should be the name of an item/field.
The web client will concatenate the strings using a space as separator.
The getItems (http://www.lightstreamer.com/docs/adapter_java_javadoc/com/lightstreamer/interfaces/metadata/MetadataProvider.html#getItems%28java.lang.String,%20java.lang.String%29) /getSchema (http://www.lightstreamer.com/docs/adapter_java_javadoc/com/lightstreamer/interfaces/metadata/MetadataProvider.html#getSchema%28java.lang.String,%20java.lang.String,%20java.lang.String%29) method of the MetadataProvider implementation must split the received id/schema on the space character and handle each token as an item/field name.
This is the behavior of the LiteralBasedProvider.
You should create your table as below:
var newTable = new NonVisualTable(new Array("test6"), new Array("value","time","index"), "DISTINCT");

mlohbihler
10-23-2007, 04:22 PM
Hurray! Thanks Mone, that works much better.

Remixen
08-27-2010, 07:09 AM
Thanks for you information i newly join and so nice post I agree with you. Your complement is so informative…

mohamida
09-09-2010, 09:39 AM
Hi everybody.

is there a way, instead of having this:
var group = "item1 item16 item3";

i get the my group from my DataProvider ?
because i have so many items that i will display, that my js file (containing the items i wil display) gets bigger.
and also that group of items is variable (can be 10 items to display today, 20 items tomorrow...)

Mone
09-09-2010, 11:08 AM
Hi,

Those variables will be two strings. For this demo those will be space-separated lists of items and fields. By the way the Client doesn't know about this and will interpret them as a group and a schema name (i.e. the Client doesn't know how many items/fields we are subscribing to).
on the server side the getItems (http://www.lightstreamer.com/docs/adapter_java_javadoc/com/lightstreamer/interfaces/metadata/MetadataProvider.html#getItems%28java.lang.String,%20java.lang.String,%20java.lang.String%29)method of MetadataProvider translates the received string in a list of items. In this example we split the string on the space character, but you may use any string as group and translate in as many items as you want on the metadataadapter.

HTH

mohamida
09-09-2010, 12:06 PM
Sorry, but I didin't understand what you said :o
espacially, what did you mean by but you may use any string as group and translate in as many items as you want on the adapter

and, if i choose to make this, will i have to make changes in the adapter, or the metadataadapter ? (because you talked about the two of them)

Mone
09-09-2010, 03:43 PM
sorry for saying adapter at the end of my previous post, now it's correct.

What I mean is that it is the getItems method of the metadata adapter (see the MetadataProvider interface) that translates the group name into a list of items.

The LiteralBasedProvider is an implementation of MetadataProvider that splits the group name on the space character and use the results as items.

The FileBasedProvider is an implementation of MetadataProvider that appends ".items" to the group name and searches for a file with that name. It then reads a list of items from that file

So, you can implement your own getItems on your own MetadataProvider implementation with your own logic

mohamida
09-09-2010, 06:51 PM
hmmm. i did understand what you're saying.
i think that is difficult for me (because i'm still a novice) to implement my own MetadataProvider, that's why i prefer using the FileBasedProvider, so that the size of my javascript won't be that big.i'll try that, and i hope i will succeed :D
thank you again Mone.