Quantcast
Channel: SAPUI5 Developer Center
Viewing all 789 articles
Browse latest View live

Filling in the GAPS in SPA Application Design with SAPUI5

$
0
0

This blog post has been rolling around in my head for some time as I've continued to delve further into the depths of Fiori application development with SAPUI5. Part of my hesitancy in posting my thoughts here was due to the fact that I've found it rather difficult to find a set of agreed-upon best practices/design patterns for Single-Page Application (SPA) application development (SAPUI5-based or otherwise). As a result, I'm not sure if these perceived gaps truly exist, or if I'm simply trying too hard to map server-side development concepts to a SPA/client-side model. Anyway, what follows are a list of the more prominent gaps that I've faced of late as I've been working on building more complex enterprise-style apps using SAPUI5. I look forward to getting feedback from the community regarding these thoughts.

 

Gap #1: Is it really all about that BASE?

Going back to my days as an undergraduate Computer Science student, I've always thought about transactions in terms of the ACID model. As you probably know, ACID transactions have the following characteristics:

 

  • Atomic: Here, the assumption is that transactions bundle together a number of activities as a logical unit of work. Atomicity ensures that all of these activities either succeed together, or else the transaction is rolled back.
  • Consistent: One way or another, ACID transactions should leave the system in a consistent state.
  • Isolated: Here, the idea is that transactions are isolated in such a way that concurrent reads/writes to the same data are prevented (e.g. through logical and/or database locks)
  • Durable: Upon completion, the results of the transactions are made permanent by outputting the results to some persistent store (e.g. the system database).

 

These days, the new transaction model that's getting a lot of press is the BASE transaction model (Basically Available, Soft State, Eventual Consistency). In simple terms, BASE transactions take a more optimistic view of transaction handling, effectively assuming that most transactions would implicitly operate in isolation and that consistency would eventually be obtained. This concept became popular in the NoSQL space where availability and performance were more desirable than guaranteed consistency. And, for many types of applications, this is a reasonable trade-off that most users are willing to accept.

 

However, since we're talking about building apps in the SAP space, I would submit that there will be lots of times where the BASE transaction model simply doesn't work for enterprise apps. For example, our company uses a fairly prominent SaaS provider (not SAP) to manage our consultant time sheets. Here, we've been able to identify multiple places where two or more users could overwrite the same piece of data without either user even realizing it. Imagine trying to justify such an occurrence to SAP users who have long relied on rock solid consistency with classic GUI transactions!

 

Limitations of the BASE Transaction Model

While this post might appear to be an indictment on the BASE transaction model, that's not my intention here. I think it definitely has a place for many types of applications. The problem(s) I see when it comes to the development of complex CRUD applications is that the onus for maintaining consistency falls to the application developer.

 

To put this into perspective, consider the time sheet application noted earlier. Had the SaaS vendor wanted to, they could have tracked changes to time sheets via their RESTful APIs using ETags, etc. In this case, if two users were to access the same time sheet and they both tried to make updates, it would have been possible for the system to alert the second user to the fact that their data was stale before overwriting the first user's changes. This is all very doable and SAP Gateway even makes it pretty easy to generate ETags with OData services, for instance. The challenge I see is that the UI layer has to assume a lot of responsibility to a) track the changes and b) figure out what to do whenever there are collisions. For instance, in the example scenario would the system have to re-fetch the updated time sheet and somehow try to merge the 2nd user's changes? This all gets very messy in a hurry. In my mind, it's much better to place a lock on the front door and never allow two or more users to get into this mess in the first place.

 

With that being said, my open question to the community is this: does it make sense to introduce some kind of RESTful service that provides access to lock resources (e.g. enqueue locks on the AS ABAP)? Here, the idea is to use this service to implement logical locks that protected resources from concurrent access, etc. The downside on this of course is dealing with situations where auto-lock clearing fails for some reason and you end up with invalid locks. This issue would likely be more pronounced than what you currently see with server-side apps such as Web Dynpro ABAP or BSPs, but what's the alternative? Is there a best practice out there to deal with concurrent access issues in client-side SPA apps?

 

Gap #2: What about resource-level security?

As the SAPUI5 library has matured, we've seen the concept of routing expand/evolve into something that's pretty robust. However, to date, the examples I've seen have implicitly assumed that a user has access to any of the routes defined within the SPA app. Now, part of this might be due to the fact that the Fiori 1-1-3 principle (e.g. 1 user, 1 scenario, 3 screens) sort of implies that perhaps an application shouldn't require resource-level restrictions, but I think the use case still exists. In server-side models, we could easily restrict access to specific pages and even content within those pages.

 

So, my question here is this: what is the best practice for controlling this kind of access? Do we implement a RESTful service to perform authorization checks and integrate it into our router/controller logic? Something else?

 

Gap #3: What about Dynamic Field Properties/Validations?

Frequently, I run into use cases where there are requirements to conditionally show/hide and/or enable/disable fields. In these scenarios, it's often the case that such rules are dynamic and may involve some fairly complex business logic. In keeping with the old adage of "find what varies, and encapsulate it", I think it's obvious that we need to abstract this functionality somehow. The question is where?

 

In server-side models, this kind of logic typically exists centrally within business objects in the model layer. For example, I've recently worked pretty extensively with Web Dynpro/FPM applications which are built on top of the Business Object Processing Framework (BOPF). Here, the BOPF object model defines node-level properties which can be bound to UI elements quite easily. At runtime, user input is constantly being synchronized with BO instances in shared memory via server roundtrips and so the property updates can take place centrally without requiring any custom logic in the UI/view layer. The downside from a UX perspective is that the user has to incur a server roundtrip for some of the UI updates to take place.

 

If we contrast this with client-side models, we have RESTful/OData service-based models which supply the data, but there's no natural mechanism for synchronizing field properties. In a couple of instances, I've created separate RESTful services to feed this data to the UI layer out-of-band, but that feels like a hack. On the other hand, I'm very hesitant to integrate this logic into SAPUI5 controller classes, etc. If I go to the trouble of building out things like mandatory field checks, consistency checks, and so forth within my OData services, I don't want to have to replicate that same logic upstream.

 

Has anyone encountered/developed a framework for something like this? This feels to me like an important gap that calls for framework-level support. Another thought that popped into my head is whether or not this is another kind of operation that should be provided in OData? In other words, besides your normal CRUD+Q, you have CRUD+Q+V, where V stands for validation of a given entity(set). This might be too crazy though.

 

Closing Thoughts

In closing, I hope the community will (forgive?) indulge me with my open questions here. I hope this post might spark some lively conversation and maybe get to the bottom of some pesky issues that I know I'm not alone on.


Play time!!!!!!

$
0
0

Hi All,

 

This is my first blog in SAPUI5 community. Hope all people will like this blog.

 

I start building this application just for fun but now I want to share with all my developer friends.

 

It's a Sudoku game with 4 and 9 grid matrix options.

 

sudoku1.jpg

 

 

Based on selected matrix, the respective cell matrix will display in page to set initial values.

 

sudoku2.jpg

 

 

Set some initial value in cells ( for example : refer below screen)

    sudoku3.jpg

Note: Depends on selected matrix, any one of cell should be filled with respect to Box. In above case, four box are filled with some values.

 

After fill initial values, select "SET INITIAL" button to set initial values. ( As we see in Sudoku screen).

 

      sudoku4.jpg

 

By pressing "SET INITIAL" button, more three button will display (as above screen) and SET INITIAL button will disappear. And all set cells values field will be disable to stop changing values.

 

Now Sudoku is ready to play.

 

After fill the all cell. User can use "CHECK" button to validate result.(As per sudoku rules).

          sudoku5.jpg

 

Whenever an error found, system will display the respective error row or column information.( as above screen). If no error found then a Success message will display. (Below screen).

            sudoku6.jpg

 

In above screen three more option exist, Refresh, Show Result and Reset.

 

By use of REFRESH option, user can make the play matrix as same like initial stage. It will clear the all entered and set values. And only two option will display in screen, SET INITIAL and REFRESH.

 

 

By use of RESET option, user can reset the play board same as after selected SET INITIAL option.

 

And finally SHOW RESULT option, by use this option, user can see the final result of set Play board.

Note: Sudoku is pure mind game and users follow some trick to get the final result. I have followed some of the tricks to fill the final result based on initial values. If someone found it's not working for any Set Value, please forward the initial value chart to me.

 

To direct play the game use below link, use your scn login credential to login into game.

 

Play Sudoku

 

For my developer friends, the all program and other files are in can be download from below link.

 

GitHub - Sudoku: Sudoku game in SAPUI5

 

NOTE:  Game will display good and aligned in Chrome browser.

 

 

 

Best of luck..

 

Praveer Kumar Sen

Grunt plugin to upload UI5 sources to NetWeaver ABAP

$
0
0

 

Intro

At the moment of writing this post in the UI5 projects I am involved there is always the discussion which IDE should be used. SAP Web IDE would be of course the best choice in most cases, but many customers are still somehow reserved regarding web based tools in the Cloud and storing the sources not on own servers. There are solutions for such problems, but they are still some kind of a workaround. Another gap of SAP Web IDE are the missing Continuous Integration and Continuous Delivery options at the moment (this gap will be closed in the next few month according to SAP). Beside SAP Web IDE the next choice we have for UI5 development is Eclipse with the UI development toolkit for HTML5. But hopefully everyone agrees, Eclipse is not really an IDE for JavaScript development (not fast, code completion slow and buggy, ...). The advantages of Eclipse are the SAPUI5 ABAP Repository Team provider which comes with the UI5 plugin and to work with an on-premise Git repository. Due to the described reservations of customers and behaviors of the IDEs (especially Eclipse) in many cases the projects decide to use another JavaScript IDE (for instance WebStorm) to implement their openUI5 and SAPUI5 apps. But there is still a gap in the process. The chosen IDE does not support the deployment of the UI5 sources to the NetWeaver ABAP system if the apps should be executed on such a system, neither directly from the IDE nor from a CI server. To close that gap, the closest solution was to create a Grunt plugin which does the job. Nearly each project uses Grunt (or Gulp which can also call Grunt tasks via a special plugin), so that the integration of the additional task is very easy (either directly in the IDE or in a project of a CI server).

 

Grunt Plugin "grunt-nwabap-ui5uploader"

The Grunt plugin which does the upload job is called "grunt-nwabap-ui5uploader". The plugin does following things:

  • Create BSP container if not already available.
  • Synchronize folders between local project and the BSP container (create new folders, delete removed folders).
  • Synchronize files between local project and the BSP container (create new files, delete removed files, update changed files).

The sources and documentation are available at GitHub - pfefferf/grunt-nwabap-ui5uploader.

 

The pre-conditions for the usage are:

  • Node.js must be installed (>= 0.12.10).
  • Grunt's command line interface must be installed globally (npm install -g grunt-cli).
  • Grunt must be installed for the project (npm install grunt --save-dev).
  • On the NetWeaver ABAP system the ABAP Development Tool services must be activated (transaction SICF, path /sap/bc/adt) and the user must have the necessary rights to use the tools and to create/modify BSP containers which acts as UI5 repositories.The plugin was tested with a NW 7.40 and NW 7.50 system.

 

To install the plugin just follow the steps described on Github. When the plugin is installed the configuration and registration of the upload task can be implemented in the "Gruntfile.js" of your project.

 

Here is a little sample project containing a UI5 app (based on UI5 1.28, so no manifest.json) to illustrate the setup. All UI5 app relevant objects are contained in folder "webapp".

00_project_webstorm.JPG

In the following Grunt file there is just a task "nwabap_ui5uploader" defined which describes that all files in the "webapp" folder should be uploaded to a BSP container "ZZ_UI5_DEMO_AP1" in package "ZZ_UI5_UP_DEMO". For simplicity reasons in that example the whole content of the "webapp" folder is uploaded. In real life projects several "build steps" would create an optimized version of the coding stored in a separate folder, for instance "build". In that case of course the optimized coding has to be uploaded.

Because the changes are tracked, a transport number is also defined. It is also possible to upload the sources as "local objects" into the "$TMP" package without transport number. To avoid that the user name and password for the NetWeaver server are stored in the file, they are passed as command line arguments which are fetched using grunt.option().

This is a very simplified Grunt file to set the focus only on the plugin, but in real scenarios there are of course some additional tasks for linting, UI5 preload component creation, test and many more.

01_gruntfile.JPG

 

Usage scenarios

After the upload task in the Grunt file is defined it is ready to use. Following two sample scenarios shows how it can be used.

 

Direct upload to NW ABAP

This first example is for developers who do "single man" projects or who wanna test their implementation directly on the NetWeaver server in for instance a BSP container assigned to the "$TMP" package.

 

In a console for the project folder the developer just have to run the following command.

grunt --user=myuser --pwd=mypassword

Before the execution the target package is empty.

02_empty_package.JPG

 

The console display which actions are done for which folders and files. In that example only "create" operations are done, but if you later change or delete files or folders the corresponding actions are displayed also in the log.

03_console_log.png

 

Afterwards the BSP container and the UI5 sources are available in the package.

03_filled_package.JPG

Testing the app via calling "index.html" file shows that the upload worked.

05_test_app.png

 

Integration into Continuous Integration/Continuous Delivery environment

The scenario to integrate the upload/deployment step for an UI5 app in a CI/CD environment is the most interesting for me. In a CI/CD project there are several build steps defined (e.g. static code checks, execution of tests). If all steps are processed successfully the sources should be uploaded to the NetWeaver ABAP server by calling the defined Grunt task.

 

For demo purposes I created for the above described UI5 project a Jenkins project pointing to the Git repository of the UI5 project. The configuration executes an "npm update" step to install/update the Node.js plugins necessary for the node related steps. Afterwards the grunt nwabap_ui5uploader step is executed which triggers the deployment of the sources to the NetWeaver ABAP server. To avoid to directly enter the password in the console step I used the "Masked Passwords" plugin. With that plugin a variable NWABAP_PWD is defined with the masked password. This variable is then addressed with "%NWABAP_PWD%" to provide the password for the grunt task execution.

06_jenkins_config.png

 

If the build is successful, in the Jenkins build log also the action steps of the upload task can be found. To see a difference to the example before I deleted the folder "test" containing file "test.txt" in the "controller" folder. The started build was successful and in the console output of the Jenkins build the following information can be found.

07_jenkins_log.png

 

And of course the BSP container is updated, that means the file and the folder removed from the Git repository were deleted on the NetWeaver ABAP server too.

08_updated_bsp_contaienr.png

 

Conclusion

With that plugin it is a lot easier for me to setup my development environment for UI5 projects regarding the choice of the IDE and the integration into a Continuous Integration and Continuous Delivery infrastructure. There are so many other Grunt plugins which can be combined in such an environment to help to improve the quality of the source code and to the improve the efficiency of a developer. In case you try out the plugin and find some bugs, please report it via GitHub please.

Combination Chart using sap.makit library

$
0
0

Combination charts allow multiple layers of a graph to share the same category, but have their own values and series grouped and drawn in different styles.

A combination chart consist of two components:

  • sap.makit/CombinationChart control
  • sap.makit/Layer element

To create a combination chart, create a CombinationChart control and add multiple Layer elements. TheCombinationChart control serves as a container for the combination chart and multiple charts are added by means of 'layers' aggregation: each chart in the CombinationChart is represented by the Layer object. TheCombinationChart control contains all the properties, aggregations, events, and methods that are shared by all layers.

Steps

  1. Load sapui5 and add makit library
  2. Get the Data.I am using custom data.data should be like this1.PNG
  3. Create CombinationChart control and define categoryRegions

2.PNG

     4.Create Layers.

3.PNG

 

     5.Add columns

4.PNG

     6.Bind data to layers

5.PNG

     7.Add layers to combination chart.

6.PNG

     8.Add combination chart to Page and add page to App control.

7.PNG

 

For more information visit blog SAPUI5 Charts:Combination chart using sap.makit library | sap abap | sapui5 made easy

Using the SAPUI5 UploadCollection to upload/download ArchiveLink files via Gateway

$
0
0

First off, disclaimer: this blog post contains my views only and are not reflective of my employer or anyone else. Now that's out of the way, we can begin!

 

I was asked to build a prototype UI5 application where the user can view and download existing attachments for an ISU business partner from ArchiveLink, as well as upload them. In the process of researching the prototype, I came across many helpful blogs, but I thought I’d also share my experience since I haven’t seen my particular scenario documented end to end.

 

The requirement to get and create attachments in ArchiveLink is not new, so I won’t really dwell on that. Instead I will be focusing on how it all hangs together, and the tweaking I had to do to deal with the ever so temperamental UploadCollection.

 

First things first. I had to build RFC function modules (I know, gross) because the system I had to work with is pre NW 7.31. Normally it would be a clean Gateway hub scenario (where the data retrieval would be written in the ECC Gateway service and consumed by the hub), but in my case I’m calling the function modules in ECC from the hub Gateway service. These function modules are pretty much just wrappers that are RFC enabled and call the standard ArchiveLink function modules, such as  ARCHIV_GET_CONNECTIONS,  ARCHIVOBJECT_GET_URI,  ARCHIVOBJECT_GET_TABLE, etc.

 

The next step was to build the Gateway service. This was pretty straightforward too, with just some tweaks to handle media types and streams. I basically had a Customer entity (unfortunately everything is in German but you’ll get the gist) which has an association with a CustomerFile entity. It’s via the CustomerFile entity that we can retrieve the value stream of the file, as well as perform the upload. In particular, note that for this to work, you need to set the entity that is handling the file content as a media type (see the checkbox below).

 

2016-03-29 09_24_11-SAP Gateway Service Builder.png

2016-03-29 09_55_36-SAP Gateway Service Builder.png

 

Other than that, the rest is as per any Gateway Service Builder project. After generating the classes and runtime objects, the next step was to redefine the methods required to handle the upload and download of content streams. I referred a lot this amazing blog by Peter Marcely, which also includes handy code snippets. You can find my code snippets below for the methods that I needed to redefine:

 

<Your model extension class>-DEFINE

METHOD define.

  super->define( ).

 

  DATA:

    lo_entity  TYPE REF TO /iwbep/if_mgw_odata_entity_typ,

    lo_property TYPE REF TO /iwbep/if_mgw_odata_property.

 

  lo_entity = model->get_entity_type( iv_entity_name = 'KUNDEN_AKTE' ).

 

  IF lo_entity IS BOUND.

    lo_property = lo_entity->get_property( iv_property_name = 'Mimetype' ).

    lo_property->set_as_content_type( ).

  ENDIF.

ENDMETHOD.

 

 

/IWBEP/IF_MGW_APPL_SRV_RUNTIME~GET_STREAM (note: I didn't really need this for the UploadCollection as the URL is used to retrieve the document, but this was useful for testing. If you need to embed the content of the file, say in an image control then this would be useful).

METHOD /iwbep/if_mgw_appl_srv_runtime~get_stream.

 

  DATA: ls_key        TYPE /iwbep/s_mgw_name_value_pair,

        lv_gp_id      TYPE saeobjid,

        lv_doc_id    TYPE SAEARDOID,

        ls_lheader    TYPE ihttpnvp,

        ls_doc        TYPE zrcm_gw_file_info,

        lt_docs      TYPE TABLE OF zrcm_gw_file_info,

        ls_stream    TYPE ty_s_media_resource,

        lv_filename  TYPE string.

 

  CASE iv_entity_name.

    WHEN 'KUNDEN_AKTE'.

 

      READ TABLE it_key_tab WITH KEY name = 'GP_ID' INTO ls_key.

      lv_gp_id = ls_key-value.


      clear: ls_key.

      READ TABLE it_key_tab WITH KEY name = 'Arc_Doc_Id' INTO ls_key.

      lv_doc_id = ls_key-value.

 

 

      CALL FUNCTION 'ZRCM_GW_READ_DOCUMENTS' DESTINATION <ECC_Destination>

        EXPORTING

          obj_id    = lv_gp_id

          sap_obj  = 'BUS1006'

        IMPORTING

          dokumente = lt_docs.

 

 

      READ TABLE lt_docs INTO ls_doc WITH KEY object_id = lv_gp_id arc_doc_id = lv_doc_id.

 

      ls_stream-value = ls_doc-content.

      ls_stream-mime_type = ls_doc-mimetype.

 

      lv_filename = ls_doc-arc_doc_id.

      lv_filename = escape( val = lv_filename

                            format = cl_abap_format=>e_url ).

 

 

      ls_lheader-name = 'Content-Disposition'.

      ls_lheader-value = '|inline; Filename="{ lv_filename }"|'.

      set_header( is_header = ls_lheader ).

 

      copy_data_to_ref( EXPORTING is_data = ls_stream

                        CHANGING  cr_data = er_stream ).

  ENDCASE.

 

 

ENDMETHOD.



/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CREATE_STREAM

METHOD /iwbep/if_mgw_appl_srv_runtime~create_stream.

  DATA: ls_key_tab    TYPE /iwbep/s_mgw_name_value_pair,

        lt_key_tab    TYPE /iwbep/t_mgw_name_value_pair,

        ls_doc        TYPE toadt,

        ls_return    TYPE bapireturn1,

        ls_kundenakte TYPE zcl_zrcm_verbindung_mpc=>ts_kunden_akte,

        lv_error      TYPE string,

        lv_filename  TYPE toaat-filename,

        lv_mimetype  TYPE w3conttype,

        lv_gp_id      TYPE char10.

 

  CASE iv_entity_name.

    WHEN 'KUNDEN_AKTE'.

      READ TABLE it_key_tab WITH KEY name = 'GP_ID' INTO ls_key_tab.

      lv_gp_id = ls_key_tab-value.

 

      lv_mimetype = is_media_resource-mime_type.

      REPLACE ALL OCCURRENCES OF '#' IN lv_mimetype WITH space.

 

      lv_filename = iv_slug.

      REPLACE ALL OCCURRENCES OF '#' IN lv_filename WITH space.

 

      CALL FUNCTION 'ZRCM_GW_STORE_DOCUMENT' DESTINATION <ECC_Destination>

        EXPORTING

          ar_object  = '/BME/V0043'

          object_id  = lv_gp_id

          sap_object = 'BUS1006'

          doc_type  = lv_mimetype

          document  = is_media_resource-value

          filename  = lv_filename

        IMPORTING

          outdoc    = ls_doc

          return    = ls_return.

 

      IF ls_return-type = 'E'.

        lv_error = ls_return-message.

        RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception

              EXPORTING

                textid            = /iwbep/cx_mgw_busi_exception=>business_error_unlimited

                message_unlimited = lv_error.

      ELSE.

 

        ls_kundenakte-arc_doc_id = ls_doc-arc_doc_id.

        ls_kundenakte-filename = iv_slug.

        ls_kundenakte-mimetype = is_media_resource-mime_type.

        ls_kundenakte-gp_id = lv_gp_id.

 

        kunden_akteset_get_entity(

          EXPORTING

            iv_entity_name    = iv_entity_name

            iv_entity_set_name = iv_entity_set_name

            iv_source_name    = iv_source_name

            it_key_tab        = it_key_tab

            it_navigation_path = it_navigation_path

          IMPORTING

            er_entity          = ls_kundenakte ).

 

        copy_data_to_ref( EXPORTING is_data = ls_kundenakte

                          CHANGING  cr_data = er_entity ).

 

      ENDIF.

  ENDCASE.

ENDMETHOD.

 


KUNDEN_AKTESET_GET_ENTITY

METHOD kunden_akteset_get_entity.

  DATA: ls_key        TYPE /iwbep/s_mgw_name_value_pair,

        lv_arc_doc_id  TYPE string,

        lv_gp_id      TYPE saeobjid,

        lv_content    TYPE xstring,

        lv_bin_length TYPE sapb-length,

        ls_doc        TYPE zrcm_gw_file_info,

        lt_docs      TYPE TABLE OF zrcm_gw_file_info.

 

  READ TABLE it_key_tab WITH KEY name = 'GP_ID' INTO ls_key.

  lv_gp_id = ls_key-value.

 

  CLEAR: ls_key.

  READ TABLE it_key_tab WITH KEY name = 'Arc_Doc_Id' INTO ls_key.

  lv_arc_doc_id = ls_key-value.

 

  CHECK lv_gp_id IS NOT INITIAL AND lv_arc_doc_id IS NOT INITIAL.

 

  CALL FUNCTION 'ZRCM_GW_READ_DOCUMENTS' DESTINATION <ECC_Destination>

    EXPORTING

      obj_id    = lv_gp_id

      sap_obj  = 'BUS1006'

    IMPORTING

      dokumente = lt_docs.

 

  READ TABLE lt_docs INTO ls_doc WITH KEY arc_doc_id = lv_arc_doc_id.

 

  MOVE-CORRESPONDING ls_doc TO er_entity.

 

  er_entity-gp_id = lv_gp_id.

 

ENDMETHOD.

 


This is the POST URL I used to upload some content for testing:


/sap/opu/odata/sap/ZRCM_VERBINDUNG_SRV/KUNDEN_AKTESet('0000208999')/$value


So far, so good.


Next I created a simple UI5 application that allows the user to view the attachments that exist, while also having the ability to upload new ones. The control that made the most sense was UploadCollection, which seems to be relatively new (read: buggy). In principle this was the perfect control for the use case, however when I started using it I realized that it’s still in its developmental stages. I referred to the UploadCollection example in SAPUI5 Explored, but please note that uses hard coded JSON data.

 

First thing I realized is when I disabled instantUpload, I lost the ability to display the existing attachments in a list. The list becomes the waiting area only for the attachments you will be uploading. That was rather annoying, because sometimes you want to check the files before you decide to upload them, as well as being able to see what files already exist. Perhaps this will be improved in a later release, but for now I just had to leave instantUpload on.

 

Another thing I noticed: after the UploadCollection is instantiated, you can no longer set the upload URL dynamically. This means you either hardcode it in the view definition (yuck), or you set it once at initialization, which is what I ended up doing. I find it strange that we are given the setter method, but when you use it after instantiation, you get this error:

 

2016-03-29 10_16_49-Brunata Kunden Akten.png

 

Then there’s the CSRF Token. I get why we need to use these, but to have to set it manually in the code is just mind boggling. Essentially I had to retrieve the CSRF Token in an AJAX call, and store the token to be sent with the upload request. This seems to be the case also with the FileUpload control as there are loads of other posts describing the same workaround. It would be nice if this was all handled automatically in the standard control.

 

The final thing I had to tweak was the completed upload event handler. I expected to have access to the response from the upload request (similar to reading the model) in this event, since it is triggered after a successful upload. Think again. If you leave this method empty, the status of the upload stays at 99% forever. I didn’t really want to rebind the whole UploadCollection aggregation each time an upload is completed, since the list could load quite slowly and appear strange to the user (while a new file is uploading, it appears at the top of the list, but after rebinding it goes somewhere else). In the end I had to resort to rebinding because it was the cleanest way. I added a busy dialog with a delay so the user wouldn’t see the file hop from the top to somewhere else.


Below are some screenshots of the application in action:

2016-03-29 09_49_39-Brunata Kunden Akten.png

2016-03-29 09_51_08-Brunata Kunden Akten.png

2016-03-29 09_51_41-Brunata Kunden Akten.png

Here are the key events for UploadCollection:

onBeforeUploadStarts: function(oEvent) {  // Stellen die Kopf Parameter slug  var oCustomerHeaderSlug = new sap.m.UploadCollectionParameter({  name : "slug",  value : oEvent.getParameter("fileName")  });  oEvent.getParameters().addHeaderParameter(oCustomerHeaderSlug);  _busyDialog.open();  },
onUploadComplete: function(oEvent) {  var sUploadedFile = oEvent.getParameter("files")[0].fileName;  var location = oEvent.getParameter("files")[0].headers.location;  var index = location.indexOf("/KUNDEN_AKTESet");  var path = location.substring(index);  var oCollection = oEvent.getSource();  var collectionPath = "/KUNDENSet('" + _gp_id + "')/AKTEN";  var oTemplate = this.byId(_collectionItemId).clone();  _collectionItemId = oTemplate.getId();  oCollection.bindAggregation("items", {  path: collectionPath,  template: oTemplate  });  setTimeout(function(){  _busyDialog.close();  MessageToast.show(_oBundle.getText("dokumentHochgeladen"));  }, 3000);  },
onChange: function(oEvent) {  // Stellen das CSRF Token wenn ein File hinzugefügt ist  var oUploadCollection = oEvent.getSource();  var oCustomerHeaderToken = new UploadCollectionParameter({  name : "x-csrf-token",  value :  _csrfToken  });  oUploadCollection.addHeaderParameter(oCustomerHeaderToken);
},

 

So there you have it. A few tweaks here and there but now it functions quite well. I hope to see future improvements in this control, as it is quite a handy one, and I'd personally like the methods that are not allowed to be removed (why tease me with something I can't actually use).

 

I hope this post has helped shed some insight if you are looking into the same scenario.

New tutorials! Even more hands-on training material to learn UI5

$
0
0

Last year, we have successfully launched our new online hands-on training material with the Walkthrough Tutorial for UI5 beginners and refreshers. It was a great success: We got very positive feedback, implemented lots of minor changes to make it even better and improved it with new steps.

 

In parallel we started working on a more complex Learning Path to conquer and master UI5 with more advanced tutorial topics. We stick to the same format: a mixture of hands on coding and explanations with small incremental steps based on our best practices and recommendations.

 

As of now 9 tutorials are available to deepen your knowledge in other areas of UI5:

 

 

This learning path gives you an idea of how they all fit together:

loioe32da15e43544f36a30afc480cf3eff9_HiRes.png

 

As usual, you find the documentation and code deltas in the Developer Guide and the running examples in the Explored App. You can download the code for each step as a zip file and import it in SAP Web IDE or other development environments as you wish.

 

Tell us how you like the new tutorial topics and what we can further improve. There is now also a new feedback option included in the Demo Kit (icon below the search icon on the left side).

 

Have fun doing the tutorials and becoming a UI5 expert!

 

Michael
UI5 Development Team

How to create and consume a gateway service via SAPUI5 - Part 1

$
0
0

I intend with this first blog post, to demonstrate how to create a simple gateway service, configure a SAPUI5 project connecting with ABAP Application Server, and consume the created OData Service.

 

This article will be divided in tree parts; in the first one, we will learn how to create a SAPUI5 project using ABAP Application Server to deploy our project.

 

The second part can be found here

 

How to create and consume gateway service via SAPUI5 – Part 2

 

Prerequisites

 

You will need to download and install the following software:

 

  • Eclipse IDE for JEE Developers (Mars or Luna)
  • SAP Development tools for Eclipse
  • SAP Netweaver Gateway on SAP ERP
  • ABAP Application Services

 

First, we need to confirm if the backend system is compatible with SAP Netweaver Gateway. So check if the software components below are installed in your system.

 

 

Sap Netweaver Gateway Server Functionalities

Sap Netweaver Gateway backend enablement

7.31

and earlier

GW_CORE,

IW_FND

IW_BEP

as of 7.40

SAP_GWFND

SAP_GWFND

 

For more information about the components, check this SCN Blog

 

http://scn.sap.com/community/gateway/blog/2013/05/27/sap-netweaver-gateway-deployment-options-in-a-nutshell

http://help.sap.com/saphelp_gateway20sp09/helpdata/en/76/08828d832e4aa78748e9f82204a864/content.htm

 

As we will use ABAP Application Server to deploy our project, check if the Central UI Components below are installed.

 

SAP NW Release

Required Central SAP UI5 Add-On Product Version

Comprised Component Versions

EHP3 FOR SAP NETWEAVER 7.0 (AS ABAP) (minimum support package stack 05, recommended minimum SPS 08) or higher

or

SAP EhP1 for SAP NetWeaver 7.3 or higher

UI ADD-ON 1.0 FOR NW 7.03 (minimum support package stack 10), instances Integration Services: Provider and Integration Services: Libs

SAP UI ADD-ON INFRA V1.0 (UI_INFRA 100), SP10

SAP UI2 SERVICES V1.0 (UI2_SRVC 100), SP10

SAPUI5 CLIENT RT AS ABAP 1.00 (UISAPUI5 100), SP10

SAP UI2 FOUNDATION V1.0 (UI2_FND 100), SP10

SAP UI2 IMPL. FOR NW 7.00 V1.0 (UI2_700 100), SP10

SAP UI2 IMPL. FOR NW 7.01 V1.0 (UI2_701 100), SP10

SAP UI2 IMPL. FOR NW 7.02 V1.0 (UI2_702 100), SP10

SAP UI2 IMPL. FOR NW 7.31 V1.0 (UI2_731 100), SP10

SAP NETWEAVER 7.4 (AS ABAP)

SAP NETWEAVER 7.4 FOR SUITE (AS ABAP)

Minimum support package stack 04 and component SAP_UI 740 SP09 for both.

All required components are included in the SAP NetWeaver 7.4 installation. Verify that the above-mentioned components are in place.

 

 

We will also need the eclipse IDE installed and configured with SAP Development Tools. So, to see how to do this, check these links.

 

https://tools.hana.ondemand.com/

https://help.hana.ondemand.com/help/frameset.htm?76137a37711e1014839a8273b0e91070.html

https://websmp104.sap-ag.de/~sapidb/012006153200000764932012E/adt_731_installation_guide.pdf

 

 

Configuring SAPUI5 Project in Eclipse

 

Let’s start creating our project. First of all, create a new project in Eclipse. Following the steps described below.

  • Access the menu: File -> New -> Project…
  • Select SAPUI Application Development Wizard, see the window below.

 

image1.jpg

  • In the next window, enter a Project name: “HelloOdata”, mark the options "sap.ui.commons Library" and "create an initial view".

image2.jpg

  • Now, inform the view name “airline”, and development paradigm “JavaScript”, and then click in the Finish button.

image3.jpg

  • See in the image below how the project structure should look like.

image4.jpg

Connecting the project with SAP ABAP Application Server

 

Now we will connect our project with SAP Application Server. To do this, proceed with the next steps:

 

  • Right click on project name, in the context menu, select Team -> Share Project…

image5.jpg

  • Next window select SAPUI5 Abap Repsitory

image6.jpg

  • Select the connection to a SAP System. Click "Browse" and select the appropriate connection.

image7.jpg

  • Then connect to your SAP system, entering your username and password.

image8.jpg

  • Now Select "Create a new BSP Application", enter a name, description and package. You need to give Z* name to your BSP application. You can also browse package and select required package in which you want to save your BSP application.

image9.jpg

  • Create a new request or select one in the list. Then click Finish.

image10.jpg

  • If you receive a version check message, click OK.

image11.jpg

  • Your project will look like this.

image12.jpg

Publishing and testing your application

 

  • With the project connected with the ABAP server, now let's publish and test.
  • First, we will submit our project. Right click on your project name, select Team -> Submit…

image13.jpg

  • In the next window, leave everything as it is and click Finish.

image14.jpg

  • To test, right click in your project name, select Run as, Run on ABAP Server.

image15.jpg

  • A new tab will open, with a blank page. You can use the url in your browser, or test directly in Eclipse.

image16.jpg

 

In the next blog post, we will see how to create a OData service using SAP Netweaver Gateway, and in the third part of the series, we will consume the OData service in our application.

How to create and consume gateway service via SAPUI5 – Part 2

$
0
0

This blog post is a continuation of a series of tree posts, about how to create and consume gateway service, the first one can be found here:

 

http://scn.sap.com/community/developer-center/front-end/blog/2016/03/29/how-to-create-and-consume-a-gateway-service-via-sapui5--part-1


All the prerequisites are listed in previews article, please read the first part before you continue.

 

In this second part, we will see how to create an OData service that will be used in the SAPUI5 application.

 

Let´s start...

 

 

Creating OData Service

 

To create the Odata service we need to access the SEGW transaction, and proceed with a few steps:

 

  • Access SEGW transaction, you will enter Sap Netweaver Gateway Service Builder.
  • Start by creating a new project, to do this, click in “New Project”.

 

image1.jpg

 

  • In "Create Project" window, enter the project name “ZHelloOData”, description “Hello Odata Service” and inform your Z package under Package.

 

image2.jpg

 

 

  • After creating the project, your project structure will look like the one in the image below.

 

image3.jpg

 

  • Next you need to create a service based in the SCARR table. To do this, right click on “Data Model” folder, choose Import->DDIC Structure.

 

image4.jpg

 

  • A wizard window will be displayed, in the first step, enter the Name “SCARR” and in ABAP Structure, enter SCARR again. Check if “Create Default Entity Set” is marked. When done, click on the Next button.

 

image5.jpg

 

  • In the next step, mark all of the checkboxes and then click in Next again.

 

image6.jpg

  • In the last step, choose the key fields, according to the image below, and then click in Finish.

 

image7.jpg

 

  • After these tree steps, the project will look like that:

 

image8.jpg

 

  • Now let´s generate the Runtime objects. Click in the button marked below.

 

image9.jpg

 

  • The popup window for choosing the appropriate request will be displayed, select the same request which we used in the first tutorial, or create a new one if you prefer.

 

image10.jpg

 

  • In the next step, it will be displayed the "Model and Service Definition" window, keep all of the fields as it is suggested and confirm.

 

image11.jpg

 

  • Then, choose your Z package and a request again.

 

image12.jpg

 

  • At the end of these steps, the "Runtimes Artifacts" will be generated. See the image below and confirm if everything is OK.

 

image13.jpg

 

 

Registering and testing the Service

 

Now we are going to register the service and make a first test. Please proceed with the following steps:

 

  • Double click on the "Service Maintenance" node, and then click "Register". See the image below.

 

image14.jpg

 

  • In the "Add Service" window, we have to keep all the values as suggested, entering only the package name. Then click "Continue". Check the image below.

 

image15.jpg

 

  • Next inform your previously created request.
  • If everything is OK you will have a green light in "Registration Status".

 

image16.jpg

 

  • With everything OK, you can go to "Gateway Client" and test the recently created service. Click in "Gateway Client".

 

image17.jpg

 

  • A new window will be displayed. To test, click on the "Execute" button and then check if the HTTP response has the code 200. Confirm the link to your service, you will need this link in the third part of this article. This link is used to access our recently created service.
  • You can also check the results in your browser, entering the URL marked below.

 

image18.jpg

 

Developing the Service Implementation

 

  • Now we are going to develop the service to query the results of the SCARR table. Let’s return to Sap Netweaver Service Builder (SEGW).

 

  • First, open the "Service Implementation" tree structure. Then, right click on "GetEntitySet (Query)" and choose “Go to ABAP Workbench”. See the example in the image below.

 

image19.jpg

 

  • In the popup click in Yes, then confirm the creation of the implementation.

 

image20.jpg

 

  • The ABAP workbench will be displayed, then open the SCARRSET_GET_ENTITYSET method. Then, confirm the creation of the method.

 

image21.jpg

image22.jpg

 

  • Now let´s implement the code to select data from SCARR table. See the image below, and activate the objects.

 

image23.jpg

 

  • For a final test, open the Gateway Client again, click in execute and check the name of the collection created. You can also do this, informing the URL in you browser.

 

image24.jpg

 

  • With the collection name, we need to change the URL to test if the results will be displayed.

image25.jpg

 

 

 

Well, we finish the second part here, in the last part of this series we are going to consume the service created in this article in a SAPUI5 application.

See you in the next post!

 

Regards, Balbino.


Mobile Application using WEBIDE with custom SQL C# OData Service - Part1

$
0
0

There are many blogs/tutorials on scn which will help to set up trial account on the web and get started with SAP or Nothwind odata services – If you are a single developer who wants to develop a mobile app using WEBIDE which does not use SAP there are things we are have to do – this blog examines and explains how to go about this process.

1)      Develop a Custom Odata Service which initially runs on your lap top and later can be moved to the cloud – for this we use the develop a Custom Odata service from Northwind database and deploy it on IIS and use this in the mobile App development. It is assumed that you have installed HAT and tested your configuration.

2)      Install HANA cloud connector on your lap top – Again there are many documents on scn and this is not covered here – just note that after you install – you have to include the IIS path the hcc.

 

In this blog we Cover the steps to  Create a Custom Odata Service on SQL Server and deploy it on IIS using Visual Stuido and set up the destination in WEBIDE which will enable us to start the application development described in Part 2.

1)      Start Visual Studio 2013 and Create a new Web Project (empty)– Call it NorthData

image1.png

    2)      Right Click on the Project and choose add new item and then choose Data and ADO.NET

Choose EF designer from Database – Then Select Next – Create a new Connection to the Northwind Database on your local SQL Server – Test the Connetion – on the next screen choose

Entity Frame work 5.0 – Next Screen choose the tables/views/stored procedures that you will use and finish - Build the Project

3) Right Click on the Project  New Item and then and choose web- WCF Data Service 5.6 and type NorthwindData.svc and click Finish

open the file NorthwindData.svc.cs and make the following changes to make the file appear as below

public class NorthwindData : DataService<NorthwindEntities>

    {

        // This method is called only once to initialize service-wide policies.

        public static void InitializeService(DataServiceConfiguration config)

        {

            // TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.

            // Examples:

            config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);

             config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);

            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;

        }

    }


NorthwindEntites is created in the webconfig file when you created the SQL Connectioin - The "*" in the config will ensure that you access any table and perform CURD on any table.

   4) Build the project and Publish to the local IIS - After Building right click on the project and choose publish - Create Custom settings and enter shown

image4.png

and Publish

image4.png

5) Start IIS and select NorthData - From the Middle Pane - select Directory Browsing and from the right pane choose Enable so that this service can be used

6) Enable Pass Through for IP address for localhost - When using Webide you cannot use localhost - we have to use ipaddress - To Get the ip address - Go to Control Panel , Windows Firewall ,  Advanced settings, Inbound Rules , New Rule, Select port, TCP, your port number and save it

7) Download and install the Cloud Connector - This is widely covered and is not discussed here - Login to Cloud Connector and make sure that the path for your odata service is allowed from the Connector

 

image5.png


The final Step is this process is to create a destination in WEBIDE - log on to hana cloud trial account and Create a destination - Again this process is well documented - Here we create a destination for this local ip address and check connectivity

image6.png

Click on the Check Connection to make sure the destination is set up correctly - Some times Cloud connector and time out - make sure that this is not case - now we are set to start the application development using SAP WEBIDE which is covered n the next part.

Deploying UI5: Mapping the solution and scenarios

$
0
0

In the first blog of this series I just got you interested, dangled out the technology choises and why this whole approach is good.

 

Now lets look at the different deployment scenarios depending on your setup.

 

HCP - All in the cloud

In this scenario you are devloping and deploying in the HCP cloud. This is probably the best as it is a simple 'Deploy' button. Ideal. I am not sure though that you get any minification or creation of dbg sources or any of the other goodies I talked about in my first blog. This is more than likely on the roadmap but I am not sure if this is there yet. Perhaps you can enlighten me I will certainly update it.

 

This scenario looks like this:

hcp.png

 

All in the cloud.

 

Local development with Git

 

This scenario is one that I have used on several clients and I know that others use it too. Source code is developed locally and commited to github or similar in the cloud. Testing is done on local servers with tunnels to odata sources. I mentioned that Graham Robinson's deployer was an inspiration to this series and this is pretty much what is happening in this scenario.

 

It looks like this:

git.local.png

 

 

 

All in the firewall

The scenario we are going to focus on mostly in this series is this one. All in the firewall on 'On premise' as you cloudy types like to say.

source control, developement workstations and the odata sources all are in the firewall and there will be no naughty touching any fluffy cloudy services thank you very much.

 

As expected it looks like this:

on-prem.png

 

Local Deployment

 

So with local development you have a little bit more of the control of having the basis people open up ports and trust the source control server and do something very similar to what Graham achieved with his Git and Local development. But basis people being basis people instead of going for a deploy on push to source control (ideal) I am going for a push to Gateway. I can contol this a little more because I am going to carefully refactor (hack) a local copy of the /UI5/UI5_REPOSITORY_LOAD_HTTP function module to accept a zip file that I will prepare with grunt.

 

solution.png

 

You should note that we have all our projects / apps under one big folder. Normally I am an advocate of one rep per app but in this scenario we didn't have that control over the source control and it made things simpler for our cross-app navigation. As bonus I found a grunt package that enabled me to create one grunt file and then have one project.json file that pointed to that grunt file to avoid repeating all the build steps for each project aka app.

 

The simple folder layout looks like this:

projects.png

 

Right, so now we are done with all the introductiony stuff. Next time we will get our grunt on.

 

 

<-- Previous blog: Introduction   Next blog : Getting our Grunt on -->

Creating APK file using Cordova

$
0
0

Its a good news for UI5 Developers that, the developed application can be deployed in their own Android Mobile.

 

Below are the steps needed to be followed.

 

1. Install the node.js server to your machine.

 

2. Then move to your command prompt and type npm install -g cordova

 

3. We need to create an cordova application, to do so type cordova create YourAppName

 

4. Move to the application you created just now and type cordova platform add android

 

5. Copy your UI5 Application and replace it in your Cordova Application(platforms -> android -> assets -> www)

 

6. Go back to cmd and type cordova build.

 

7. Your apk file will be generated. Copy the apk place in your mobile and install it.

 

Your can view your application.

 

 

 

 

To know more info about cordova click here

Know about UI5 index.html file

$
0
0

<!DOCTYPE HTML>

<html>

  <head>

  <meta http-equiv="X-UA-Compatible" content="IE=edge">

  <meta http-equiv='Content-Type' content='text/html;charset=UTF-8'/>

  <title>Name Your App</title>

  <script src="resources/sap-ui-core.js"

             id="sap-ui-bootstrap"

            data-sap-ui-libs="sap.m"

            data-sap-ui-theme="sap_bluecrystal"

            data-sap-ui-xx-bindingSyntax="complex"

            data-sap-ui-resourceroots='{ "sap.ui.namespace": "./"}'>

  </script>

  <script>

  new sap.ui.core.ComponentContainer({

                      name : "sap.ui.namespace"

                      }).placeAt("content");

  </script>

  </head>

  <body class="sapUiBody" role="application">

  <div id="content"></div>

  </body>

</html>

 

The UI5 application, gets initialized from it index.html file. Here in this blog I would like to highlight the main function of each field.

 

The first line which gets executed here is called bootstraping, it initializes the sap.ui core libraries.

 

data-sap-ui-libs - The required libraries has be declared here like sap.m, sap.ui.commons, sap.ui.layout and so on

 

data-sap-ui-theme - This is the place where you can mention the look and feel of your application. By default the  theme is Blue Crystal. We have few other theme like Gold Reflection and High Contrast

 

data-sap-ui-xx-bindingSyntax - If you need to bind the values within your application like formatter.js, then you need to mention it.


data-sap-ui-resourceroots - The namespace of the application needs to be mentioned  

 

sap.ui.core.ComponentContainer - This part navigates your application to the Component.JS file to get more information

Minimising UI5 app’s footprint to run from an ESP8266

$
0
0

tame-the-phoenix-1.png

 

img1.png

A while back, I sent this twitter message into the Twitter-verse, with the intention to blog shortly after that on how I got UI5 running on an ESP8266. I'm afraid this blog was conceived a bit later than intended, but here it is nevertheless. This blog is about squeezing a UI5 web application, including the UI5 framework into the ROM of an ESP8266 without adding any additional storage. The available memory space for the UI5 app is 3MB, while the UI5 framework alone is actually many times larger than that. But first a little bit on why I wanted this.

 

While I was working on my veranda control box, I was also looking for a way to control it remotely. Of course it would be linked up to my OpenHab home automation system using MQTT, but it's always nice to be able to operate it from a web-page as well. This comes in handy when the MQTT server is not properly setup yet or when the ESP8266 chip can't reach the MQTT server for another reason.

 

It would be easy to build a little UI5 application and get it to run from the ESP8266 while loading the framework from the usual CDN. The files are all static, and the browser takes care of the heavy-lifting when it comes down to a pretty user-interface. The only thing the ESP8266 needs to do is serve some static UI5 application files and serve some JSON/RESTful services that allow the UI5 application to read and change sensors and relays as well as the configuration.

 

It is getting a bit more complicated when the ESP8266 has just been switched on for the first time and doesn't know what WiFi network to connect to yet. When my veranda control box can't connect to the WiFi network, it will switch itself to access point mode. Once it is in access point mode, you could e.g. take out your phone, connect to this access point and run the setup in the browser to reconfigure it. However, when you're connected to WiFi access point of the ESP8266, you won't have access to the internet at the same time, and you won't be able to load the UI5 framework from a CDN. This means that the entire UI5 framework needs to be hosted on the chip as well.

 

That's nice: as the entire UI5 framework is way too big for the ESP8266, there's a challenge! The D1 Mini module has an ESP8266 ESP12 onboard, with has 4MB of flash memory. But not all of it can be used for the UI5 application, as it also needs to host a webserver, MQTT client, Thingspeak client, OTA firmware upgrade, sensor and relay logic, etc. So I though a 3MB / 1MB split would be a fair split: 3MB as SPIFFS filesystem for the UI5 application plus framework and 1MB for the firmware. This translated into PlatformIO's `esp8266.flash.4m.ld` layout. If the filesystem available for the UI5 app is going to be 3MB, this would mean that I would have to bring the size of the UI5 application and framework down to less than 3MB!

 

Performance-wise, it would be a great idea to leverage the '-preload' files as much as possible. It's reduces overhead in the browser, but also from the ESP8266's perspective, it's easier to continue streaming an already opened file than to open another file, and another, and another. Since the preload files contain all modules that a library consists of, leveraging the preload files would be preferred. So let's see what the damage would be in terms of memory usage:

 

img2.png


From these files, I would need the libraries sap.m (1.5M), sap.ui.core (1.1M) and sap.ui.commons (576K), I would need the icons font SAP-icons.ttf (264K), the UI5's core sap-ui-core.js (552K) and some jQuery files (20K), totalling up to approximately 4MB. So, even if I would strip the framework down to the bare minimum, it would already exceed the size of the available ROM, and I haven't even added a theme and my application!

 

To make the framework smaller, it would be necessary to remove modules from the preload files that are not needed by the application. This sounds more daunting than it is, because the library preload files are actually not to difficult to understand. And if you understand how they work, they're also not too difficult to reconstruct, to include only relevant modules. The preload file consists of essentially all of the modules which make up the library. These modules are all minified/compressed and inserted into one file with some metadata wrapped around them. The screen-shot below is an example of such file:

 

img3.png


In the screen-shot, you can see that the file starts with some metadata about the library, but quite quickly starts listing the modules that make up this library. In the screenshot, you can see modules `sap.m.AccButton`, `sap.m.AccButtonRenderer`, `sap.m.ActionListItem` and `sap.m.ActionListItemRenderer`. You can even see that there's some space for improvement if the copyright notices for all modules are removed

 

So, great! Now the only thing I needed to do was to figure out which modules my application uses to be able to reconstruct the library files with only those modules required by my application. The UI5 framework actually offers a very nice feature to figure this out. If you press Ctrl-Alt-Shift-P, a dialog is displayed that gives some insights in the application. Part of this insight is a list of modules that is currently loaded. So if you launch this dialog after running through the functionality of your application, you'll have a list of all module required to run the application:

 

img4.png


I'm interested in the modules that need to be loaded, but I also need to have an overview of what other files I need to get my application to run such as json and css files. This is where the Chrome developer tools come in very handy. After browsing around a little bit, while having the network tab open, I now have a nice collection of all the files that need to be included in the ESP8266's ROM. To be able to automate processing of the contents of the network tab, I have saved the contents as a HAR file, and use tools such as grep to turn it into a packaging script.


img5.png


Once, you have the HAR file, is is quite easy to make a list of all the files required to run the application using command line tools such as grep, cut and sed:


img6.png


The eventual script I generated using the contents of the har file and the contents of UI5's debug dialog can be found here:

https://github.com/jpenninkhof/espardu_devicex/blob/master/build-data.sh

 

In bash this script you can see that almost all files, from both the application and library will be mangled by minifiers. I'm currently using Node.js module 'uglify' for javascript and css files, 'pretty' for xml and json files and 'html-minifier' for html files. After minifying the files, I'm trying to package them up as much as possible into preload files. UI5 framework files go into library preload files, while as many of the application files as possible go into a component preload file.

 

The total size of the application, including the UI5 framework is now...

 

img7.png


A total of 2.2M, which even provides ample room for expansion of the application!

 

If you're interested in what the app currently looks like, have a look at the little demo below:

 

http://i2.wp.com/www.penninkhof.com/wp-content/uploads/2016/03/veranda-control.gif

 

Initially the application will show a dashboard, presenting the relay status, temperature and humidity. When you click on the configuration tile, it will be possible to setup the connection to the WiFi access point, MQTT server and Thingspeak. Clicking on the diagnostics page will bring you to the diagnostics dashboard, showing some internal variable of the ESP8266 such as uptime, voltage and available memory. The time in the right-top corner is the current time, which is quite a challenge on an ESP8266 as it doesn't have a real-time clock built-in (and please don't ask me why the time shows a time after mid-night ;). The icon in the top right indicates whether the web-application is currently connected to the ESP8266. After reconfiguration of the ESP8266, it will reboot and the connection icon will shorty show a disconnected state.

 

As with any OpenUI5 app, the application is fully responsive and plays nicely on Desktop, tablets and phones. UI5 is awesome!

 

The entire firmware, including the app and build script can be found on Github: https://github.com/jpenninkhof/espardu_devicex. The UI5 app is in the webapp directory.

Need help in routing and passing parameters to another view ? Find it here. (Eclipse IDE)

$
0
0

Hello Everyone,

 

In this blog post we will learn how to navigate to a different view through the concept of routing and pass the data/parameters to that view.

Below is the step by step procedure:

  1. Create a new SAPUI5 application project in Eclipse IDE.



  2. In the Create a New View window, provide the initial view name and choose the type of view as XML.




  3. As we require two views to for the navigation, create another view called “SecondView” of the same type (XML).
    Note: Here we require one more view which is a kind of container of all the views in the application. Create one more view and name this view as “MainView”.

  4. After the above steps, we create an initialComponent.jsfile in theWebContentfolder that will hold our application setup. The init function of the component is automatically invoked by SAPUI5when the component is instantiated. Our component inherits from the base classsap.ui.core.UIComponentand it is obligatory to make the super call to theinitfunction of the base class in the overriddeninitmethod.

The structure of the project now looks like :

 

5.  Now, we are ready with the creation of all the files required, let’s go step by step and add the code in these files.

Index.html


On the index page we now instantiate the component instead of the view. The helper method sap.ui.core.ComponentContainer instantiates the component by searching for a Component.js file in the namespace that is passed in as an argument. The component automatically loads the root view that we have defined above and displays it. If you now call the index.html file, the app is now packaged into a UI component.


Note : Please remember to change the path of controller in the views and controllers, since we added a property data-sap-ui-resourceroots='{"NavigationDemo": "./"}'. Append "NavigationDemo." before the already existing path.


FirstView.view.xml

   

<core:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m"        controllerName="NavigationDemo.navigationdemo.FirstView" xmlns:html="http://www.w3.org/1999/xhtml">    <Page title="Navigation Demo">        <content>            <VBox>                <HBox>                    <Label text="Username" class="sapUiSmallMargin" />                    <Input type="Text" placeholder="Enter the username.." id="idUserName" />                </HBox>                <HBox>                    <Label text="Email ID" class="sapUiSmallMargin" />                    <Input type="Email" placeholder="Enter the email id.." id="idEmail"/>                </HBox>                <Button text="Go to the next view" type="Emphasized" class="sapUiSmallMargin" press="onButtonPress"/>            </VBox>        </content>    </Page></core:View>

    FirstView.controller.js


sap.ui.controller("NavigationDemo.navigationdemo.FirstView", {    onInit: function() {    },    onButtonPress: function(){        //Setting the data to the model        var username = this.getView().byId("idUserName").getValue();        var email = this.getView().byId("idEmail").getValue();        this.getView().getModel("Details").setData({            username: username,            email: email            });        //Navigating to second page        var oRouter = sap.ui.core.UIComponent.getRouterFor(this);        oRouter.navTo("secondView");    }
});

     SecondView.view.xml


<core:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"    xmlns="sap.m" controllerName="NavigationDemo.navigationdemo.SecondView"    xmlns:html="http://www.w3.org/1999/xhtml">    <Page title="Navigation Demo - Second View" showNavButton="true"        navButtonPress="onNavBack">        <content>            <VBox>                <Text text="{Details>/username}" class="sapUiSmallMargin" />                <Text text="{Details>/email}" class="sapUiSmallMargin" />            </VBox>        </content>    </Page></core:View>

     SecondView.controller.js


sap.ui.controller("NavigationDemo.navigationdemo.SecondView", {    onNavBack: function(){             //Navigating to second page        var oRouter = sap.ui.core.UIComponent.getRouterFor(this);        oRouter.navTo("firstView");    }
});

     MainView.view.xml

<core:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m"        controllerName="NavigationDemo.navigationdemo.MainView" xmlns:html="http://www.w3.org/1999/xhtml">    <App id="app"></App></core:View>

     Component.js


sap.ui.define([    "sap/ui/core/UIComponent",    "sap/ui/model/json/JSONModel"
], function(UIComponent, JSONModel){    "use strict";    return UIComponent.extend("NavigationDemo.Component",{        metadata: {            "version": "1.0.0",            "rootView": {                viewName: "NavigationDemo.navigationdemo.MainView",                type: sap.ui.core.mvc.ViewType.XML            },            "dependencies": {                "libs": ["sap.ui.core", "sap.m", "sap.ui.layout"]            },            "routing": {                "config": {                    "routerClass": "sap.m.routing.Router",                    "viewType": "XML",                    "viewPath": "NavigationDemo.navigationdemo",                    "controlId": "app",                    "controlAggregation": "pages"                },                  "routes": [                         {                             "pattern": "",                             "name": "firstView",                             "target": "firstView"                         },                         {                             "pattern": "secondView",                             "name": "secondView",                             "target": "secondView"                         }                ],                "targets": {                    "firstView": {                          "viewName": "FirstView"                    },                    "secondView": {                          "viewName": "SecondView"                    }                }            }        },           init: function(){            UIComponent.prototype.init.apply(this, arguments);            this.getRouter().initialize();                   //Creating a JSON model            var oModel = new JSONModel();            this.setModel(oModel,"Details");        }    });
});

Working :


First view :


Second view :


Thank You

 

Happy Coding!


Please provide your valuable feedback.
Ashutosh Hans

How SAPUI5 and OpenUI5 versions are related

$
0
0

Sometimes questions arise how the code contained in SAPUI5 is related to the OpenUI5 code. High-level answers have been given elsewhere and are repeated right below, but there are details that have never really been explained. I'll try to cover them in this blog post.

 

The following has been written before - one can generally say:

  1. the code in OpenUI5 is identical to SAPUI5 (this includes the entire core framework functionality and all the general and important control libraries – the OpenUI5 code developed at GitHub is used as central piece of SAPUI5)
  2. but SAPUI5 contains some additional control libraries (typically ones that are specific to SAP products or use-cases, in some cases due to organization reasons)
  3. and OpenUI5 is Open Source, while SAPUI5 is not (SAPUI5 is not something you can “buy”, though: it’s part of other SAP software/platforms, and a relatively small part of those, so you wouldn’t buy such a platform just to use the additional UI5 libraries)

 

If this already answered your questions: great, have a nice day!

But there are more technical details to this, particularly regarding version numbers and publishing dates, and whoever is interested in these details: please read on!

 

 

 

Which one is published earlier? SAPUI5 or OpenUI5?

Short answer:

OpenUI5

 

Long answer:

OpenUI5 patches and releases are published on http://openui5.org and https://openui5.hana.ondemand.com by the UI5 development team, with no dependencies to other teams or software components, so this usually happens within hours (or rarely a few days) after the release build has been created. SAPUI5 on the other hand is currently not available as a separate download, but part of the mentioned SAP platforms like the SAP HANA Cloud Platform and the NetWeaver ABAP UI Addon. Those have their own release schedules, which introduce some delay. As an example, the HCP version at https://sapui5.hana.ondemand.com is usually updated every two weeks, so 1-2 weeks is a typical delay for a patch release there.

 

In addition, SAP has established a testing/validation process to ensure only high-quality software is released to customers, which adds some delay after a new feature release is built. This means that even when a new release like 1.36 is created internally, it takes several weeks until it is available to customers. In OpenUI5 we also want to ship good quality, so we also wait for this official “go!” and publish a new stable release in sync with (usually at the same day as) the first SAPUI5 shipment for this release. This is why we e.g. published 1.36.5 as first “stable” 1.36 version. In contrast to SAPUI5, however, there are additional preview releases published before this date: those are not guaranteed to be stable but can be used for regression/compatibility testing and for trying new features before they are available in a stable release. The complete list of OpenUI5 versions also offers all preview versions as soon as they are built.

 

So as a summary, new stable releases of UI5 are published as OpenUI5 the same day where also SAPUI5 is delivered in one or another SAP product, but other products may get it later, due to their release schedule, and patch releases of OpenUI5 can be published right away, while the various delivery channels of SAPUI5 may add some delay.

 

 

 

Are the same versions of SAPUI5 and OpenUI5 really the same?

Short answer:

Yes and no.

 

Slightly longer but still pretty short answer:

Yes, patch builds for both are done at the same time from the same codeline, so the common code is identical.

But no: these patch builds with identical content don’t always get the same version numbers.

 

Long answer:

There is something seemingly quirky about version numbers: SAPUI5 does have two version numbers, as can be seen e.g. in the Ctrl-Alt-Shift-P support popup:

 

sapui5-1.28.31.png

 

These two version numbers (“SAPUI5 Version” and “Core Version”) are always roughly the same, but sometimes out of sync by one or two patch revisions. In case of SAPUI5 1.28.31, the core version is behind by one.

This is caused by libraries created by either the core development teams (“Core Version”) or by other contributing teams (“SAPUI5 Version”) requiring additional patches, when other libraries don’t need to be updated. Those libraries with no change get no version increase. This can be seen in more variety in the Ctrl-Alt-Shift-S popup when you scroll down to the “Libraries” section. You see a range of different sub-versions of 1.28:

 

sapui5libversions.png

 

The “SAPUI5 Version” is the one applicable for the entire package, the ”Core version” only for the main libraries developed by the core teams of UI5, like sap.ui.core, sap.m, sap.ui.commons etc. – these are more or less the libraries contained in OpenUI5. The version number used for OpenUI5 always equals the “Core Version”, as you can verify by looking at https://openui5.hana.ondemand.com/1.28.30 in comparison to https://sapui5.hana.ondemand.com/1.28.31, which was depicted above:

 

openui5-1.28.30.png

 

(Yes, this says “SAPUI5”, but it’s a screenshot from the OpenUI5 Ctrl-Alt-Shift-P popup.)

 

You see: the OpenUI5 version 1.28.30 was built at the same day – 7th of March 2016as SAPUI5 1.28.31 and of course from the same codeline. But the latter has core version 1.28.30 and this is (apart from the build date) what lets you relate them to each other.

 

This means SAPUI5 1.28.31 is (in all its core parts) identical to OpenUI5 1.28.30.

 

This also means that SAPUI5 1.28.30 and OpenUI5 1.28.30 do not have an identical core, as they refer to different patches, even though they happen to have the same version number. But this is purely a numbering thing and should not be confused with diverging codelines or changes being applied in either one first.

 

 

Alright… this blog post was about a relatively tiny technical detail, but one that has led to confusion in the past, so I thought it’s not a bad idea to write it down and share...


How to create and consume gateway service via SAPUI5 – Part 3

$
0
0

In this third and last part of this series, we will consume the OData service previously created, using SAPUI5, displaying the query results in a table.

 

We need to use the project created in eclipse in the first part of this series and consume the service created in second part. The part one and two can be found in the following links.

 

How to create and consume a gateway service via SAPUI5 - Part 1

 

How to create and consume gateway service via SAPUI5 – Part 2

 

Let´s change the project according with this example.

 

First, we need to change index.html file, including the sap.ui.table component. See example below.

 

<script src="resources/sap-ui-core.js"        id="sap-ui-bootstrap"        data-sap-ui-libs="sap.ui.commons, sap.ui.table"        data-sap-ui-theme="sap_bluecrystal">  </script>

Now we need to change the controller, including the logic to create a model that will connect to Odata service. In airline.controller.js, create a new method getModel. Here we will inform the url from Odata service which we create in second part of our tutorial. Please check the url created in service and replace in your code.

 

getModel: function(){
// Return model based in OData Service
return new sap.ui.model.odata.ODataModel("http://Yourserver:Port/sap/opu/odata/SAP/ZHELLOODATA_SRV");
}

Replace the url by the url from your service, you can find it in the service created, see the previously blog post.

 

image18.jpg

 

The last change will be made in view file. Here we going to do the logic to create a table that display the results from the Odata Service.

 

In createContent method enter the code below.

 

var layout = new sap.ui.commons.layout.MatrixLayout('layout');
layout.setWidth('100%');
var rPannel = new sap.ui.commons.Panel('rPannel');
var rTitle = new sap.ui.commons.Title('rTitle');
rTitle.setText('Airlines');
rPannel.setTitle(rTitle);
var oTable = new sap.ui.table.DataTable();
oTable.addColumn(new sap.ui.table.Column({
label : new sap.ui.commons.Label({
text : "Airline"
}),
template : new sap.ui.commons.TextField().bindProperty("value",
"Carrid"),
sortProperty : "Carrid"
}));
oTable.addColumn(new sap.ui.table.Column({
label : new sap.ui.commons.Label({
text : "Airline Name"
}),
template : new sap.ui.commons.TextField().bindProperty("value",
"Carrname"),
sortProperty : "Carrname"
}));
oTable.addColumn(new sap.ui.table.Column({
label : new sap.ui.commons.Label({
text : "Currency"
}),
template : new sap.ui.commons.TextField().bindProperty("value",
"Currcode"),
sortProperty : "Currcode"
}));
oTable.addColumn(new sap.ui.table.Column({
label : new sap.ui.commons.Label({
text : "Url"
}),
template : new sap.ui.commons.TextField().bindProperty("value",
"Url"),
sortProperty : "Url"
}));
oTable.setModel(oController.getModel());
oTable.bindRows("/SCARRSet");
rPannel.addContent(oTable);
layout.createRow(rPannel);
this.addContent(layout);

 

In the logic above we have some points of attention: The name of properties of table column is the same displayed in metadata, or the same of the columns of the DDIC table. In line 48, we have to set the name of our collection, we can find in the XML, see 3th image of this blog. You need enter the value with a '/', just like you can see in this example.

 

 

Now you can save and submit the files. To do this, right click over the project name, on project explorer, then choose team submit, this procedure was demonstrated in first article. Let's run and test, the final result is like a demonstrate in image below.

 

 

image.jpg

 

I appreciate so much to publish this blogs and want to continue publish more and more about my studies and learning.

 

Thank you all!

Mobile Application using WEBIDE with custom SQL C# OData Service - Part2

$
0
0

In Part 1 of this blog I have discussed on how to create a custom odata Service using.NET

Mobile Application using WEBIDE with custom SQL C# OData Service  - Part1

In this blog we will use the Odata Service developed in part 1 running on your laptop to write a simple Application that consists of

1) Login Screen - Northwind Employee screen - The userName = Employee FirstName and Password = Last Name

2) On Success Full Login display the employee info of the Login User - There is a button On Press display Employee List Page

The steps are create application, add routing, add datasource, add the pages, configure routing (manifest.json)

In Part 1 we create a Desination chinHook that referes to the custom Odata Service we  will use this - When Completed the application will look as follows

apppage.png

 

1) Login to SAP WEBIDE and Create SAPUI5 Application - Give the name as Northwind1 and name space as com.sap.northwind1 - on the View Creation Page give the name Login - this will create a Login.view.xml view and the corresponding Controller.  During the Creation Process you can choose to check the box for Mobile apps - If you have configure HAT you can later set the devicee configuration and run it on the mobile device

 

 

2) open the Login.view.xml and give an id <App id="app"> - This required so that we can configure the app to make this first default page

 

3) Open the Login view in the designer and add couple of input controls and button for Login as show below - Select the Login Button and choose Events from the right and add event  onLoginPress - This creates an empty function the corresponding controller file

 

4) Right click on webapp folder and add two more Ui5View name it Employee and EmployeeList - In the Employee Page add couple of Lables and bind this

to FirstName,LastName and address fields - Add a button and Press Event to go to the EmplistPage. In the EmployeeList view drag list and give it id as Emplist and map the listitem to some of the employee fields that you would like to List - Before you do this you choose the Datasource for the view as Employee from the dropdown.

 

5) Right Click on the webapp Folder and an odata Service - Make sure that HANA cloud connector is running  This creates and entry in the neo-app.json file.

Untitled.png

{

      "path": "/destinations/chinHook",

      "target": {

        "type": "destination",

        "name": "chinHook"

      },

      "description": "chinHook"

    },

 

5) We will first enable routing  to do this open the manifest.json in code and make sure you the following lines below models

models": {

  "i18n": {

  "type": "sap.ui.model.resource.ResourceModel",

  "settings": {

  "bundleName": "com.sap.northwind1.i18n.i18n"

  }

  }

  },  // new part to be added to the file

  "routing": {

  "config": {

  "routerClass": "sap.m.routing.Router",

  "viewType": "XML",

  "viewPath": "com.sap.northwind1.view",

  "controlId": "app",

  "controlAggregation": "pages",

  "transition": "slide"

  },

 

6) open component.js and in the init function add the line below to initialize the router

this.getRouter().initialize();

 

7) Right Click manifest.json -open in the designer and make you add the following shown below - Login view is Level 1, Employee is Level 2 and EmployeeList is level3

Untitled.png

8) open Login.controller.js an and the code given bleow

sap.ui.define(["sap/ui/core/mvc/Controller"], function (Controller) {

  "use strict";

  return Controller.extend("com.sap.northwind1.controller.Login", {

   getRouter : function () {

  return sap.ui.core.UIComponent.getRouterFor(this);

  },

    onLoginPress: function () {

           // this.getRouter().getTargets().display("employee");

      

             //  var oRouter = sap.ui.core.UIComponent.getRouterFor(this);

             //  oRouter.navTo("employeesList");

 

            var ur =  this.getView().byId("txtUserName")._lastValue;  //replace the id by your ides

            var pa =  this.getView().byId("txtPassword")._lastValue;

            var url = "/destinations/chinHook/NorthData/NorthwindData.svc/Employees?";

            var params = "$filter=LastName eq '" + pa + "' & FirstName = '" + ur + "'&format=JSON";

            var gg = this;

            url = url + params;

            $.ajax({

  url:url,

  dataType: 'json',

  success: function(response) {

   var x = response.value.length;

             if(  x > 0 ) {

         var empid =  response.value[0]["EmployeeID"];

    

    

         //gg.getRouter().navTo("employee", {

         //  EmployeeID: empid

         //});

    

          gg.getRouter().navTo("employee",{

      employeeId : empid

  });

        }

        else {

        alert("Please Check username and password and retry");

        }

  },

  error: function(XHR, textStatus, errorThrown){

                   alert(textStatus + ":" + errorThrown);

                }

  });

  }

  });

});

 

9)Open the Employee,controller.js and add the following

sap.ui.define(["sap/ui/core/mvc/Controller",

  "sap/ui/model/odata/ODataModel"

], function (Controller,ODataModel) {

  "use strict";

  return Controller.extend("com.sap.northwind1.controller.Employee", {

   getRouter : function () {

  return sap.ui.core.UIComponent.getRouterFor(this);

  },

  onInit: function () {

 

        //

          var sUrl  = "/destinations/chinHook/NorthData/NorthwindData.svc/";

    var oModel = new ODataModel(sUrl);

        this.getView().setModel(oModel);

        var oRouter = this.getRouter();

        oRouter.getRoute("employee").attachMatched(this._onRouteMatched, this);

},
_onRouteMatched : function (oEvent) {
alert('on matched');
var oArgs, oView;
oArgs = oEvent.getParameter("arguments");
oView = this.getView();
//var path =  "Employees(" + oArgs.EmployeeID + ")";
//var path =  "Employees(" + "1" + ")";
var path = "/Employees(" + oArgs.employeeId + ")";

        

oView.bindElement({
path : "/Employees(" + oArgs.employeeId + ")",
events : {
  //change: this._onBindingChange.bind(this),
dataRequested: function (oEvent) {
oView.setBusy(true);
},
dataReceived: function (oEvent) {
                    
                                                                                oView.setBusy(false);
}
}
});
},

//,

/**
*@memberOf com.sap.northwind1.controller.Employee
*/

onEmpListPressed: function () {

//This code was generated by the layout editor.

        var oRouter = sap.ui.core.UIComponent.getRouterFor(this);

         oRouter.navTo("employeesList");

}
});

});

 

10) Open The EmployeeList.controller.js and add the following

sap.ui.define([

  "sap/ui/core/mvc/Controller",

  "sap/ui/model/odata/ODataModel"

], function (Controller, ODataModel) {

  "use strict";

  return Controller.extend("com.sap.northwind1.controller.EmployeeList", {

  getRouter: function () {

  return sap.ui.core.UIComponent.getRouterFor(this);

  },

  onInit: function () {

   var sUrl = "/destinations/chinHook/NorthData/NorthwindData.svc/";

   //var sUrl = "/destinations/Northwind/V2/Northwind/Northwind.svc/";

    var oModel = new ODataModel(sUrl);

        this.getView().setModel(oModel);

  }

});

});

Dynamic Binding of SAPUI5 Table Columns and Rows

$
0
0

          The sap.ui.table.Table control is commonly used in desktop and tablet applications.It provides a comprehensive set of features for displaying and dealing with vast amount of data.

           The Table control reuses its DOM element of the rows.When a user scrolls only the row contexts are changed but the rendered controls remain the same.This is why table control is able to handle vast amount of data.Keep the column number as low as possible to increase the table performance.

           The Table control relies completely on data binding , and its supported feature set is tightly coupled to the data model and binding used.So lets see how to dynamically bind Table rows and columns.We will make it as simple as possible.

Steps

  1. First step is to include sap.ui.commons and sap.ui.table libraries in index.html file.1.PNG
  2. First we need data for the Table.Here we need two sets of data.One for binding the column and other for rows.You can Get Data from Odata Service.Here I am using custom data.

2.PNG

3.Create Table control.The default value for visibleRowCount is 10.We will give it 3 .

3.PNG

4.Create a json model instance.Set data to the model.

4.PNG

5.Set the model to Table Control.

5.PNG

6.Bind Columns

6.PNG

7.Bind Rows And place it

7.PNG

Hope You liked it.For more information see

Dynamic Binding of SAPUI5 Table Columns and Rows | sap abap | sapui5 made easy

Fiori Launchpad: add custom buttons to FLP Shellbar

$
0
0

Hi All,

We got a request for extending the Fiori Launchpad (FLP) Shell Bar adding 2 custom buttons. The function of these buttons is the integration of resources already available as HTML/Web for all employees, so out of the context of any role, task or business process. In our case the resources are an already available online documentation a web chat tool for live support. Both are web app. We implement the buttons available on the Shell Bar of the FLP because of its easy access. Alternatives we considered are adding an entry in the action sheet of the Account / Settings Button and adding a Tile in the FLP home page but the buttons in the Shell Bar better fulfilled our requirements.

 

Here we describe the code we used. Maybe helps other developers.

Our playground is a S4HANA System (lib 1.28.6). At first copy your FioriLaunchpad.html and add the following script code in the head tag of the copied html file:



The buttons are displayed on the right and on the left part of the shell bar

FioriBlog_rechts.png

FioriBlog_links.png


The code:


/**
* ADD Chat Support Button
*/            var oRendererExtensions = jQuery.sap.getObject('sap.ushell.renderers.fiori2.RendererExtensions');            var oSupportHeaderItem = new sap.ushell.ui.shell.ShellHeadItem('supportChatBtn', {                icon: sap.ui.core.IconPool.getIconURI( 'travel-request' ),                tooltip:'Support Chat',                showSeparator: true,                press: onSupportHeaderItemPress            });            function onSupportHeaderItemPress(){                window.open('http://server/chatTool.html', 'ChatSupportWindow', 'width=400,height=400,status=yes,scrollbars=yes,resizable=yes');            }  // add button to the right side of the shellbar            oRendererExtensions.addHeaderEndItem(oSupportHeaderItem);
/**
* ADD Online Help Button
*/            var oDocumentationHeaderItem = new sap.ushell.ui.shell.ShellHeadItem('sharepointBtn', {                icon: sap.ui.core.IconPool.getIconURI( 'sys-help' ),                tooltip: 'Online Help',                showSeparator: true,                press: onDocumentationHeaderItemPress            });            function onDocumentationHeaderItemPress (){                window.open('http://server/OnlineHelp.html', '_target');            }            // add button to the left side of the shellbar            oRendererExtensions.addHeaderItem(oDocumentationHeaderItem);

 

We simply open the URL’s as a new Page or Tab but if it makes sense for you, you can use a sap.m.Popover embedding an iframe. Just take care of browser restrictions like mixed content.


FioriBlog_rechts_popover.png

 

/**
* ADD Chat Support Button
*/            var oRendererExtensions = jQuery.sap.getObject('sap.ushell.renderers.fiori2.RendererExtensions');            var oSupportHeaderItem = new sap.ushell.ui.shell.ShellHeadItem('supportChatBtn', {                icon: sap.ui.core.IconPool.getIconURI( 'travel-request' ),                tooltip:'Support Chat',                showSeparator: true,                press: onSupportHeaderItemPress            });            var oHTML = new sap.ui.core.HTML({preferDOM : false,content:               "<div><iframe src='http://server/chatTool.html'></iframe></div>"            })            var oSupportPopoverContainer = new sap.m.ScrollContainer({                // if you set the size here also set the size of the iframe accordingly                //width : "250px",                //height : "300px",                horizontal : true,                vertical : true,                content: [oHTML]                    });            oSupportPopoverContainer.addStyleClass('sapUiContentPadding');             var oSupportPopover = new sap.m.Popover("configuration_popover", {                title: "Support Chat",                placement: sap.m.PlacementType.Bottom,                content: oSupportPopoverContainer            });            function onSupportHeaderItemPress (){                if(oSupportPopover.isOpen()){                    oSupportPopover.close();                }else{                    oSupportPopover.openBy(oSupportHeaderItem);                 }            }

 

 

Hope it helps

 

Regards

 

Robert Kleger and Christian Montagner

New openSAP course "Developing Web Apps with SAPUI5" is now open for registration

$
0
0

We – the UI5 developers and the colleagues from the openSAP learning platform – have worked hard to create an online course for interactively learning SAPUI5. Are you ready to deep dive into the main development concepts of SAPUI5 and to learn how to code responsive apps from scratch?

 

Then the openSAP course Developing Web Apps with SAPUI5will be the right thing for you. It has just been published and is now open for registration! The course will start mid of May 2016. Read more about the course content and dates in the official announcement.

 

Cf16O10XEAA6odm.png

This course is all about real coding and will give you lots of practical experience with SAPUI5. We have recorded almost 30 videos units teaching you SAPUI5 with lots of background information. If you do the optional coding exercises for each unit you will develop responsive web apps with lots of exciting features. And you can even score a record of achievement by doing the weekly assignment and the final exam.

The video units and the exercises were done by real content experts and developers from the SAPUI5 team, so it’s first-hand knowledge right from the experts. And we will be available for your questions in the online forums during the course. There will also be a few nice surprises in this course so stay tuned ;-)

Oh, and all topics of the course are equally relevant for OpenUI5 and SAPUI5 development, so every web developer is welcome to enroll for free!

Not convinced yet? There’s even a teaser video. ;-)

See you in the course!

Michael on behalf of the whole course team

Viewing all 789 articles
Browse latest View live




Latest Images