Skip to Content
Author's profile photo Steve Rumsby

Personas v3, JavaScript and tables

Peter Spielvogel is doing a great job of covering the basic JavaScript skills you need to write Personas scripts in version 3 with the same level of functionality as scripts in version 2. I thought I’d start a series covering things that you couldn’t do in version 2, or couldn’t do easily, that version 3 makes possible or easier. I’m going to start with something I managed to get working in version 2, but only just – custom tables. Version 3 still doesn’t have a custom table object, and so you still have to manually copy and paste the table contents. In version 3, though, you can build an HTML table to display in the HTML viewer object, rather than my separate grid of custom text fields, and having JavaScript as the scripting language makes the copy and paste operations much easier.

I’m going to build this on SMEN, after having first hidden the menu and rippling pond and then added an HTMLviewer object and a script button labelled “Refresh”. The table I’m going to copy this time is the work process list from SM50, just because that’s something everyone will have available and so it makes a good demo. The final screen looks like this:

Screen Shot 2014-12-01 at 14.33.01.png

Note, I’ve made no attempt to provide any pretty formatting for the table – this is as basic as it gets! The table has more columns than will fit in the viewer and so there’s automatically a horizontal scrollbar. If there were also more rows, you’d get a vertical scrollbar too.

Let’s go through the script in smallish chunks. First we need to navigate to SM50 and grab a reference to the table of work processes.

session.startTransaction(“SM50”);

var selectedTable = session.findById(“wnd[0]/usr/cntlGRID1/shellcont/shell/shellcont[1]/shell”);

var columnNumbers = selectedTable.columns.length;

var rowNumbers = selectedTable.rowCount;

First notice the session object, which contains lots of methods for interacting with the backend system and objects on the screen. Our first use of it is to call the startTransaction method to run SM50. Next we use the findById method to get a reference to the table object on the screen. Also here we’re using variables to hold the dimensions of the table as well as the reference to the table object. We’ll need all of those for step 2 – copying the data from the table.

// Now loop through the table and copy the contents to a standard JavaScript array.

// Note that the screen table is accessed in a column oriented fashion, like HANA:-)

// Here the copy is built the same way, although we could swap rows and columns during the

// copy to get a more natural JavaScript array.

var currentColumn = 0;

var currentRow = 0;

var table= new Array();

for(currentColumn = 0; currentColumn<columnNumbers; currentColumn++) {

table[currentColumn] = new Array();

table[currentColumn][0] = selectedTable.columns.elementAt(i).title;

for(currentRow = 0; currentRow<rowNumbers; currentRow++) {

table[currentColumn][currentRow+1] = selectedTable.getCellValue(currentRow, selectedTable.getColumnId(currentColumn));

}

}

This code uses JavaScript’s looping ability to iterate through all the cells of the screen table and copy them to a separate JavaScript array. Note that JavaScript arrays are one-dimensional – just a single list of values. To create a two dimensional table you create an array of arrays. You can find more details of JavaScript arrays and how they work here.

So now we have a copy of the data in the table on the screen we need to head back to SMEN. That’s easy – just push the “Back” button.

session.findById(“wnd[0]/tbar[0]/btn[3]”).press();

Finally, we need to create the HTML table and display it in the HTMLViewer control.

var htmlTable;

htmlTable = “<table border=1>”;

for(currentRow = 0; currentRow <= rowNumbers; currentRow++) {

htmlTable += “<tr>”;

for(currentColumn = 0; currentColumn < columnNumbers; currentColumn++) {

htmlTable += “<td>”;

htmlTable += table[currentColumn][currentRow];

htmlTable += “</td>”;

}

htmlTable += “</tr>”;

}

htmlTable += “</table>”;

// Finally, send the table to the HTML viewer

session.findById(“wnd[0]/usr/htmlViewerPersonas_14”).content = htmlTable;

We’re using loops again to run through all the columns and rows of the copied data and construct a string of HTML to display that data in a table. String concatenation in JavaScript is done simply with the + operator (the JavaScript + operator adds numbers but concatenates strings). In the code above I use the “assignment operator” += to append to the existing string value. Finally note that the usual way to use the HTML Viewer object is to assign to its “url” property to set the URL being displayed, but you can also set the “content” property to directly provide the HTML.

I’m doing nothing fancy with the formatting of the table or the data here – for details of how HTML tables work and some of the formatting you can apply to them, read this. I’m also making no effort to process any HTML special characters (like “<“, for example). The complete script is attached to this blog post as “table_copy.txt”. Paste it into the script editor and then assign the script to the “Refresh” button to complete the process.

This is obviously a display-only table. Constructing something that responds to mouse input – double-click on a cell to cause an action of some sort – or that allows input, will require further experimentation 😉 . Still, this simple table copy might be useful in some circumstances, and it does demonstrate some of the power you get from having JavaScript as the scripting language in Personas version 3. It should be possible to make this easier to use by wrapping it in a JavaScript object and hiding all of the nasty code in simple methods. JavaScript’s object orientation certainly has the potential to make complex scripting easier to manage. Maybe that will be my next blog? 🙂

Assigned Tags

      32 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Florian Henninger
      Florian Henninger

      Hi Steve,

      SM50 is really something everybody is having available.. especially a lot also knows what it covers.

      Is there a chance to get access to Personas 3.0 right know to play a bit around with it?

      I found it by my own. Of course, there is the ramp up program available, but can I use it in the amazon cloud access also?

      ~Florian

      Author's profile photo Steve Rumsby
      Steve Rumsby
      Blog Post Author

      Personas is an add-on that installs in a NetWeaver system. It doesn't run independently, so it can't run in the cloud. Unless the NW system is in the cloud also, I guess.

      Right now the only way to it access to it is via the ramp-up programme, which is full. See Peter Spielvogel's response here for SAP's best guess about when it will become generally available - currently Q1 2015.

      Author's profile photo Daniel Ruiz
      Daniel Ruiz

      hi Steve,

      just got the Personas 3 working around 15 minutes ago, and I cannot get the onLoad to fire.. it seems in your sample, the user needs to 'click' something, while I'm looking into something more like 'auto-execute'.. is there any hook method provided by Personas 3 to do such?

      Cheers,

      D.

      Author's profile photo Steve Rumsby
      Steve Rumsby
      Blog Post Author

      Yes, there's an onLoad event for the screen - look at the "Screen Events" option on the insert tab in the screen editor (he says without a system in front of him, so that might not be completely correct).

      If you don't see it there, or if it doesn't fire, it might be because you aren't completely up to date with kernel patches or OSS notes. Check that, and update if necessary.

      Steve.

      Author's profile photo Daniel Ruiz
      Daniel Ruiz

      hi Steve,

      thanks for that - I can see the event, I bind it to a function and it just doesn't fire when the screen loads - however, if I press CTRL+SHIFT+I (Inspector, Chrome) it will fire an event.. I can also see there's a roundtrip happening, the UR wheel shows up very briefly..

      it would be more of a 'init' like a document ready sort of method to inject all other libraries I need to complete the demo.

      we just patched this morning to 7.42 KERNEL 27, it should be the last one.. all notes are pretty much implemented (have been implemented before) -- do we need to apply all of them again?

      Cheers,

      D.

      PS: I just added you here in SDN.

      Author's profile photo Steve Rumsby
      Steve Rumsby
      Blog Post Author

      You shouldn't have to reapply the notes, no. Kernel pl28 was released on Friday. I'm pretty sure the onLoad event has worked for me, but it has been a while. I'll check it tomorrow and report back here!

      Author's profile photo Daniel Ruiz
      Daniel Ruiz

      thanks Steve.. 27 was a typo, I meant 28!

      🙁

      well, it doesn't work as I mention, I will open a ticket.

      Author's profile photo Steve Rumsby
      Steve Rumsby
      Blog Post Author

      It turns out that keeping completely up to date might be the problem - my flavor with an onLoad script works on a pl26 system but not my pl28 system. With pl28 the script isn't triggered. Best add that to the OSS message...!

      Steve.

      Author's profile photo Daniel Ruiz
      Daniel Ruiz

      hi Steve,

      thanks a lot for coming back with this finding.. will attach to the message before closing.

      there's also some other issue, not sure if you want to confirm.. the session.findById doesn't work when the element contains a "\" - it seems when we pull the element or inspect it it keeps the element with just one \, but the findById method will only really match an element replacing \ for \\ (escaping).. is this a problem in PL26 too?

      Cheers,

      D.

      Author's profile photo Steve Rumsby
      Steve Rumsby
      Blog Post Author

      I'd not spotted that. Can you give me an example of a transaction/screen object that triggers the problem and I'll check.

      Steve.

      Author's profile photo Andy Silvey
      Andy Silvey

      Hi Steve and Peter Spielvogel,

      I'm a little confused, but that's not the first time 🙂

      I always thought the point of SAP Screen Personas was:

           ScreenPersonas.png

      As the picture says,

          SAP Screen Personas provides a simple, drag and drop approach to modify many common SAP Gui screens and make them more useable as well as more visually appealing

           We all know, even without SAP reminding us, we have a duty to keep things simple and reduce complexity

           For anybody implementing SAP wherever possible stick as close to the standard as possible

           Only customise if you really have to etc

      And hence, the question, why, is Personas now going down the route of custom development and all of the complexity that custom development creates ?

      I have been following Personas since the beginning and thanks to your articles Steve and Peter I am as uptodate on the subject as I can be.

      And when I read this blog I just think, why ? Isn't this going against the point of Personas, a simple drag and drop approach to modify common SAP Gui screens

      and now we're programming and needing Developers etc.

      Just some thoughts.

      Best regards,

      Andy.

      Author's profile photo Former Member
      Former Member

      Personas IMHO does offer a simple drag and drop approach to modify common SAP Gui screens.

      However what Steve I believe is trying to highlight here is that if you were so inclined you could go beyond the scope of simply modifying screens into building upon enhancements to existing SAP applications.

      Author's profile photo Steve Rumsby
      Steve Rumsby
      Blog Post Author

      Thanks Neil!

      Andy, you're right - that was the original intention for Personas. In fact the original tagline was "Personalization without Programming". And if all you need is a drag and drop editor for the visuals of an SAP transaction, Personas does that very well. A large part of my Personas development is just that.

      But there's only so much simplification you can achieve that way. Some transactions are so complex that tweaking the visuals isn't enough. My best example of that is IW33. I describe my simplification of it in this blog - Simplifying a multi-screen transaction with Personas. There's no way to achieve that level of simplification without the Personas scripting capability. In some cases Personas scripts can be quite simple, but you can achieve a lot if you are prepared to take the scripts beyond the simple. Something like this perhaps - Putting everything together - the finished Personas project.


      Personas scripting is powerful enough, especially in version 3, that you can think of Personas not just as a tool for simplifying individual SAPgui transactions, but of simplifying business processes.


      Of course, we already have several ways of developing new interfaces to SAP functionality - ABAP dynpro, ABAP web dynpro, SAP UI5, the new Web IDE, to name a few. Dare I mention Java web dynpro, also? Why do we need another? For the same reason we have the current ones. The same reason we don't do all development in the C++ language that the kernel is written in, or the machine code the CPU understands. Different languages and development environments are for different purposes and different target audiences.


      For me, Personas development takes place at a different level of abstraction from ABAP or UI5. ABAP calls BAPIs to interact with the NW system, but Personas scripts call SAPgui transactions. Those are much richer, more functional building blocks. Personas development can be a much quicker process. It is also more limited. Not everything you might want to do can be done directly in a Personas script. My Personas developments have been given a helping hand from little bits of ABAP here and there.


      In summary, Personas needs scripting to be able to do all of the transaction simplification that users need. Given that it exists, that it is capable of doing more than just transaction simplification, that it is sufficiently different from existing development environments, and most importantly that people are finding it useful, then why not?


      Obviously, I don't speak for SAP - this is all just my opinion. I won't use Personas for everything - it isn't appropriate for everything. I will choose the appropriate tool for the task at hand. I am glad that Personas is one of those choices.

      Author's profile photo Peter Spielvogel
      Peter Spielvogel

      Hi Andy,

      Neil and Steve have covered the topic very well, so I’ll keep my comments brief.

      Our original intention with SAP Screen Personas was, as you pointed out, “to provide a simple, drag and drop approach to modify many common SAP GUI screens and make them more useable as well as more visually appealing.” Most customers would agree that the product, independent of version, achieves this goal.

      The feedback we received on version 2 was that while scripting was easy (although not necessarily drag and drop), it did not have enough power to accomplish mass simplification efforts. For example, suppressing a finite but unknown number of pop-ups windows, is very straightforward with a looping mechanism and considerably more difficult without. So, we added more power to the scripting engine by basing it on JavaScript.

      So, we still have drag and drop simplicity to remove items from screens (the first request from our original co-innovation customers), merge tabs, pre-fill fields, and make other visual enhancements. But, we also have the power to do much, much more such as combining information from different transactions on a simple screen, automating keystrokes, or changing the flavor based on the screen size using the scripting engine. In between, there are some simple scripting techniques that rely on JavaScript, but hardly require programming skills.

      If you want to stick to a drag and drop approach, you can make basic modifications to your screens. If you want to greatly simplify the SAP user experience for your employees, this will likely require scripting. The choice is yours.

      Regards,

      Peter

      Author's profile photo Andy Silvey
      Andy Silvey

      Hi Steve and Peter,

      thank you for burying my doubts.

      It's great to know the underlying principles are there and if people so wish, they can extend with scripting.

      Andy.

      Author's profile photo Matt Fraser
      Matt Fraser

      Steve,

      Thanks for this. We got very excited about Personas as a possible replacement for GuiXT here, and sent one of our business analysts to Personas (v2) training to learn more. She came back rather discouraged at the news that it wouldn't work with custom tables, which is something we do a lot of here in GuiXT, and that it wouldn't in v3 either. I don't know if this is a full solution, but it certainly seems like something that could address this concern of ours.

      Regards,

      Matt

      Author's profile photo Steve Rumsby
      Steve Rumsby
      Blog Post Author

      It is certainly easier with v3 scripting to manipulate table data, including copy it around. With some work to add formatting and other capabilities I'm sure the code above could be turned into something really quite powerful. I've already added column filtering and I'm thinking about how to support row filtering. I don't know yet if there is a way to build tables that support input or drilldown. I'll investigate that in due course!

      All of these enhancements will obviously make the code significantly more complex, which would be a big problem in v2, but with JavaScript in v3 that's much less of a problem. I have a blog brewing about how to use JavaScript objects with Personas to help with code maintainability.

      All that said, official support for table operations would certainly be easier 🙂

      Author's profile photo Former Member
      Former Member

      Hi Steve,

      I am running PL29 and am not able to recreate this example.  There is a method which you are using which my system is throwing errors on.  Could you verify that this still works on your most current system?

      Below are the changes I had to make to get this to work on my system:

      Your code:

      for(currentColumn = 0; currentColumn<columnNumbers; currentColumn++) {

           table[currentColumn] = new Array();

           table[currentColumn][0] = selectedTable.columns.elementAt(i).title;

           for(currentRow = 0; currentRow<rowNumbers; currentRow++) {

             table[currentColumn][currentRow+1] = selectedTable.getCellValue(currentRow, selectedTable.getColumnId(currentColumn));

            }

      }

      My Code:

      for (var currentColumn=0;currentColumn<totalColNum;currentColumn++){

        table[currentColumn] = new Array();

        table[currentColumn][0] = selectedTable.columns.elementAt(currentColumn).title;

        for (var currentRow=0;currentRow<totalRowNum;currentRow++){

          var cellValue=selectedTable.getCellValue(currentRow,selectedTable.getColumnName(currentColumn));

          table[currentColumn][currentRow+1] = cellValue;

        }

      }

      I also had to create a cellValue variable, else the code errored out if everything was on one line.

      Great example!  I like the possibilities of 3.0, just can't wait til the hitches get worked out.

      Thanks!  Christian

      Author's profile photo Steve Rumsby
      Steve Rumsby
      Blog Post Author

      The first correction (i->currentColumn) is a typo on my part. My loop counters are always i and j for outer and inner loops, but I thought more descriptive names might make it more understandable. I only made that change after I'd copied the code out, though. What I posted was not actually my running code. My mistake.

      For the second, I believe there was a plan to change the table access API to make it simpler. That may have come in the most recent note. I've been busy on an ERP patching project for the last few days so I haven't had a chance to play too much with that note. I've just tested now and my code no longer works, as you suggest. Thanks for giving me the fix 🙂

      I have a refinement of this that I'm planning to post in a few days, given time. I think you'll like it...

      Steve.

      Author's profile photo Former Member
      Former Member

      Hi Steve,

      I would like to confirm if is it possible to do the same for an ALV?

      I have the idea that isn't possible because it's not possible to grab a reference of an ALV.

      Best regards,

      Frederico

      Author's profile photo Steve Rumsby
      Steve Rumsby
      Blog Post Author

      That might depend on what you mean by ALV. It should work for anything that presents as a Grid. My example is the table from SM50, which I would call an ALV. Can you give me an example of what you'd like to do?

      Steve.

      Author's profile photo Former Member
      Former Member

      I mean this for example:

      ALV.png

      Thank you,

      Frederico.

      Author's profile photo Steve Rumsby
      Steve Rumsby
      Blog Post Author

      Right, then no you can't get a reference to such a screen with the data as a table. This is true for both Personas 2 and Personas 3. The data in these screens appears to Personas as simply a collection of unrelated text fields, with no row/column structure.

      Steve.

      Author's profile photo Former Member
      Former Member

      Thank you!

      Frederico.

      Author's profile photo Gaurav Anadkat
      Gaurav Anadkat

      Hi Steve,

      I would like to confirm that we are not specifying any URLs while creating HTMLViewer. Just passing data through content property using script.

      I tried the same approach but my HTMLViewer won't provide any results. I am getting proper data in table Variable. Can you help?

      Regards,

      Gaurav

      Author's profile photo Steve Rumsby
      Steve Rumsby
      Blog Post Author

      If you add "/.*" to the URL whitelist table, that should make the HTMLViewer happy.

      Steve.

      Author's profile photo Gaurav Anadkat
      Gaurav Anadkat

      Thanks, Steve.

      Working fine now. If i call RFC and i import html table content in W3HTML type, still "requestResults" method is giving me data in JSON. Is it by default ? I checked other methods but could not find any method to metion Data Type we want to receive. In Personas 2.0 it used to work well where we could specify the type. Any pointers?

      Regards,

      Gaurav

      Author's profile photo Steve Rumsby
      Steve Rumsby
      Blog Post Author

      Yes, you need to parse the results with "JSON.parse()".

      Steve.

      Author's profile photo Ian Rayner
      Ian Rayner

      HI Steve,

      I have just replicated your code (thank you very much!), but I am struggling myself to get it to display in the html viewer. I do have /.* in my whitelist but it still doesnt display.

      When i execute the script i get the "flavor contains non whitelisted url" message.

      In the HTML viewer itself it asks for a URL what exactly should I be entering? I think this is my issue.

      thanks

      Ian

      Author's profile photo Cristiano Hansen
      Cristiano Hansen

      Hi Steve,

      Thanks for sharing. I am still a rookie in Personas scripting, but I am learning from the best. 🙂

      Hopefully I'll be able to do some magic with Personas and write about my experiences here.

      Thanks once again,

      Cris

      Author's profile photo Steve Rumsby
      Steve Rumsby
      Blog Post Author

      The scripting interface to tables has changed since I wrote this blog. There's an article on the Personas Wiki that explains the now official way to copy table data - Copying Table data into a variable - SCN Wiki. Use the code from that page rather than my code above.

      Steve.

      Author's profile photo Steve Rumsby
      Steve Rumsby
      Blog Post Author

      At this point I think you need to start exploring your browser's developer tools, and in particular the debugger, to step through the code and see what might be going wrong. Place a "debugger" statement further up, maybe just before the start of the enclosing for loop (on rowIndex), and see what that tells you.

      Steve.