How a Page can access a Web Block's query

How a Page can access a Web Block's query

  
Hello everyone.

I have one page in my application (Requests) that I factored into a Web Block. The old Page has a Table Records list and an action (created by Intelli Warp in the page's action place holder) to export the list to Excel.
In the new page using a Web Block, I needed to implement the same "Export to Excel" action. The problem this action needs access to the Table Records source query. The Table Records and its source record have private scope in the Web Block. How can a Web Block expose its private scoped varaibles like queries in its Preperation method?
Hi  Shraim,

You can't access a query inside a WebBlock or other actions directly.
You can only input parameters and output text using the Notify method.
Why  don't you implement the method inside the WebBlock?
In this case I don't know the real requirement you have, to try to help you, since we can do some tricks using javascript to do communicate with a WebBlock.

Kind Regards,
Gonçalo Martins

Hi Goncalo.

Basically, I think of the Web Block as re-usuable peice of UI that also needs to have its own set of public methods to be consumed by pages using this Web Block.

I did try to define a method ExportRequeststoExcel inside the Webblock but again I dont know how to expose this method so it can be used by pages using this Web Block.

I am not sure I know what or how to use the Notify method you are talking about.

I did some reading on the NotifyWidget. Basically its an Ajax based mechanism for a parent to notify (refersh) a Web Block. My quest is:
1- Parent page has the "Export to Excel" link and the user clicks it

2- the Web Block should somehow receive (be aware of) the user clickin on that link to execute its ExportToExcel action

How can I acheive these two steps using the NotifyWidget pattern ?
Hi Shraim,

WebBlocks can't really expose methods to be consumed by pages. They can expose "events" using the NotifyWidget pattern, so it works the other way around - the WebBlock can communicate information back to the parent WebScreen.  

Let me give you a couple of ideas on how to move forward:
  • Refactor into an User Action the logic to get the necessary data for the WebBlock to display the Table Record and use that same logic in your WebScreen "Export to Excel" Screen Action
  • Include the "Export to Excel" funcionality inside your WebBlock so that it too becomes reusable
  • Use JavaScript to click a link inside the WebBlock (to trigger the Excel download) when the parent link on the WebScreen is clicked. This is a little bit of an hack, so I'd stay away from it if possible :)
Let me know if any of these work for you.
Thank you Goncalo. I have read most of the conetnt on the forum related to using NotifyWidget as means to communicate between a Web Page and a Web Block. Problem none of the posts give a step by step explanation how to use this pattern.

For your suggestions:

1-
Refactor into an User Action the logic to get the necessary data for the WebBlock to display the Table Record and use that same logic in your WebScreen "Export to Excel" Screen Action
I want my best to avoid communicating the complete list of records out of the Web Block. It looks more intuitive to just give a command to tell the Web Block to export its displayed list to Excel rather than asking the Web Block to give its list of records for an external action to do the Export to Excel

2-

Include the "Export to Excel" funcionality inside your WebBlock so that it too becomes reusable
Yes this is also my preferred approach. My problem is that I want to trigger this "Export to Excel" functionality from the parnent Page as the button/link to invoke this functionality is in the parent page and not in the Web Block

3-

Use JavaScript to click a link inside the WebBlock (to trigger the Excel download) when the parent link on the WebScreen is clicked. This is a little bit of an hack, so I'd stay away from it if possible :)
I agree with you this is a hack as it entails having some dummy or fake link/button inside the Web Block to be invoked when the parent Page's link/button is invoked.
I am not really a veteran web developer nor a java script developer. Still, I would have no problem in writing java script if I can get some guidance to where and how to include custom java script logic in service studio. I would appreciate your help showing a step by step guide how to do that
Hello Shraim,

Sorry for the late response but weekend got in the way :)

For my #1 suggestion, I was more thinking along the lines of refactoring the action that gets the data into a self sustained User Action. This User Action could then easily feed the WebBlock table records and also the Export to Excel functionality. So these would be two separate calls and no need to pass record lists around. I think this might be my favorite route, actually. 

For my #2 suggestion, it was about actually including the link inside the WebBlock to provide complete isolation and reuse. If you can't do this, then on to #3...

For suggestion #3, it would be necessary to perform the following high level steps:
  1. Create the "fake" invisible link inside the WebBlock that triggers the Export to Excel functionality via Screen Action
  2. Mark this link with a CSS class of your own (i.e. ExcelExportLink). This will be used to identify the link in the context of a web page later on
  3. On the parent page, execute a JS in the onClick of the "Export to Excel" link - use Extended Properties for this - that does something like "$('.ExcelExportLink).click(). You'll need to include JQuery to get this to work. 
I still think you should go for solution #1, but let me know how it works out. 
Thank you so much Goncalo. As this is my first AP project, I am really trying to learn best practices and patterns. I appreciate your patience in discussing each point separately to better learn each and hopefully provide same guidance for future newcomers like myself.

Option #1: I understand the architecture but need to verify the steps to implement. You explain to "refactor the action that gets the data". 
1- The Web Block has a preparation that gets its data. Are you suggesting for the logic of the block's preparation action to be factored into this new Action?
2- If previous point is what you mean, does this mean that when "Export to Excel" link needs to execute its logic, your factored User Action would Re-Execute the query that gets the data for the Block?

Option #2: A friend who is an experienced AP developer also suggested this option. Basically he suggests to keep the right-bar for tasks and other information while blocks contain their own links. For me I see this as a valid UX pattern as long as it is followed in all the application's UI.

Option #3: I am not a big fan of using JS specially for implementing hacks but I still feel it is important to learn this pattern for other scenarios when I will not have other alternatives.

For communicating between a Web Block and a Parent Page, the above 3 options seem to cover one area but we still miss another important one:

1-   when a Web Block needs to communicate to a Parent Page that something happened ==> use the NotifyWidget pattern

2-   when a Parent page needs to invoke an action in a Web Block ==> no standard pattern

I am thinking that your option # 1 could work as a general pattern to cover point 2. Would love to hear your input.
I started to implement Option # 1 and hit a snag. The query in the Web Block's preperation method joins several entities in order for the search where clause (used by the wbe block's filtering) to work.
I factored the query into a user action and it became obvious that I need an output parameter for the action. The Output parameter (RequestsList) would be a RecordList and the Record type is Request.
When I used an Assign to assign the List property of the Simple Query to the O/P parameter RequestsList, the error I got a type mismacth error (see image).
I am assuming that I will need to define a new structure type that has all the same attributes as the Requests and also all the same attributes in the other entitties joined with Requests in the Query GetRequestsByPriorityId. If that is the case, then this would be very cumbersome to do manually whenever considering to refactor a simple query into a User Action. Is there  an easier way around this or am I going about this all wrong???

Shraim,

Excellent summary of what we discussed. For the clarifications you requested:
  1. Shraim wrote:
    Option #1: I understand the architecture but need to verify the steps to implement. You explain to "refactor the action that gets the data". 

    1- The Web Block has a preparation that gets its data. Are you suggesting for the logic of the block's preparation action to be factored into this new Action?
    2- If previous point is what you mean, does this mean that when "Export to Excel" link needs to execute its logic, your factored User Action would Re-Execute the query that gets the data for the Block?

     
     Yes, you should take the WebBlock preparation and refactor it into a UserAction that becomes used both inside the WebBlock (via preparation) and on the Screen Export to Excel implementation. And yes, the query would be re-executed which should not be a problem for most cases. Keep in mind that not executing the query again would force data to be kept somewhere else (i.e. Viewstate) causing unwanted side effects like bigger page sizes. 
  2. I agree, option #2 should be implemented consistently so that your users don' get confused. But it is a very valid option, no doubt.
As for the snag you hit, keep in mind that when selecting the type of your Output Parameter you can make it composite - in other words, it can be composed of all the Entities you are joining. To do this, go to your RequestsList output parameter, left click on "Record Definition", and then use the "Record Editor" to specify the make of your output parameter. More info can be found here - www.outsystems.com/help/servicestudio/7.0/Miscellaneous/Record_Editor.htm

I hope this makes your refactoring work - it seems you're heading in the right direction :)
Shraim wrote:
Thank you so much Goncalo. As this is my first AP project, I am really trying to learn best practices and patterns. 
 
About Best Practices, I strongly recommend the reading of the following documentation:
Kind Regards,
Gonçalo Martins
Experiencing AgilePlatform so far and reflecting on over 20 years experience in the field I have no doubt that it is a true paradigm shift. But honestly, the quality of the OutSystems community is no less as a paradigm shift compared to what is in the industry.

Thank you both Goncalos. The composed record structure is a true Gem and the best practices documentations are a must read. 

Gonçalo Gaiolas wrote:
  1.  Yes, you should take the WebBlock preparation and refactor it into a UserAction that becomes used both inside the WebBlock (via preparation) and on the Screen Export to Excel implementation. And yes, the query would be re-executed which should not be a problem for most cases. Keep in mind that not executing the query again would force data to be kept somewhere else (i.e. Viewstate) causing unwanted side effects like bigger page sizes. 
 
Following this to the end, I need to ask about the RefreshQuery pattern. The Web Block has a method RefreshRequestTable that refershes the Table Records widget by calling a RefreshQuery (for the old Simple Query) followed by an Ajax Refresh for the Table Records.

After refactoring the Simple Query to a User Action, the Table Records widget is now bound to the User Action not to the Simple Query.

For refreshing the table, does the same pattern apply? Meaning, in the RefreshRequesTable method (see image) can I simply call the new User Action insetad of the Refresh Query and expect the call to the Ajax Refresh for the table to work the same at runtime (refreshing the table showing new refershed data content)

Shraim wrote:
 
Following this to the end, I need to ask about the RefreshQuery pattern. The Web Block has a method RefreshRequestTable that refershes the Table Records widget by calling a RefreshQuery (for the old Simple Query) followed by an Ajax Refresh for the Table Records.

After refactoring the Simple Query to a User Action, the Table Records widget is now bound to the User Action not to the Simple Query.

For refreshing the table, does the same pattern apply? Meaning, in the RefreshRequesTable method (see image) can I simply call the new User Action insetad of the Refresh Query and expect the call to the Ajax Refresh for the table to work the same at runtime (refreshing the table showing new refershed data content)
 
 
Thanks for the kind words, I know both me and Gonçalo greatly appreciate them.I hope you continue on your journey to become e ture master of the OS Platform :)

As for your sample, you're need something a little bit more evolved. Because we are now going to bind two different sources to our TableRecord, the best way is to have a Local Variable (lets call it RequestsRL) of the same type as the Output parameter on GetRequestsByPriorityId. This variable will serve as the Source Record List for the Table Record on the Page.

This way, after you (re) call GetRequestsByPriorityId you must Assign RequestsRL with the new results and then simply refresh the TableRecords (by doing what you are already doing). 

Let us know if that worked for you and keep going!
Thanks again Goncalo.

Reading your answer I think maybe my image has given the impression that I am binding my TableRecord to two sources. The image shows the action RefreshRequestsTable. In this action the RefreshQuery was there to referesh the old source which was a Query.

After refactoring the source query to a user action, I want to change the RefreshRequestsTable action so it refershes the TableRecords by calling my factored user action insetad of the RefreshQuery refreshing the query that is not any more.

My confusion is conceptual. The old pattern uses a RefreshQuery (to recall the source query of the table) then Ajax Refresh (to refresh the table UI bound to the source query).

With the refactored user action, does the same pattern hold? I mean can I just consider the user action just like a query and wherever I usually need to refresh a source query I mearly need to re-call the user action ?
Short answer is no. There is no RefreshAction widget similar to RefreshQuery so you'll need to factor out the Source Record List to the local variable, assign the local variable in your Screen Action (to the result of the UserAction call), and then refresh the TableRecords. This is the equivalent (with a few more steps) of a RefreshAction.

The issue is that the second invocation to the GetRequestsByPriorityId is a whole new instance, and not mapped to the original at all. Therefore, you need to have a common denominator (the local Variable where the Source Record List is bound to) that provides the necessary commonality between the two calls. 

I can try to put together a small sample tomorrow if my explanation still doesn't make sense, but let me know if it does. 
I got it now. It makes sense if you think of it in terms of ByRef and ByVal in programming languages.Yes after your explanation it is even more intuitive than the refreshQuery because the RefreshQuery is not a common programming pattern in .NET or Java.
Another snag...

In the Web Block UI I have pagination elements (generated by Intelli Warp). The source expression of these UI elements (before factoring the source query to a user action) uses the query's "Count" property. 

After factoring to user action that returns a "Record List", the web block now uses a local variable of the type Record List to store the output of the factored user action.

The problem is that the local variable of type Record List does not have a property "Count" as the query does. How can I support the pagination UI using a source of type Record List instead of a source of type Query?
One way of supporting that is adding an additional Output Parameter to your action that returns the Count of total results. You can then use this output for your pagination. The downside is that this User Action can no longer be marked as a Function (because of two output parameters), but that should not be too much of a problem. 

Also for your learning path, here is some great additional reading about the differences of Count and Length and their implications. 
Shraim wrote:
Another snag...

In the Web Block UI I have pagination elements (generated by Intelli Warp). The source expression of these UI elements (before factoring the source query to a user action) uses the query's "Count" property. 

After factoring to user action that returns a "Record List", the web block now uses a local variable of the type Record List to store the output of the factored user action.

The problem is that the local variable of type Record List does not have a property "Count" as the query does. How can I support the pagination UI using a source of type Record List instead of a source of type Query?
 
 Hi Omar,

I'm glad to see you keep on pushing your skills :)

Regarding this hole topic let me give you some pointers.
Take into carefull consideration that option #1 might lead you to some performance issues. Remember that encapsulating a simple query in a user action does not allow the Platform to optimize it and so all the columns will be fetched from the database. One way to work around this would be to use an advanced query with an output structure. But I think that is just over complicating what you need.

If you drag and drop your entity to the web block flow the IntelliWarp pattern already has the export to excel.

Why don't you use the export action inside the web block with the corresponding link action to trigger it? If you truly want to reuse it it makes no sense to have to implement an button outside the web block to trigger an action encapsulated in the web block (although as Gonçalo explained this is not possible)

Cheers,
André