IBM BPM 8.5.6 Client-Side human service visibility script - response

I have a table that when I select one or more rows and click a button I go to a service that when finish remove those rows from the table. My problem is that button must appear when I select one or more rows otherwise disappear.
My visibility script for the button is:
if(local.get("pSuspendedTasks").get("listAllSelected")[0] == null){
return "HIDDEN";
}
return "DEFAULT";
When I call the service and return without the rows that I selected before the button still there.
NOTE: I use responsive coaches toolkit

You must clear the selection items on the list pSuspendedTasks.
You can do it calling method listClearAllSelected on server side as below:
tw.local.pSuspendedTasks.listClearAllSelected()
To works fine, don't forget to pass and return the entire list to the service.
Regards,
Bernardo Baumblatt.

Related

Non-Editable Timestamps in Google Slides based on creation of a new slide in a presentation

This is probably a longshot, but I'm a teacher working with students on Engineering Design notebooks. One of the main goals/requirements is that each page has a date, and that date shouldn't be editable by students.
I've been looking for scripts that allow me to automate the date in Google Slides, which is where we are building our notebook template.
There are quite a few scripts for updating a date whenever you open a presentation.
does anyone know how to add a script that would update the current date in a text field, only when a new slide is created? EX: Student opens their digital google slides notebook, then they click CTRL+M or right click > New Slide. When the new slide pops up, it autopopulates the date field with the current date, and cannot be edited by the student.
Thanks for any help in pointing me in the right direction.
Yes, you can create a non-editable textbox and later fill it with a timestamp using a script.
The solution below may not meet your whole question, maybe just the first goal, but the idea can be converted into a better script.
A textbox cannot be edited in the slide view if it is placed in a layout in the master view.
To give you the idea, we are going to create a "non-editable" textbox in the main slide layout as an example:
We need to get the Slide id first. From our Google Slides document, take note of its id from its URL format https://docs.google.com/presentation/d/{your slide id}/edit. Use {your slide id} to define the constant SLIDE_ID in your script.
To edit the main layout, we have to enable the Master view from the menu View > Master
In the Master view, we will notice the slides under the "Master" and "Layouts" list. Choose the first layout from the "Layouts" list. The first layout is usually the main slide layout.
In the main slide layout, we create a text box with the text Date. We use the text to find the textbox object id with the following Script 1 first. In the image below, it is the red textbox with the Date text.
Script 1:
const SLIDE_ID = "{your slide id}";
//don't enable the debug log when running this script in production to speed up the processing
const ENABLE_DEBUG_LOG = true;
function findLayoutObjectIdByText_(text) {
var presentation = SlidesApp.openById(SLIDE_ID);
var layouts = presentation.getLayouts(); //layouts[0].getShapes()[0].getObjectId()
layouts.forEach(layout => { // iterate through every layout in the presentation
layout.getShapes().forEach(shape => { // iterate through every shape in the slide
const textStr = shape.getText().asString(); // get shape text string
const textObject = shape; // get shape text object
const matches = textStr.match(text); // find matches
if (matches != null) {
if (ENABLE_DEBUG_LOG) Logger.log("TEXT : " + textStr);
if (ENABLE_DEBUG_LOG) Logger.log("MATCH : " + textObject.getObjectId());
return; //a workaround since we can't use a break statement in forEach() loop
}
});
});
}
function openSlide() {
findLayoutObjectIdByText_(/^Date/g);
}
Select Run > Debug > openSlide. After a few seconds from your script editor, go to View > Logs to see the output for "MATCH". For example, the object id is ga66cd6addf_0_17
Output:
[20-11-01 12:21:09:042 HKT] TEXT : Date
[20-11-01 12:21:09:044 HKT] MATCH : ga66cd6addf_0_17
We can now modify the codes in the openSlide() function in Script 1 as follows:
Modified Script 1:
function openSlide() {
//findLayoutObjectIdByText_(/^Date/g); //comment it out once we are done
var presentation = SlidesApp.openById(SLIDE_ID);
var today = new Date();
var shape = presentation.getPageElementById("ga66cd6addf_0_17").asShape();
if (shape ! null) { //if the shape object present (not being removed)
shape.getText().setText(today.toLocaleDateString('en-US', {day: 'numeric', month: "short", year: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric'}));
}
}
Select Run > Debug > openSlide. After a few seconds, we can see the Date in the textbox has been changed to a proper timestamp in our Google Slides document as follows:
Now, we can use the modified openSlide() function as a time-driven trigger (if the script scope is in the Google Slides document) or as an event trigger (if the script scope is in Google Form or Google Sheet) to keep updating the text. The timestamp textbox cannot be modified when we are not in the master view.
It is not necessary to create a new slide using a script, but you can refer to https://developers.google.com/slides/how-tos/create-slide.
The important thing is to make sure to edit every layout in the "Layouts" list in the Master view with the above idea. Every time the student creates a new slide from the Google Slides document, the new slide will automatically retrieve the assigned slide layout (most likely it is the third Layout in the Master view) that you have included in the timestamp textbox.
Next idea: the above steps can be turned into a whole script if you want to but I will not cover how it can be done here.
Caveat: Since every new slide uses the assigned default slide layout, we are going to see the same timestamp value for all newly created slides. Maybe it is better to run a script that is executed from a Google Form's onSubmit() scope trigger where the student submits his/her attendance for every session, for example. Once submitted, the script will duplicate a Google Slides document for the student from the master/template Google Slides document that has included the "Date" textbox in the layout and timestamps the "Date" textbox in the duplicated document (like the concept of mailmerge/document bookmarks in the Microsoft Word). The script will only act upon the duplicate but not the master/template. The link to this duplicated Google Slides document can be provided from a response email or from a Web redirect. You can include the student's name in this duplicate document as well! So, every student will have his/her own Google Slides document with a different current timestamp each time it is created.
See the merge concept in https://developers.google.com/slides/how-tos/merge
Note: we still cannot avoid the students from modifying the layouts in the Master view when we give them the edit permission.

Grid filled by a data provider: how to trigger an action after refreshment?

In Vaadin 8.2, I have a Grid bound to a bean using a data provider (AbstractBackEndDataProvider). Data is fetched from a DB, filters are applied:
Grid grid = new Grid<>();
grid.setDataProvider(dataProvider.withConfigurableFilter()); // dataProvider derives from AbstractBackEndDataProvider<T,F>
The essential flow is the following: user inputs an item id in a form and submits, a submit event listener gets the user input, creates a new filter and updates the data provider:
filterSubmitButton.addClickListener(event -> {
try {
ItemListFilter filter = new ItemListFilter(
itemFilter.getValue(), // itemFilter = new TextField();
);
filterBinder.writeBean(filter);
dataProvider.setFilter(filter);
} catch (ValidationException e) {
//...
}
});
When the data provider gets the filter updated it calls a service to fetch new items from DB with the filter applied (to the DB query). Vaadin takes care of refreshing the Grid with new data afterwards.
What I want is to have a callback at this last moment. Say an use case would be to check if a filtered fetched result set contains only one item, to select this item in the Grid (which in its turn will trigger an event showing item details in another pane). Or to select the first grid row after initial list is loaded
But the problem is that there is neither grid.addRefreshListener() nor dataProvider.addRefreshmentListener(). Any other listeners do not seem to apply in this case.
Thanks for any help in advance.
The only solution I've found is a trade-off.
The item list presenter (which handles the view with the grid) passes its com.vaadin.event.EventRouter to dataProvider (I've modified the dataProvider to hold an EventRounter as a member). And now instead of streaming DB results directly from the dataProvider I fire an event that the data is fetched (using EventRouter). The presenter can subscribe to this event and then delegate it to the presenter of the details panel. There you can read the fetched results (the event contains them), check if there's only one entry and open it by id.
public class ListItemDataProvider extends AbstractBackEndDataProvider<Item, ItemFilter> {
//...
#Override
protected Stream<Item> fetchFromBackEnd(Query<Item, ItemFilter> query) {
// ...
List<Item> fetchedResults = service.fetch(query.getOffset(), query.getLimit(), orderBy, getFilter(query));
eventRouter.fireEvent(new FilteredDataFetchedEvent(this, fetchedResults));
return fetchedResults.stream();
}
}
#Controller
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ItemListPresenter {
// ...
public void addFilteredDataFetchedListener(ItemListView.FilteredDataFetchedListener listener) {
eventRouter.addListener(FilteredDataFetchedEvent.class, listener, FilteredDataFetchedListener.FILTERED_DATA_FETCHED);
}
}
Few notes:
This is not exactly what I needed. Yes, I can do the most of my use case, if the filter is applied the list is reloaded and the details view gets the event to reload too. But I can't re-use the "selectionChanged" event listeners for this and actually can't select a row in the grid at all (just because the event from dataProdiver is thrown before the grid is updated).
This is sort of a dirty trick, because now the dataProvider throws events and deals with eventRouters of views/presenters. On the other hand Vaadins data providers anyway do allow to subscribe on events. Using that out-of-box grid-dataProvider reactive binding we just don't have an event fired after data is fetched, so we do it in a custom way.
What could also work is use the given Vaadin's subscriber dataProvider.addDataProviderListener and delegate from there an event containing the filled filter and just act independently catching that event in the details panel. But then you would need to execute sql queries twice (which can be costly) or cache them etc. This brings no benefits in comparison to the given and is still a trade-off.
When you invoke dataprovider.refreshAll(), the associated grid is automatially refreshed. Therefore, after following lines in your code:
filterBinder.writeBean(filter);
dataProvider.setFilter(filter);
add logic to get size of returned records (eg. dataprovider.size()) and if that equals one (01), invoke some other logic to select the one record and display its details in other panel.

Pre-populate ListBox / MultiSelectList with selected items

Is there a way to pre-populate a MultiSelectList with selected items?
Example:
I have a single View that has the following ListBoxFor that will cause the page to update what it's displaying by allowing filtering of Model.Companies.
#Html.ListBoxFor(m => m.SelectedCompanies, new MultiSelectList(Model.Companies, "IdString", "CompanyName")
What I'd like to have happen is after the update, the MultiSelectList will have the items that were selected before the page updated and refreshed. Does that mean I need to return SelectedCompanies with what was selected, or is there another way?
I am using the javascript library Chosen for usability of the ListBox on the client side, but I don't think that this affects what I'm trying to do.
Sometimes, JS libaries can interfere with your desired results. I can't speak for Chosen JS library, but inspect the markup and see how it renders. As long as it still has the listbox on the client (it must have some input element defined somewhere; my guess it hides it and updates the values as they are selected), then yes it should integrate fine.
However, when the controller posts back, you have to repopulate the Model.SelectedCompanies property with whatever values came back from the POST operation to the controller. The property should still have the selected companies if you return a View from the POST operation. If you are using a RedirectToAction instead, you'd have to store the selections in TempData.

Displaying Grails domains in jquery tabs

What would be the best way to display data from Grails database in JQuery UI tabs? What I would like is to have a tab interface and on each tab is a list of the records from a different domain. For instance, Tab1 displays the record list from Domain1, Tab2 displays the record list from Domain2, etc.
I have the JQuery UI tab interface set up and working and am currently using createLink to call the method from the controller to return the model of the appropriate domain. The tabs look like this:
<div id="tabs">
<ul>
<li>Hardware records</li>
<li>Model records</li>
<li>Building records</li>
</ul>
</div>
The method from the controller looks like this:
def listHardware() {
[hardwareList:Hardware.list(), hardwareInstanceTotal:Hardware.count()]
}
I've also played around with rendering a whole GSP within the tab by using "render(view:'HardwareList', model:[hardwareList:Hardware.list(), hardwareInstanceTotal:Hardware.count()]", but that takes a VERY long time (at least 5 seconds) to load each time the tab is selected and is not at all ideal, especially if it were to take that long for each tab.
UPDATE
As noted in one of my answers to Rimero's answer below, I was able to use templates to display tables of my domains' data. I'm also trying to implement pagination on each tab using the tag, but each time I click on one of the pages to view another page, it takes me to the full template itself outside of the tab interface. Any thoughts on how to format the tag so that everything stays within the tab??
Here's my suggestion:
You can fetch everything at once in your controller in your index method for example.
You can implement your tab contents as templates
(g render template). Each tab == 1 template.
You can fetch your domain objects buildingList,
etc. from the index method of your controller.
The g:render template code for each tab may only need to be passed a map or a collection for rendering.
In this case you don't need hyperlinks to controllers endpoints. You just keep anchors to the tab(div id) as in the default example here -> http://jqueryui.com/tabs/.
UPDATED ANSWER
As you said that sending all the data at once takes a long time, you could fetch it asynchronously. If possible populate the data only for the first tab directly.
Create a business method for each tab, that will return the model as JSON, data is only fetched if not already retrieved from the server (Need to keep state or see for example if the tab id has some DOM nodes.
Using JQuery, when the DOM is ready, get the current tab and if you didn't fetch the data for the first tab eagerly, fetch it at this moment with the busy image spinning.
As soon as you select a new tab, you need to check if the data was already fetched, if not, you send an ajax call and your callback function populate the data in the tab div container for example.
Hope it helps.

How Can I remove backstack till the required pagename in Wp7.1

I want to remove pages from backstack till a particular page say "C" has reached when I am on some other page say "F".
Is Its posiible to remove backstack upon pagename?
Thanks and Regards,
Kanaya
You can easily traverse the backstack and check the page names and remove items like this:
while (NavigationService.CanGoBack)
{
if (NavigationService.BackStack.First().Source.OriginalString == "/C.xaml")
{
break;
}
NavigationService.RemoveBackEntry();
}
You can keep a record a all the pages you have navigated in the code like a screen manager. That contain the pages in the same order as the default stack. So you can find the position of the desired page from that list and call remove back entry function that many times.

Resources