I have a view panel where I want to style the color the of text in the row based on a value in the document.
<xp:viewPanel id="dataView1" var="rowData" rows="5"
rowClasses="#{javascript:rowData.getColumnValue('objectStatus') == 'Inactive' ? 'status-inactive' : ''}">
This works perfectly fine if the view has at least one document, but if the view is empty I get the following error:
com.ibm.xsp.exception.EvaluationExceptionEx: Error while executing JavaScript computed expression
Error while executing JavaScript computed expression
Script interpreter error, line=1, col=10: [ReferenceError] 'rowData' not found
I'm guessing it has something to do with rowData not being created unless a document exist, but I can't figure out how to check for it.
I tried if (rowData != null) and !#IsNull(rowData) but I still get the same error.
How do I solve this problem?
(Note that I am late to the XPages game.)
EDIT:
Thanks to all for the input but I was able to solve the issue by simply checking the view count:
if (getComponent('dataView1').getRowCount() > 0) {
'Inactive'.equals(rowData.getColumnValue('objectStatus')) ? 'status-inactive' : ''
}
EDIT 2:
Knut has a slightly quicker solution so I gave him credit.
You can test it with if (typeof rowData !== 'undefined') ....
If the view is empty then rowData is 'undefined'.
<xp:viewPanel id="viewPanel1" var="rowData" rows="5"
rowClasses="#{javascript:
if (typeof rowData !== 'undefined')
rowData.getColumnValue('objectStatus') == 'Inactive' ? 'status-inactive' : ''
}">
(This solution is probably some ms faster than .getRowCount() :-) )
Knut correctly explains the solution to what you're trying to do. The answer to why it doesn't work is slightly different. rowData was an apt name to choose, it's going to be the current row's data. But you're setting a property for the DataView as a whole. What is the current row for the whole DataView? The answer is, there isn't one because you're not dealing with an individual row.
Related
I have created a function in SSJS Library. Because I use it in more than one XPages.
When I call this function behind a button I cannot see the value in the field
If I print it out I can see the value at the Admin Console but cannot see it in the form Even if I get page with full refreshed.
Actually my another question is.. is it possible to compare notesXSPDocument and NotesDocument. Maybe someoen can say that what is the best way for that?
function deneme(document1:NotesXSPDocument,otherDocfromOtherDatabase:NotesDocument)
{
//do staff here
if (document1.getItemValueString("field1")==otherDocfromOtherDatabase.getItemValueString("field2"))
{ //do some staff here...
document1.replaceItemValue("fieldName","FieldValue");}
}
You can compare item values from Document and XSPDocument, just be careful with the type you are comparing.
In your code you are comparing 2 javascript strings with == operator.
The code seems to be OK, just remember to save the document1 after the changes and maybe check that the items have some value.
var valueFromXspDoc = document1.getItemValueString("field1");
var valueFromDoc = otherDocfromOtherDatabase.getItemValueString("field2");
if (valueFromXspDoc && valueFromDoc && (valueFromXspDoc === valueFromDoc)) {
// stuff here...
document1.replaceItemValue("fieldName","FieldValue");
document1.save();
}
Don not compare it with == sign. A better way is to document1.getItemValueString("field1").equals(otherDocfromOtherDatabase.getItemValueString("field2"))
I've been able to successfully create dynamic field names and save the values for input fields using the technique described here: http://lpar.ath0.com/2014/04/07/repeated-xpages-input-controls-with-number-indexed-field-names/
I also have a computed field which has a number indexed name but whose value is computed based on a keyword choice. I can assign the dynamic field name for it like so:
<xp:text escape="true" id="computedField1">
<xp:this.value><![CDATA[#{compositeData.dataSource[compositeData.fieldName2]}]]></xp:this.value>
</xp:text>
The property definition for this field looks like this:
and the call to the composite control looks like this:
<xc:cc_dynamicAssetItems
row="#{(rownum lt 10)? '0':''}#{rownum}"
dataSource="#{document1}"
fieldName1="replace#{(rownum lt 10)? '0':''}#{rownum}"
fieldName2="budget#{(rownum lt 10)? '0':''}#{rownum}" >
</xc:cc_dynamicAssetItems>
I am at a loss however on how to pass the value to this computed field. The SSJS for it would have been:
var projectNumber = getComponent("ProjectNumber").getValue();
if(projectNumber == ""){
return "Nothing found";
}else{
return projectNumber + "A";
}
I'd appreciate some direction.
Thanks,
Dan
Instead of setting the value of your component, you should set the value of the underlying datasource. This means that your logic should not run in your computed field, than in your onChange event of the ProjectNumber component.
Then you have to update e.g. document1.budget01 only, which is a lot faster.
As an alternative, you can still pass a method binding* to your custom control, as described here: Pass javascript code to Custom Control
(*: in your case a value binding)
did you try javascript instead expression language
ex:
fieldName1="#{javascript: 'replace'+(rownum > 10? '0':'')+rownum}"
I have created an XPage with the following: Started by creating a custom layout control using the Application Layout. I aded the layout control to the xpage and then dropped in a Dynamic Content Control. I configured the control as follows:
<xe:dynamicContent id="dynamicContent1" defaultFacet="GovernanceReviews"
useHash="true">
<xp:this.facets>
<xc:ccViewDocumentTemplates xp:key="DocumentTemplates"></xc:ccViewDocumentTemplates>
<xc:ccViewGovProcurementReviews xp:key="GovProcurementReviews"></xc:ccViewGovProcurementReviews>
<xc:ccViewGovRevReporting xp:key="GovRevReporting"></xc:ccViewGovRevReporting>
<xc:ccViewGovRevWOCompleted xp:key="GovRevWOCompleted"></xc:ccViewGovRevWOCompleted>
<xc:ccViewGovernanceReviews xp:key="GovernanceReviews"></xc:ccViewGovernanceReviews>
<xc:ccViewProfilesByType xp:key="ProfilesByType"></xc:ccViewProfilesByType>
<xc:ccViewProfilesWithTargetCompl xp:key="ProfilesWithTargetCompl"></xc:ccViewProfilesWithTargetCompl>
<xc:ccViewLastUpdated xp:key="LastUpdated"></xc:ccViewLastUpdated>
<xc:ccViewUserGuide xp:key="UserGuide"></xc:ccViewUserGuide>
<xc:ccViewTracking xp:key="Tracking"></xc:ccViewTracking>
</xp:this.facets>
</xe:dynamicContent>
Then I dropped in a navigator control in the left column and created BasicLeafNodes to correspond to the dynamic content control I used the href property and used the #content="" to display the correct content.
This works just fine, but I am having problems figuring out how to make the selections in the navigator highlight when they are selected. I know I need to compute the Selectd property,but I can't figure out how to get the xp:key value so I can compare it to the SubmitValue. I know this is probably something simple, but I can't figure it out.
Can someone please enlighten me.
Thanks,
MJ
ADDED 03/26/2014 - I have a feeling that it has something to do with Using the href property of the Dynamic Content Control to perform the content switching. I know that makes the BasicLeafNodes Links. So, not sure how the Navigator records which link is being executed and how to capture that.
MJ
Add a value is the submitValue property
And in the onItemClick Event
Assign the submitted value to a viewScope variable
viewScope.Selected=context.getSubmittedValue()
And finally check if the viewScope variable equals your item submit value in the selected property. This needs to be calculated
if(viewScope.Selected="byCategory"){
return true
}else{
return false
}
The following is working for me:
if(viewScope.Selected == "byCategory"){
return true
} else{
return false
}
An equality test must be made with two equal symbols (or three). One equal symbol evidently always returns true.
I did it by jQuery. Just put the following code to the custom control, which contains navigator.
$( function() {
if (window.location.hash.length > 0) {
select()
}
});
$(window).on('hashchange', function() {
select();
});
function select() {
$(".lotusColLeft .lotusMenu .lotusBottomCorner li").removeClass(
"lotusSelected")
$(".lotusColLeft .lotusMenu .lotusBottomCorner li a")
.filter(
function() {
return window.location.hash.indexOf($(this).attr(
'href')) > -1
}).parent().addClass("lotusSelected")
}
I am working with Position Absolute's Form validation engine.
I have a specific case for validation that I'm hoping this can solve for me. I need to be able to make one field required based on the value of another field.
For example:
If country.dropdown = "USA", then state.dropdown is required.
or
If country.dropdown <> 'USA" then state.dropdown is not required.
Do you think this is possible with JQuery Validation Engine? If so, can you point me in the right direction?
I have to say, first, that I have never used the Position Absolute's Form validation engine,
but I got interested in it reading your question.
From the documentation ( https://github.com/posabsolute/jQuery-Validation-Engine ), it appears that you have to create a custom validation function.
I created a working fiddle here: http://jsfiddle.net/5pKjW/6/
Even if it works, I am not completely satisfied with it, because a "sentinel value" is needed because of this condition in the validation engine at line 584.
// If the rules required is not added, an empty field is not validated
if(!required && field.val() == "" && !errorMsg) options.isError = false;
This is the markup of the select withe the custom function:
<select class="validate[funcCall[checkCountry]]" type="text" name="state" id="state">
<option value="none" ></option>
<option value="CALIFORNIA" >CALIFORNIA</option>
<option value="NEW ENGLAND" >NEW ENGLAND</option>
<option value="TEXAS" >TEXAS</option>
</select>
And this is the validator initialization:
jQuery("#formID").validationEngine({
'customFunctions': {
'checkCountry': function (field, rules, i, options){
if ($('#country').val() === 'USA' && field.val() === 'none') {
return options.allrules.required.alertText;
}
}
}
});
1) First, you have to define a validation function that can be global or can be passed as an argument of the plug-in (as I did above). A custom function accepts this inputs: field, rules, i, options.
You have no reference to the form, you only have reference to the current field.
So if you want to access another field, you have to select it as usual with jQuery (in the example: $('#country') ).
2) You check for the validation condition. In the example it fails if:
$('#country').val() === 'USA' && field.val() === 'none'
If the condition is not respected, the function must return a String. In the example, I returned the standard message in options.allrules.required. The documetation explains how to define custom messages for custom functions.
As you can see, because of the
if(!required && field.val() == "" && !errorMsg) options.isError = false;
line in the validation engine, the developer is forced to make the condition inside the if fail, and setting the required condition to true or the error message to a falsy value is not right. So, the only way is to make field.val() != ''.
For this reason, the first option element in the markup has the sentinel value none, instead of being empty. It is not a clean solution, and it may even not be possible to implement easily (I don't know if you generate the markup yourself (if you don't, things get more difficult and you need to manipulate the form via javascript, before the validation engine initialization)).
This is not a clean solution.
A nicer solution would have been using condRequired, if only it would have accepted a custom function, instead of only checking if one of its arguments had been populated.
I have an ObservableColection totalsCol and want to retrieve an object whose id matches the specified id. I coded as :
IEnumerable<Totals> ie = totalsCol.Where(a => a.IdCTS == ct1.TOR_Id);
if (ie.Count() > 1)
{
// Update the TotalCts of Totals object
ie.ElementAt(0).TotalCTS = ct1.TotalCts;
CalculateTotalsPercent();
}
I get ie.count as null. Whereas it has 3 records. And on debugging, I can see that under Source of base.
Where am I wrong here ? I beleive the way am updating the the value with ie.ElementAt will reflect changes in totalsCol observableCollection.
Kindly help me out.
I implemented :
totalsCol.First(a => a.IdCTS == ct1.TOR_Id);
and solved the issue.