BSP Guide : How to create a basic BSP…
1: The basicest of
basics
Go in to txn SE80, and instead of “program” in the ddown[D1] menu
on the LHS[D2] of the
screen, select “BSP Application”. Enter a new BSP application name. Just like
regular ABAP, if SAP doesn’t know
what the application is, it will create one for you. Give it a description,
generate it as local object,
Activate the project as it is.
Rightclick on the top of the (as yet empty) tree structure
and select “Create->Page”.
Activate the page using the Ctrl-F3 or the button. (as per
regular ABAP).
This should now look as follows:
Believe it or not, you can now run this!
You get asked for a username and password, since internet
explorer is now trying to connect to SAP .
Enter your SAP username and
password, and you get passed to the page.
Notice in the URL of the internet explorer, you’ve got a
load of junk, but also some telling information:
For example, the z_qp_01/pag1.htm is what I called the
program and the page.
The start of the URL is the SAP
Server upon which the bsp is written. 1080 is the port that’s been configured
in SAP for the release of the
BSPs.
2 : Breaking down the
screens.
BSPs use what’s called ‘page fragments’ to break down a
screen. They work a lot like includes in ABAP, or better yet, windows in
SAPScripts. The good thing about them is that you can reuse them over and over,
so you can create a header screen that holds the company logo in it, and put it
onto every screen in an application. Or you could have one that presents the
username and timestamp.
From your basic screen, (pag1)
change:
<%@page language="abap"%>
<%@extension name="htmlb" prefix="htmlb"%>
<htmlb:content design="design2003">
<htmlb:page title = "Page 1 ">
<htmlb:form>
<htmlb:textView text = "Hello World!"
design = "EMPHASIZED" />
<htmlb:button text = "Press Me"
onClick = "myClickHandler" />
</htmlb:form>
</htmlb:page>
</htmlb:content>
<%@extension name="htmlb" prefix="htmlb"%>
<htmlb:content design="design2003">
<htmlb:page title = "Page 1 ">
<htmlb:form>
<htmlb:textView text = "Hello World!"
design = "EMPHASIZED" />
<htmlb:button text = "Press Me"
onClick = "myClickHandler" />
</htmlb:form>
</htmlb:page>
</htmlb:content>
Into :
<%@page language="abap"%>
<%@extension name="htmlb" prefix="htmlb"%>
<%@extension name="htmlb" prefix="htmlb"%>
<htmlb:content design="design2003">
<htmlb:page title = "Page 1 ">
<%@ include file = "top.htm" %>
</htmlb:page>
</htmlb:content>
<htmlb:page title = "Page 1 ">
<%@ include file = "top.htm" %>
</htmlb:page>
</htmlb:content>
Now the include file doesn’t exist yet, so if you rclick on
the top of the tree hierarchy on the lhs of the screen, you can create another page.
We’ll call this one top.htm (since that’s what we’ve ref’d
in the pag1.htm)
This page will be different to the first one – it will be a
“page fragment”.
Now we’ll drop what we removed from the pag1.htm and put it
into top.htm, so it now looks like this:
<%@page language="ABAP"%>
<htmlb:form>
<htmlb:textView text = "Hello World!"
design = "EMPHASIZED" />
<htmlb:button text = "Press Me"
onClick = "myClickHandler" />
</htmlb:form>
<htmlb:form>
<htmlb:textView text = "Hello World!"
design = "EMPHASIZED" />
<htmlb:button text = "Press Me"
onClick = "myClickHandler" />
</htmlb:form>
Activate top1.htm, and activate pag1.htm, which now
references top1.htm instead of containing the text and the button.
You also need to include the fact you’ll be using “HTMLB”
within the page fragment…
So put that in underneath
<%@page language="ABAP"%>
thus…
<%@page language="ABAP"%>
<%@extension name = "htmlb" prefix="htmlb" %>
<%@extension name = "htmlb" prefix="htmlb" %>
Activate and run the application from pag1.
Result should most likely be that the program runs the same
as it did on the first page. Still, we’ve proved the point of page fragments.
3 : Making the
program a bit more interactive.
Thus far we’ve seen the htmlb standards for outputting a bit
of text, and creating a button. But nothing happens when we press the button at
the moment.
If you’ve missed that, it’s the bit in the page fragment
<htmlb:button text = "Press Me"
onClick = "myClickHandler" />
onClick = "myClickHandler" />
Change the button to :
<htmlb:button id = 'id_1'
text = "Press Me"
onClick = "onInputProcessing()" />
text = "Press Me"
onClick = "onInputProcessing()" />
This has the effect of giving the button a program id (like
the process code in a dialog screen) and makes the clicking of the button point
to the onInputProcessing part of the main screen.
Save and activate the fragment top.htm.
Now got back to the main page – pag1.htm.
There’s an “event handler” tab which deals with interactions
between the user and the screen. When the button gets pressed, it invokes the
“onInputProcessing” code, which works like a PAI in dialog. So in the event
handler, use the dropdown list to find the “onInputProcessing” event for the
page.
The following code handles HTMLB events:
IF event_id = CL_HTMLB_MANAGER=>EVENT_ID.
DATA : event TYPE REF TO CL_HTMLB_EVENT,
button_event TYPEREF TO CL_HTMLB_EVENT_BUTTON,
tv type ref to cl_htmlb_tableview,
tv_data TYPEREF TO CL_HTMLB_tableview.
data: wa_zcaps1 type ZCAPS1.
data: vl_cookiename TYPE char30.
event = CL_HTMLB_MANAGER=>get_event( runtime->server->request ).
IF event->name = 'button'AND event->event_type = 'click'.
button_event ?= event.
case button_event->id.
when 'id_1'.
navigation->goto_page( 'pag2.htm' ).
endcase.
endif.
endif.
button_event TYPE
tv type ref to cl_htmlb_tableview,
tv_data TYPE
data: wa_zcaps1 type ZCAPS1.
data: vl_cookiename TYPE char30.
event = CL_HTMLB_MANAGER=>get_event( runtime->server->request ).
IF event->name = 'button'
button_event ?= event.
case button_event->id.
when 'id_1'.
navigation->goto_page( 'pag2.htm' ).
endcase.
endif.
endif.
The key to this bit of code is the bit near the end…
IF event->name = 'button' AND event->event_type = 'click'.
button_event ?= event.
case button_event->id.
when 'id_1'.
navigation->goto_page( 'pag2.htm' ).
endcase.
button_event ?= event.
case button_event->id.
when 'id_1'.
navigation->goto_page( 'pag2.htm' ).
endcase.
Essentially this says “If the event ID is id_1, go to pag2”.
Now we’ve not created pag2.htm yet, so we go to the
navigator on the lhs of the screen, rclick the “Pages with flow logic” and
create a new page. (page with flow logic)
This automatically creates another page just like the first
one. We don’t want this, since we won’t be able to tell the difference!.
So we’ll get rid of all the htmlb form, and replace it with
a success message.
So the contents of pag2.htm should now look like this:
<%@page language="abap"%>
<%@extension name="htmlb" prefix="htmlb"%>
<htmlb:content design="design2003">
<htmlb:page title = "Second Page ">
success!!!
</htmlb:page>
</htmlb:content>
<%@extension name="htmlb" prefix="htmlb"%>
<htmlb:content design="design2003">
<htmlb:page title = "Second Page ">
success!!!
</htmlb:page>
</htmlb:content>
Now the trick to this is that whilst most html
output is tagged to help with formatting and so forth, you can actually just
put text in an html page. Internet explorer shouldn’t find this a problem.
Activate the target page pag2.htm.
Go to pag1.htm and run it. Clicking on the button
directs us to pag2.htm.
4: More interaction..
4.1 Simple Text Entry
So far so good. But we most likely want users to
enter some information, or to output some stuff from SAP .
Or mayhap a combination of both.
First declare your data in the “Page Attributes” tab of
pag1.htm
We’ll declare name1 type name1.
We’ll flag it as automatic as well. This allows calling
pages to pass the data in (kind of like in a fm call where you pass data in.)
Activate the page, so when we go to the top.htm page
fragment, top will be able to “see” the newly declared attribute.
Now we’ve declared it, we can use it in the top.htm page
fragment.
The HTMLB syntax for a data entry of this type is as
follows:
<INPUT type="text" name="name1"
value=<%= name1 %> >
value=<%= name1 %> >
This needs to go inside the <htmlb:form>
<htmlb:form/> tags.
This can then be handled inside the eventhandler
if needs be.
The <%= name1 %> indicates that we’re using an ABAP
variable here.
Within the BSP, it is in fact possible to switch between
ABAP and HTML/HTMLB
The <%= %> indicates the commencement and ending of
ABAP.
We’ll demonstrate handling of this in the eventhandler by
coding in a condition that if the name1 is a particular value, then we’ll do
something else.
case button_event->id.
when 'id_1'.
if name1 = 'bugs'.
navigation->goto_page( 'pag3.htm' ).
else.
navigation->goto_page( 'pag2.htm' ).
endif.
endcase.
when 'id_1'.
if name1 = 'bugs'.
navigation->goto_page( 'pag3.htm' ).
else.
navigation->goto_page( 'pag2.htm' ).
endif.
endcase.
And
as usual, we’ll need to create pag3.htm giving it the following contents :
<%@page language="abap"%>
<%@extension name="htmlb" prefix="htmlb"%>
<htmlb:content design="design2003">
<htmlb:page title = "Page 3 ">
<htmlb:form>
Page 3
</htmlb:form>
</htmlb:page>
</htmlb:content>
<%@extension name="htmlb" prefix="htmlb"%>
<htmlb:content design="design2003">
<htmlb:page title = "Page 3 ">
<htmlb:form>
Page 3
</htmlb:form>
</htmlb:page>
</htmlb:content>
Activate everything, go back to page1 and test.
You should find that if the contents of the field on the
screen is “bugs” then we go to page 3, and if not then we go to page 2.
4.2 Dropdown Lists.
The classic HTML dropdown list is as follows:
<select name="cars">
<option
value="volvo">Volvo</option>
<option
value="saab">Saab</option>
<option
value="fiat">Fiat</option>
<option
value="audi">Audi</option>
</select>
However, in SAP ,
we can get round the need to repetitively give the user options by using the
BSP’s capability to code a bit in ABAP and a bit in HTML.
Create a pag1.htm page attribute called v_vbeln of type
vbeln. Activate the page.
For this exercise we’ll also need a table of vbelns. This
gets defined in the pag1
“type definitions” tab. This is exactly the same as a declaration
in a regular ABAP program.
types: BEGIN OF ty_vbeln,
vbeln TYPE vbeln,
end of ty_vbeln.
types: tty_vbeln TYPE TABLE OF ty_vbeln.
vbeln TYPE vbeln,
end of ty_vbeln.
types: tty_vbeln TYPE TABLE OF ty_vbeln.
This gives
you a type tty_vbeln and a 1 field structure we can use.
Then in the PageAttributes Tab, declare a table
and wa of these types:
t_vbeln TYPE TTY_VBELN
wa_vbeln TYPE TY_VBELN
Now for the fun part…
In the top.htm, code in the following after the name1 input
tags, but still within the form tags.
<%
select vbeln from vbak into table t_vbeln
where erdat = '20080610'.
%>
<select name="v_vbeln" value= <%= v_vbeln %>
title= "SD Doc Number" >
<%
loop at t_vbeln into wa_vbeln.
%>
<option value=<%= wa_vbeln-vbeln %>> <%= wa_vbeln-vbeln %>
</option>
<%
endloop.
%>
</select>
select vbeln from vbak into table t_vbeln
where erdat = '20080610'.
%>
<select name="v_vbeln" value= <%= v_vbeln %>
title= "SD Doc Number" >
<%
loop at t_vbeln into wa_vbeln.
%>
<option value=<%= wa_vbeln-vbeln %>> <%= wa_vbeln-vbeln %>
</option>
<%
endloop.
%>
</select>
So what we’re doing here is selecting the data out of SAP using regular ABAP,
Then defining a dropdown selection, using HTML
Then going into a loop using ABAP again.
Then putting the contents of the loop into the HTML options
table.
Then closing the loop using ABAP again.
Then closing the select using HTMLB.
Activate everything and test it from pag1.htm.
You should see the dropdown list.
4.3 Date Entry
To reap the benefits of other people’s work in creating
calendar dropdowns, add in the following in the top.htm still within the
htmlb:form/> tags.
<htmlb:inputField id = "opening_date"
value = "<%= opening_date %>"
showHelp = "TRUE "
type = "date"
/>
value = "<%= opening_date %>"
showHelp = "
type = "date"
/>
You will also need to establish the data in the
first place at the top of page1 – opening_date type datum.
Activate. Run. See the dropdown.
5 Making it a bit prettier…
5.1 Breaks.
<br> is the html for “new line”
Hence our top.htm example can go from looking
like this:
to this:
Next up we probably want to label the fields a
bit. The button’s okay as it is as it kind of speaks for itself, but the text,
the date and the document number most likely want labelling. The easiest way
would be to just type the text in before the field…
E.G.
<br>
NAME1
<INPUT type="text" name="name1"
value=<%= name1 %> >
<br>
NAME1
<INPUT type="text" name="name1"
value=<%= name1 %> >
<br>
But this doesn’t look particularly great:
So what we’ll do is get them lined up by means of
a table.
5.2 Grids.
An html page grid serves as a way of tidying up
the display. The problem is they’re fairly complicated in terms of the amount
of html code they take up versus the improvement they make on the screen.
That said, users can be picky, and this is the
way to make them happy.
First define how big you want the grid to be, and
then use the following example to wrap the fields we’ve got already in a table
that lines it all up. Since the table will handle the new lines, we can get rid
of the <br> formatting.
<htmlb:gridLayout columnSize = "4"
rowSize = "8" >
rowSize = "8" >
</htmlb:gridLayout>
sits around the whole thing.
And then
<htmlb:gridLayoutCell columnIndex = "3" rowIndex = "1" >
</htmlb:gridLayoutCell>
sits around each cell, to describe where it sits
in the grid.
So put the “opener” tag in front of everything
you want “placed” i.e. the texts and the fields themselves. Columns should
alternate between 1 and 2, and at every new column, increment the row by 1.
Code should now look like this :
<%@page language="ABAP"%>
<%@extension name = "htmlb" prefix="htmlb" %>
<htmlb:form>
<htmlb:gridLayout columnSize = "4"
rowSize = "8" >
htmlb:gridLayoutCell columnIndex = "1" rowIndex = "1" >
<htmlb:textView text = "Hello World!"
design = "EMPHASIZED" />
</htmlb:gridLayoutCell>
<htmlb:gridLayoutCell columnIndex = "1" rowIndex = "2" >
<htmlb:button id = 'id_1'
text = "Press Me"
onClick = "onInputProcessing()" />
</htmlb:gridLayoutCell>
<htmlb:gridLayoutCell columnIndex = "1" rowIndex = "3" >
NAME1
</htmlb:gridLayoutCell>
<htmlb:gridLayoutCell columnIndex = "2" rowIndex = "3" >
<INPUT type="text" name="name1"
value=<%= name1 %> >
</htmlb:gridLayoutCell>
<htmlb:gridLayoutCell columnIndex = "1" rowIndex = "4" >
DOCUMENT
</htmlb:gridLayoutCell>
<htmlb:gridLayoutCell columnIndex = "2" rowIndex = "4" >
<%
select vbeln from vbak into table t_vbeln
where erdat = '20080610'.
%>
<select name="v_vbeln" value= <%= v_vbeln %>
title= "SD Doc Number" >
<%
loop at t_vbeln into wa_vbeln.
%>
<option value=<%= wa_vbeln-vbeln %>> <%= wa_vbeln-vbeln %>
</option>
<%
endloop.
%>
</select>
</htmlb:gridLayoutCell>
<htmlb:gridLayoutCell columnIndex = "1" rowIndex = "5" >
DATE
</htmlb:gridLayoutCell>
<htmlb:gridLayoutCell columnIndex = "2" rowIndex = "5" >
<htmlb:inputField id = "opening_date"
value = "<%= opening_date %>"
showHelp = "TRUE "
type = "date"
/>
</htmlb:gridLayoutCell>
</htmlb:gridLayout>
</htmlb:form>
<%@extension name = "htmlb" prefix="htmlb" %>
<htmlb:form>
<htmlb:gridLayout columnSize = "4"
rowSize = "8" >
htmlb:gridLayoutCell columnIndex = "1" rowIndex = "1" >
<htmlb:textView text = "Hello World!"
design = "EMPHASIZED" />
</htmlb:gridLayoutCell>
<htmlb:gridLayoutCell columnIndex = "1" rowIndex = "2" >
<htmlb:button id = 'id_1'
text = "Press Me"
onClick = "onInputProcessing()" />
</htmlb:gridLayoutCell>
<htmlb:gridLayoutCell columnIndex = "1" rowIndex = "3" >
NAME1
</htmlb:gridLayoutCell>
<htmlb:gridLayoutCell columnIndex = "2" rowIndex = "3" >
<INPUT type="text" name="name1"
value=<%= name1 %> >
</htmlb:gridLayoutCell>
<htmlb:gridLayoutCell columnIndex = "1" rowIndex = "4" >
DOCUMENT
</htmlb:gridLayoutCell>
<htmlb:gridLayoutCell columnIndex = "2" rowIndex = "4" >
<%
select vbeln from vbak into table t_vbeln
where erdat = '20080610'.
%>
<select name="v_vbeln" value= <%= v_vbeln %>
title= "SD Doc Number" >
<%
loop at t_vbeln into wa_vbeln.
%>
<option value=<%= wa_vbeln-vbeln %>> <%= wa_vbeln-vbeln %>
</option>
<%
endloop.
%>
</select>
</htmlb:gridLayoutCell>
<htmlb:gridLayoutCell columnIndex = "1" rowIndex = "5" >
DATE
</htmlb:gridLayoutCell>
<htmlb:gridLayoutCell columnIndex = "2" rowIndex = "5" >
<htmlb:inputField id = "opening_date"
value = "<%= opening_date %>"
showHelp = "
type = "date"
/>
</htmlb:gridLayoutCell>
</htmlb:gridLayout>
</htmlb:form>
And the result is that the fields have lined up
nicely:
5.3 Graphics
An easy way to impress users and make them
happier with a web-page is to put a few graphics on there. Graphics are stored
in the MIME repository on SAP .
Getting graphics into the repository, and calling them on a BSP is a pretty
simple process.
Get the graphic in by rclicking on the root of
the navigation tree on the lhs of the screen, and go to “Create->MIME
Object->Import”.
6 More Data manipulation.
6.1 – Passing Data between screens.
The data doesn’t actually “survive” between
screens. You can demonstrate this by entering data on page 1, pressing the
“pressme” button, then going “BACK” to the first screen using the navigator
button “Back” in Internet explorer.
There are a number of ways of doing this. One of
these is a server cookie, which stores the data on the database, as a complete
structure or table.
For the time being, we’ll create an object that
the BSP can sit on. This will survive between BSP Screens, and it’s known as
the “Application Class” for the BSP. Name the application class in the
Properties Tab of the Application.
Create the class in SE24, and give it attributes
that mirror what’s in your BSP. At this stage it’s most likely name1, vbeln,
and datum.
Make them PUBLIC INSTANCE ATTRIBUTES of types
becoming of their names.
Save and activate the class.
Now handle the data entry by passing the
variables from the bsp into the variables in the class. In the
“onInputProcessing” set the object “Application” attributes to the Page Values.
application->attr_name1 = name1.
application->ATTR_DATE1 = opening_date.
application->ATTR_VBELN = v_vbeln.
application->ATTR_DATE1 = opening_date.
application->ATTR_VBELN = v_vbeln.
This stores the data in the object, after pag1 is
processed. To retrieve it again, the pages need to set the values to the object
values onInitialisation. This is like the PBO of a dialog screen.
So we just reverse the above code to.
name1 = application->attr_name1.
opening_date = application->ATTR_DATE1.
v_vbeln = application->ATTR_VBELN.
opening_date = application->ATTR_DATE1.
v_vbeln = application->ATTR_VBELN.
And put it in the onInitialisation of the pag1
screen. This means that when pag1 is invoked, it picks up the data from the
object.
Activate and test this – enter data, press the
“Pressme” button, then navigate back to the pag1.htm using “Back”. The data
should still be on the screen.
6.2 Present some data in a table.
We’ll create a new page fragment called SO_TABLE
to present the data in, and put this on pag2.htm
In pag2.htm we’ll need a list of salesord line
items, so declare the tabular variable in the “Page Attributes” tab of
pag2.htm. This will need to be “Typed” first in the “Type Definitions” tab.
Go to the “onInitialisation” tab, and populate
the table based on the vbeln of the application data.
select * from vbap into table t_vbap
where vbeln = APPlication->attr_vbeln.
where vbeln = APPlication->attr_vbeln.
Next you
need to output this in a table. Syntax for outputting in a table
is:
<%@extension name = "htmlb" prefix="htmlb" %>
<htmlb:form>
<htmlb:tableView id = "sales_order"
table = "<%= t_vbap %>"
selectionMode = "SINGLESELECT"
>
<htmlb:tableViewColumns>
<htmlb:tableViewColumn columnName="VBELN">
</htmlb:tableViewColumn>
<htmlb:tableViewColumn columnName="POSNR">
</htmlb:tableViewColumn>
<htmlb:tableViewColumn columnName="ARKTX">
</htmlb:tableViewColumn>
<htmlb:tableViewColumn columnName="UMZIZ">
</htmlb:tableViewColumn>
<htmlb:tableViewColumn columnName="MEINS">
</htmlb:tableViewColumn>
<htmlb:tableViewColumn columnName="NETWR">
</htmlb:tableViewColumn>
</htmlb:tableViewColumns>
</htmlb:tableView>
</htmlb:form>
<htmlb:form>
<htmlb:tableView id = "sales_order"
table = "<%= t_vbap %>"
selectionMode = "SINGLESELECT"
>
<htmlb:tableViewColumns>
<htmlb:tableViewColumn columnName="VBELN">
</htmlb:tableViewColumn>
<htmlb:tableViewColumn columnName="POSNR">
</htmlb:tableViewColumn>
<htmlb:tableViewColumn columnName="ARKTX">
</htmlb:tableViewColumn>
<htmlb:tableViewColumn columnName="UMZIZ">
</htmlb:tableViewColumn>
<htmlb:tableViewColumn columnName="MEINS">
</htmlb:tableViewColumn>
<htmlb:tableViewColumn columnName="NETWR">
</htmlb:tableViewColumn>
</htmlb:tableViewColumns>
</htmlb:tableView>
</htmlb:form>
ACTIVATE and Run. This creates a table control
for you to use in the program.
You may want to add in a bit of logic that
ensures that the user is prompted for further information if they’ve not
entered enough, or if the data on the screen is inconsistent they are prompted
to fix it.
To do this, we must introduce some very basic
javascript.
The javascript is processed as part of the html,
so you can code in any java functions in the page fragment itself.They go in a
“Header” section of the html. So in the fragment which contains the entry field
“Name1”, first code in the following :
<head>
<script type="text/javascript">
function checkFormular1(htmlbevent)
{
var txt="";
if(document.Formular1.name1.value.length==0){
alert("Please enter a name!");
}
}
</script>
</head>
<script type="text/javascript">
function checkFormular1(htmlbevent)
{
var txt="";
if(document.Formular1.name1.value.length==0){
alert("Please enter a name!");
}
}
</script>
</head>
Since the onClick event is already being used by
the htmlb, we can use the onClientClick which can be used for checking the data
at the client side. This saves server roundtrips, where the client (e.g. internet explorer) has to go and look at the server (e.g. SAP)
Then change the attributes of the <form> we
are using to encapsulate the data entry. We give it the if “Formular1” to match
the “Formula1” in the function above.
So in the page fragment,
<htmlb:form>
becomes
<htmlb:form id="Formular1">
This handles the message output.
However, the onInputProcessing will still go
ahead, so we’ll put a check in there also.
Check name1 is not initial
This prevents any further processing from
occuring.
Worth doing the check after the object has been
populated.