Xpages nested dojo tab container repeat dojo tab panel with checkboxgroup - does not update - dojo

Hi I'm new to Xpages and have encountered an issue for which I am unable to find a relevant question / answer after searching (see title for search terms).
I would be grateful for insight into how to solve the following issue.
I have a nest of 3 Dojo Tab Containers, each container holds a repeat container with a Dojo Tab Control, the inner most Tab Control carries a standard checkBoxGroup.
The computed labels for the tabs are read from a multi-dimensional sessionScope variable, the final dimension carries the computed 'label|value' pairs for the checkBoxGroup. The data is bound to a document.
I can switch between the various tabs and select/deselect check boxes and the status remains tracked when switching back an forth among the tabs. However, and this is the crux, only the checkBoxGroup values on the final tab are written back to the underlying document on submission, the checkBoxGroup values displayed on the other innermost tabs are ignored.
Any advice guidance on how to resolve this issue would be gratefully received.
<xe:djTabContainer id="djTabContainer1"
style="height:600px;width:1200.0px"
doLayout="false">
<xe:this.rendered><![CDATA[#{javascript:control = getComponent("STP2radioGroup1");
control2 = getComponent("STP2radioGroup2");
if (control == null || control2 == null){return false;};
val = control.getValue();
val2 = control2.getValue();
if (val == "None" || val2 == "All") {
false ;
}
else {
true;
}}]]></xe:this.rendered>
<xp:repeat id="repeat1" rows="30"
value="${sessionScope.GHC}" var="GHCTabs" first="0"
indexVar="GHCTabIndex" repeatControls="true">
<xe:djTabPane id="djTabPane1"
title="#{javascript:GHCTabs}">
<xe:this.rendered><![CDATA[#{javascript:!empty(sessionScope.Services[GHCTabIndex])}]]></xe:this.rendered>
<xe:djTabContainer id="djTabContainer2"
style="height:550px" doLayout="false">
<xp:repeat id="repeat3" rows="30"
value="${sessionScope.Enviro}" var="EnviroTabLables"
indexVar="EnviroTabIndex" first="0" repeatControls="true">
<xe:djTabPane id="djTabPane2"
title="#{javascript:EnviroTabLables}">
<xe:this.rendered><![CDATA[#{javascript:!empty(sessionScope.Services[GHCTabIndex][EnviroTabIndex])}]]></xe:this.rendered>
<xe:djTabContainer
id="djTabContainer3" style="height:500px"
doLayout="false">
<xp:repeat id="repeat2"
rows="30" value="${sessionScope.Aspect}" var="AspectTabs"
indexVar="AspectTabIndex" first="0"
repeatControls="true">
<xe:djTabPane
id="djTabPane3" title="#{javascript:AspectTabs}">
<xe:this.rendered><![CDATA[#{javascript:try{
if (sessionScope.Services[GHCTabIndex][EnviroTabIndex][AspectTabIndex] == null){false}
else
{true}
}
catch(e){
dBar.error("Error in 'Visible' property for Aspect Tab for checkBoxGroup - " + e.toString)}}]]></xe:this.rendered><xp:checkBoxGroup
id="checkBoxGroup1" styleClass="threeColumnCheckboxGroup"
value="#{Subscription.Services}" style="width:100.0%">
<xp:selectItems>
<xp:this.value><![CDATA[${javascript:try{
if (sessionScope.Services[GHCTabIndex][EnviroTabIndex][AspectTabIndex] == null){
dBar.error("sessionScop.Services["+GHCTabIndex+"]["+EnviroTabIndex+"]["+AspectTabIndex+"] = null")}
else
{sessionScope.Services[GHCTabIndex][EnviroTabIndex][AspectTabIndex]}
}
catch(e){
dBar.error("checkBoxGroup")}}]]></xp:this.value>
</xp:selectItems>
</xp:checkBoxGroup>
</xe:djTabPane>
</xp:repeat>
</xe:djTabContainer>
</xe:djTabPane>
</xp:repeat>
</xe:djTabContainer>
</xe:djTabPane>
</xp:repeat>
</xe:djTabContainer>

All rows of the repeat are bound to the same sessionScope variable. That means they will replace not append to the scoped variable.
For binding editable fields within a repeat, you'll need to do something along the lines of Tim's answer to this question. I would recommend setting repeatControls="true" on all repeats, so the rows are created and bound when the page is loaded. You may get unpredictable results with components bound dynamically because, after the initial load, it's a one-way mapping from the component to wherever the value is stored. If the order of the repeat changes, the component values won't, and so the values will be out of step with what you expect.

Related

Properly capture chagnes of contenteditable <td> in bootstrap-vue b-table

So I have this problem with the rendering of contenteditable cells that drives me crazy. I have b-table like this
<b-table
v-once
v-if="showTable"
:small="true"
:items="timeSerres"
:fields="timeSerriesX"
:primary-key="timeSerriesX[0].key"
striped hover responsive selectable
#focusout.native="editCell"
>
</b-table>
I am setting :fields like this
this.timeSerriesX[j]={
key:'t-'+diff.toString(),
label:this.$moment(this.endDate).add(-diff, 'M').format('MMM-YY'),
tdAttr:{contenteditable:true}
}
I am setting :item, like this
this.rowText.split('\t').reverse().forEach(function(element,i_) {
row['t-'+i_]=element
});
this.timeSerres.push(row);
To detect editing I capture focusout native event and handle it like this
editCell(event)
{
var row_index = event.target.parentNode.rowIndex-1
var cell_index = event.target.cellIndex;
var newValue = event.target.innerText;
var row = this.timeSerres[row_index]
var key = this.timeSerriesX[row_index].key;
row[key]=newValue;
this.$set(this.timeSerres,this.rowIndex,row);
},
This approach works fine until I hit the corner case. When the cell is initially empty, and then I input data into the table cell, the input will be rendered twice when focus out.
E.g click on empty cell, input "1" then focus out the browser will render actually "11";
Or click on empty cell, input "ab" then focus out the browser will render actually "abab"
Please help!

Dojo Slider isReversed

What I am trying to do is detect, using onChange, if a dojo horizontal slider is being dragged right to left. This happens to be in IBM XPages, but the area of CSJS code below should be universal. How do I use the _isReversed property to get true/false?
<xe:djHorizontalSlider
style="margin-left:5px;width:200px;height:20px"
id="djHorizontalSlider1" showButtons="false"
defaultValue="1" maximum="15" minimum="1"
intermediateChanges="true"
discreteValues="8" value="#{viewScope.sliderNumber1}">
<xe:this.converter>
<xp:convertNumber integerOnly="true"
type="number">
</xp:convertNumber>
</xe:this.converter>
<xp:eventHandler event="onChange" submit="false">
<xe:this.script><![CDATA[
//I WANT TO DETECT IN THIS CSJS
//IF THE SLIDER WAS DRAGGED RIGHT TO LEFT
}]]></xe:this.script>
</xe:djHorizontalSlider>
When the onChange event happens the widget already changed its internal values making it almost impossible to detect any change here. But I wrote a small workaround to detect if the slider was moved from right tot left.
You should place this code inside your onChange handler. What it does is saving the current value in a data attribute on the widget itself. When another change occurs it will be checked against the new value and updated with the new value. This way you can compare the previous value (could also be the starting value) against the new value.
Hope this works for you!
// find dojo widget
var w = dijit.byId("#{id:djHorizontalSlider1}");
// get previous value from attribute (or default value)
var previousValue = dojo.attr(w.domNode,"data-prev-value") || w.params.value;
// log info about current and previous value
console.log("new value=" + thisEvent);
console.log("previous value=" + previousValue);
//save new value
dojo.attr(w.domNode,"data-prev-value",thisEvent);
// check value
if(parseInt(thisEvent) < parseInt(previousValue)){
alert("Detected slide right to left! new value="+thisEvent+", old value="+previousValue);
}

Remove "MIME type" column from Filent Content List

I am Using a Script Adapter by passing payload to get contend for a Content List from "Search with values" event
When Contend get loaded to content list , i have a custom view to preview them. But if i clicked on MIME type column , It opens a separate view with the mapped viewer
So I need to remove this column or make it un-clickable
1) I am passing search values to content list's "Search with values" event , from where can i handle Content List's contend loading ,any Dojo Event i can use ?
2) With Script Adapter can i do this without going for a "response filter"
Edit :
As Nicely explained by "Ivo Jonker" (in his answer - "or try to specifically locate the widgets on your page" and with his example code)
responsed = page.ContentList8.ecmContentList.getResultSet();
var cols = responsed.structure.cells[0];
for (i=cols.length-1; i>0; i--){
var col = cols[i];
if (col.field=="mimeTypeIcon")
cols.splice(i,1);
}
page.ContentList78.ecmContentList.setResultSet(responsed);
I simply remove this row. Thanks Again and lovely blog , hope you keep posting more great articles.
The values passed through the Search With Values event will eventually be handled by the icm.pgwidget.contentlist.dijit.DocumentSearchHandler
that in turn creates a SearchTemplate to execute the search (ecm.model.SearchTemplate.prototype.search). One option would be to aspect/before/around the DocumentSearchHandler#query to manipulat the searchresults and by that way to remove the column.
The wiring however does not provide any handles to achieve this for a specific query-resultset combination leaving you to either fix this on a global scale (icm.pgwidget.contentlist.dijit.DocumentSearchHandler.prototype#query), or try to specifically locate the widgets on your page.
Personally, taking into account #2, i'd go for the responsefilter-option if you feel the global solution wouldn't be a problem, or alternatively i'd personally prefer to create a simple ICM widget that instantiates/implements a "plain" ecm.widget.listView.ContentList and exposes a wire to set the ecm.model.Resultset.
You'd then be able to create your own Searchquery in a scriptadapter, remove the column, and pass the resultset.
The script adapter could be something like:
var scriptadapter=this;
var queryParams={};
queryParams.query = "SELECT * FROM Document where id in /*your list*/";
queryParams.retrieveAllVersions = false;
queryParams.retrieveLatestVersion = true;
queryParams.repository = ecm.model.desktop.repositories[0];
queryParams.resultsDisplay = {
"sortBy": "{NAME}",
"sortAsc": true,
"columns": ["{NAME}"],
"honorNameProperty": true};
var searchQuery = new ecm.model.SearchQuery(queryParams);
searchQuery.search(function(response/*ecm.model.Resultset*/){
//remove the mimeTypeIcon
var cols = response.structure.cells[0];
for (i=cols.length-1; i>0; i--){
var col = cols[i];
if (col.field=="mimeTypeIcon")
cols.splice(i,1);
}
//emit the resultset to your new contentlist, be sure to block the regular synchrounous output of the scriptadapter
scriptadapter.onPublishEvent("icm.SendEventPayload",response);
//The contentlist wire would simply do contentlist.setResultSet(response);
});

Modifying column header names in Master-Detail grid in Devexpress

I have a Master-Detail set up with 2 grids. On the master grid, I have the ShowOnlyPredefinedDetails option set to false.
This means that I see a little + sign that allows me to expand the details of the detail grid (in the master grid). I would like to rename
some columns in that section as well as hide certain columns. I'm using VB.NET How do I go about this. See image.
You can accomplish this by using the grid control ViewRegistered event, from there you can modify the columns in that grid view that have columns within them that you want to modify, rename, or remove. Here is an example, I hope that it helps:
private void myGridControl_ViewRegistered(object sender, DevExpress.XtraGrid.ViewOperationEventArgs e)
{
if (e != null)
{
if (e.View != null)
{
//Inside of this statement you can adjust, add, and modify all of the columns inside of that grid that appears when you click on the +
(e.View as GridView).Columns["myHiddenColumn"].Visible = false;
(e.View as GridView).Columns.Add(new GridColumn() { Name = "AddColumn", Caption = "Name To Display", Visible = true, FieldName = "DataField"});
(e.View as GridView).Columns["DataField"].OptionsColumn.AllowEdit = false;
(e.View as GridView).Columns["DataField"].OptionsColumn.AllowFocus = false;
(e.View as GridView).Columns["DataField"].OptionsColumn.ReadOnly = true;
}
}
}
I think all you need to do is create a second grid view for your details. If you haven't already done this, do the following:
In your grid designer, click "Retrieve Details" if you have not already done so. This will cause the designer to recognize that you have a second level in your bound object:
Once you see the second layer, now you need a new grid view for it. Click on "Click here to change view" and select "Create a new view" and pick "GridView."
Now you will see both grid views from the designer, and clicking on one or the other will change the context of the menus to the left:
For example, if you have gridView2 selected, when you click on the "Layout" menu, it will show the current layout for your detail grid rather than the master grid. From here, you can remove or add columns as you see fit. Likewise, from the "Columns" menu you will see the new columns (you may have to add them to the view by dragging them over), and you can change the Caption property to change the text of the title.
I suggest you use the Data Annotation attributes with properties of your data-classes to declare how you data should be displayed in GridControl:
To skip column generation for the specific property you can mark this property with the <DisplayAttribute(AutoGenerateField := false)> declaration.
To prevent column from displaying you can mark this property with the <DisplayAttribute(Order := -1)> declaration. Later, user can show this column via Column Chooser UI.
To specify the column caption use the <DisplayAttribute(Name := "YOUR CAPTION")> declaration.
You can also control filtering/editing/formatting and validation capabilities.
Related Links:
Tutorial: Create and Manage Data in Code and Apply Data Annotation Attributes
Video Tutorial: Create and Manage Data in Code and Apply Data Annotation Attributes

Dojo:how to find if the widget has focus in dojo

how do I find out if my custom widget has focus in Dojo?
i have dojo editor i wnat to know if the editor has already focus or not?
you can use the module dijit/focus to find out the focus
FROM DOJO DOCS
Tracking active widgets
At any point in time there is a set of (for lack of a better word)
“active” or “focused” widgets, meaning the currently focused widget
and that widget’s ancestors. “Ancestor” can mean either DOM ancestor
(ex: TextBox –> Form), or a logical parent-child relationship (ex:
TooltipDialog –> DropDownButton).
For example, if focus is on a TextBox inside a TabContainer inside a
TooltipDialog triggered by a DropDownButton, the stack would be
TextBox –> ContentPane –> TabContainer –> TooltipDialog –>
DropDownButton.
The activeStack[] parameter indicates this set of widgets, and an app
can monitor changes to activeStack[] by:
require([ "dijit/focus" ], function(focusUtil){
focusUtil.watch("activeStack", function(name, oldValue, newValue){
console.log("Focused widget + ancestors: ", newValue.join(", "));
});
});
the question in title has a different answer than the one in the descriptions.
there are two ways achieving the question in the title, by using dojo's focusUtil ("dijit/focus"). both ways give you something that you could find the widget using it and the dijit's registry ("dijit/registry").
focusUtil.curNode: gives you the DOM Node that currently has the focus. the function below, you could get the widget reference.
function getWidgetByNode(node){
var result;
while (!result && node){
result = registry.byNode(node);
if (node.parentElement)
node = node.parentElement;
else
node = null;
}
return result;
}
var focusedWidget = getWidgetByNode(focusUtil.curNode)
focusUtil.activeStack: gives you an array of the widgets (parent to child) that has the focus. so the last item in the array is the direct widget which has the focus. index values are widget ids, so you should get the widget by the following code
var focusedWidgetId = focusUtil.activeStack[focusUtil.activeStack.length-1];
var focusedWidget = registry.byId(focusedWidgetId);
now if you want to know if the currently focused widget is some specific one, it depends on what you have in hands from that specific widget:
widget itself: like the return values of above samples. now you have to compare if these are the same thing. you can not compare two widget objects using the == operator. you could compare their ids like this:
myWidget.id == focusedWidget.id
widget's id: this way you just easily get the id of the current node from focusUtil and compare it with the id you have liek this:
myWidgetId == focusedWidgetId
references:
http://dojotoolkit.org/reference-guide/1.9/dijit/focus.html
http://dojotoolkit.org/reference-guide/1.9/dijit/registry.html
require([ "dijit/focus" ], function(focusUtil){
var activeElement = focusUtil.curNode; // returns null if there is no focused element
});
check blow url here you can see some examples
http://dojotoolkit.org/reference-guide/1.8/dijit/focus.html#dijit-focus
a) For dojo 1.6: call dijit.getFocus(). This will return an object containing the currently focused dom node, among other things (selected text, etc.). To get the corresponding widget, simply do:
var activeElement = dijit.getEnclosingWidget(dijit.getFocus().node);
This is the full reference for dijit.getFocus(), from the source code:
// summary:
// Called as getFocus(), this returns an Object showing the current focus
// and selected text.
//
// Called as getFocus(widget), where widget is a (widget representing) a button
// that was just pressed, it returns where focus was before that button
// was pressed. (Pressing the button may have either shifted focus to the button,
// or removed focus altogether.) In this case the selected text is not returned,
// since it can't be accurately determined.
//
// menu: dijit._Widget or {domNode: DomNode} structure
// The button that was just pressed. If focus has disappeared or moved
// to this button, returns the previous focus. In this case the bookmark
// information is already lost, and null is returned.
//
// openedForWindow:
// iframe in which menu was opened
//
// returns:
// A handle to restore focus/selection, to be passed to `dijit.focus`.
b) For dojo 1.7 and up, use dijit/focus:
require([ "dijit/focus" ], function(focusUtil) {
var activeElement = focusUtil.curNode; // returns null if there is no focused element
});