How to prevent full refresh using onChange event SSJS - xpages

(You may be able to figure out an answer by ONLY reading the last question by itself, but I included everything for reference if necessary)
The onChange of one field is causing displayErrors to show validation results prior to when I need it to do that.
On an xpage, I have these two comboboxes:
1.) locationType
2.) locationEtc
Choices for locationEtc are dependent on what was selected in locationType field.
In the locationEtc field, the choices are using one computed value with this code:
try
{
var locType = getComponent("locationType").getValue();
var key = '';
switch(locType) {
case 'Commuity Service Center':
key = 'loc_cso';
break;
case 'RYDC':
key = 'loc_rydc';
break;
case 'YDC':
key = 'loc_ydc';
break;
case 'HQ':
key = 'loc_hq';
break;
default:
key = 'facilities';
}
var luChoices = #DbLookup('','keywords', key, 'choices');
luChoices.unshift("Select one|''");
return luChoices;
}
catch(e)
{
print("Error:::::"+e);
}
The choices were NOT changing for locationEtc whenever I pick a locationType, but then they do when I add code to clear the location field whenever locationType changes, using a simple action for onChange event of locationType field:
This is great, but when it all refreshes, my displayErrors control appears (yellow background area) showing required field validation results, and a lot of the fields are not filled in yet by design.
How can I make the displayErrors to show ONLY when tying to submit?
Thanks everyone who can help.
Matt

Set disableValidators="true" on the simple action that you created

Related

SwiftUI ColorPicker "opened" and "closed" events?

I need to be able to undo / redo the colors that are picked with the new SwiftUI ColorPicker ( on the iPad : it's presented as a floating window )
The thing that makes it very difficult is that there is apparently no way to know that the user has indeed chosen a color ( and therefore closed the panel )
Instead, the behavior of ColorPicker is that it will keep updating the binded color as the user is manipulating the color controls. This is very helpful to show a live preview, but you don't want to register all these color variations for undo / redo purposes : you only want the color that was finally picked.
Therefore there is no logical distinction between the colors that the user tried, and the one that was selected
And I looked everywhere : there aren't any modifiers / notifications related to that.
I know SwiftUI hasn't been there for long, but this seems like a crucial functionality that's missing?
Has anyone found a workaround?
Undo is always tricky. One size does not fit all. In this case a good solution is to throttle the number of events that come into the UndoManager. You can do so by comparing the current time to the time you last commit.
Create a view model that represents your Source of Truth, and conform to ObservableObject to publish events. It will own the UndoManager. It will have a computed property that gets/sets to the internal data, and check the current time against the time of last commit.
class EditViewModel: ObservableObject {
var commitTime = Date.now
let undoManager = UndoManager()
private var _color: Color = .red {
didSet {
objectWillChange.send()
}
}
var color: Color {
get { _color }
set {
let oldValue = color
let now = Date.now
if now.timeIntervalSince(commitTime) > 1 {
undoManager.registerUndo(withTarget: self) {
$0.color = oldValue
}
}
self.commitTime = now
_color = newValue
}
}
}
Now all that's left to do is create your view and pass in the binding. The implementation details are opaque to the View since it is managed by the ViewModel.
struct EditView: View {
#StateObject var vm = EditViewModel()
var body: some View {
Form {
ColorPicker("Color", selection: $vm.color)
}
}
}
If you need even more control, you can additionally compare the last committed color to the new value and only commit if there is a significant change.
I will also agree that a data-driven approach like SwiftUI's can make undo more tricky. For example, when you need to coalesce multiple operations together into one undo group. By its very nature an undo group is procedural-- the user did one thing after the other, and finally terminates on some condition. But I'm sure there is some way to encapsulate this step-wise operation in a transaction object of some kind.
Undo is hard!

NetSuite SuiteScript Client Side drop down validation

I have a custom form where, in a subtab, I have a dropdown that I need to find out the selected value on the client side after the user selects to perform some validation. I created the script and tied it to the on change event of the dropdown. I cannot seem to find the code to get the selected value on the client side. I have found code to read the value on the server side from a submit event. I need this on the client side on change. I am going to use the ID to look up a record and check a value on that record and if applicable popup a warning to the user. Either SS1 or SS2 is good, whatever would be better I have both available. Any help with this would be great. thanks
In a client script, you can use nlapiGetFieldValue() to retrieve the results.
function fieldchanged(type, name, linenum) {
if(name == 'dropdownid') {
var value = nlapiGetFieldValue('dropdownid');
alert(value);
}
}
OK the nlapiGetFieldValue, did not do the trick, what did was the following
function ValidateField( type, field, linenum ) {
if ( field === 'recordid' ) {
var vendorid = nlapiGetCurrentLineItemValue(type,field,linenum);
var vendorRecord = nlapiLoadRecord('vendor',vendorid);
}
return true;
}
thanks for your help

Material Angular md-autocomplete clear and blur after selection (multi select)

I am trying to use md-autocomplete in Angular Material as a multi selector. The idea is, that the selected element from the autocomplete will be added to an object array after selection and then the selection will be removed from the md-autocomplete. I was able to clear the md-autocomplete, but the focus stays on the md-autocomplete input and so the autocomplete suggestions are still visible.
Example:
http://cdpn.io/QjQGVQ
Code:
function selectedItemChange(item) {
$log.info('Item changed to ' + JSON.stringify(item));
if(item)
{
//check if item is already selected
if($filter('filter')(vm.contactsSelected, function (d) {return d.id === item.id;})[0])
{
$log.info('Item already selected. Will not add it again.');
}
else
{
//add id to object
vm.contactsSelected.push(item);
}
// clear search field
vm.searchText = '';
vm.selectedItem = undefined;
//somehow blur the autocomplete focus
//$mdAutocompleteCtrl.blur();
}
}
PS: I am aware I could use the contact chips of Angular Material instead, but I was still wondering how the blur could be achieved.
If you set md-no-cache="true" property inside your the list will dissapear, but input field will not be cleared. I think is better solution than clearing input field but leaving the list visible, but is up to you.

Write the plugin when Selecting the lookup flied and according to filed selection Show/Hide Address filed in form.....?

We Have Contact Entities in contact Entitie one lookup filed company Name in that lookup having two values 1.Account and 2.Contact . When we are selecting contact show the address filed when we select account hide the address filed we needs to write the plugin to Execute that works. Kindly any one help me on the same.
Thanks!!
Rajesh Singh
First, if you need to make change on a form, you can't use plug-ins. Plug-ins are made for bussinees logics, like Update another record when the first one is created, make complex logic, etc...
What you need it is a javascript that executes on the OnLoad of the form and OnChange event in that OptionSet.
The lines you are looking for are:
function ShowField()
{
// The field is present on the form so we can access to its methods
var optionSet = Xrm.Page.getAttribute("custom_attribute");
if (optionSet == undefined)
{
return;
}
// The control is present on the form so we can access to its methods
var controlAddress = Xrm.Page.getControl("custom_address");
if (controlAddress == undefined)
{
return;
}
var valueOptionSet = optionSet.getValue(); // This is the value you set creating the OptionSet
switch (valueOptionSet)
{
case 0: // Your account value, show
controlAddress.setVisible(true);
case 1: // Your contact value, hide
controlAddress.setVisible(false);
default:
return;
}
}
You need to register a web resource and register the event, if you need more information about the code or why this stuff is here and why this not just tell me.

xpages custom deleting doc. from view panel

I'm trying to delete selected doc from viewPanel1. The view is categorized ( can be > 1 category ) and is listing documents from 2 different datasources, let say: Cdoc and Pdoc. These docs. are linked by a common field.
my scenario: If the users select a Cdoc => the delete action will take place to the respective Cdoc but also for the all Pdoc being in the same category. If the user selects a Pdoc => delete just the Pdoc. Also, I would like to add some confirmation text with some information ( Value fields ) from the selected documents.
I tried the following
var viewPanel=getComponent("viewPanel1");
var docIDArray=viewPanel.getSelectedIds();
for(i=0;i < docIDArray.length;i++){
var docId=docIDArray[i];
var doc=database.getDocumentByID(docId);
var formName = (doc == null)? null : doc.getItemValueString("Form");
if( formName =="fmPersContact" ){
.....
} // in this case, it works OK.
else if ( formName =="fmCompanie" ){ // here if I selected > 1 Cdoc, it deletes just one Cdoc + the respective PDocs.
var doc:NotesDocument = null;
doc=database.getDocumentByID(docId);
var ky:java.util.Vector = new java.util.Vector();
ky.add(doc.getItemValueString("txt_NumeCompanie"));
... // delete method
}
Could you tell me what I did wrong and what am I missing in the above code? thanks for your time!
The first thing you want to do is confirm. Unlike Lotusscript, you cannot use a function in the middle of a script to open the confirm dialog and get the answer. To do this, I recommend using the confirm simple action before going into an execute script simple action.
<xp:button
value="delete"
id="button1"
>
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action>
<xp:actionGroup>
<xp:confirm message="Are you certain?"></xp:confirm>
<xp:executeScript
script="#{javascript:doSomething();}"
>
</xp:executeScript>
</xp:actionGroup>
</xp:this.action></xp:eventHandler></xp:button>
EDIT
In the past, I have also used built my own dialogs with the extension library, filled the text in with SSJS and then called the doWhatever() or close() from the dialog itself. This is not the best solution as it requires an update from the server to get the string. The best solution would be, as Paul Withers says, to use CSJS to perform the confirmation. I have yet to do this though.
/EDIT
For your delete function, I recommend getting the document you want to delete, then tell whether it is a P- or C- doc, either by the form name or whatever mechanism you use, and then either delete the single document or by getting a documentcollection from the view by using getAllDocumentsBykey(), then iterating through them all, deleting them one by one.
var ky:java.util.Vector = new java.util.Vector();
ky.add("MainCat");
ky.add("subCat");
ky.add("subCat2");
var vw:NotesView = database.getView("vw_myView");
var docs:NotesDocumentCollection = vw.getAllDocumentsByKey(ky);
//... delete stuff...
//dont forget to recycle
Post Question Edit
I recommend the following to get the form name:
var getSelectedDoc = function(){
var vwPnl = getComponent("viewpanel");
var ids = vwPnl.getSelectedIds();
var id = null;
var doc:NotesDocument = null;
if(ids.length > 0){ //could use for loop var i = 0; i < ids.length;i++
id = ids[0]; //could pack all ids into java.util.ArrayList and return that list to work on further
//be warned that if the user selects a parent doc and those automatically deleted by it that you need a mechanism to check if the document was already deleted!
}
if(id != null){
doc = database.getDocumentByID(id);
}
return doc;
}
var doc = getSelectedDoc();
var formName = (doc == null)? null : doc.getItemValueString("form");
if(PDOC_FORM_NAME.equalsIgnoreCase(formName)){
deleteFunctionComplete(doc);
} else if (CDOC_FORM_NAME.equalsIgnoreCase(formName)){
deleteFunctionTwo(doc);
} else {
// uh-oh
}
this also allows you to have the document in case you want to delete it right away.
Edits for comments
If Cdoc should delete more than one document, then yes. You should be using the getAllDocumentsBykey keeping in mind that the view needs to be built for it. By that I mean if you have a view with one single category, there is no issue, just plug in the string and you are fine. If you have a view with three categories, you cannot feed a vector into the getalldocs function with only two values, it must be all three. So, you want to delete all for "mycomp" with the underlying pdocs "Greg" "Sally "Bob", just use alldocsbykey("mycomp"), if the view looks like:
mycomp
---Greg
---Sally
---Bob
but if the view looks like
Poland
---mycomp
------Greg
------Sally
------Bob
then the a vector with poland and mycomp must be used. "poland" does not get the correct documents. --just an fyi and pitfall that is sometimes had.
Edit after further question clarification
I prefer this loop style to remove docs
var doc_temp:NotesDocument = null;
var doc_toDelete:NotesDocument = null;
var coll_docs:NotesDocumentCollection = ...; //get document collection
var doc_nextDoc = coll_docs.getFirstDocument();
while(doc_nextDoc != null){
doc_temp = doc_nextDoc; //set document to delete
doc_nextDoc = coll_docs.getNextDocument(doc_nextDoc); // set next document before deletion
try{
doc_temp.remove(true);//lots of errors can happen here, such as ACL settings
} catch(e) {
//handle, or just break
} finally{
if(doc_temp != null) try{doc_temp.recycle()} catch(e){}// try to recycle, could also cause errors
doc_temp = null;// for the sense of completeness
}
}
Even further edit based on the question edits
of course you are only deleting one Pdoc, the way you have that set up, you are only ever returning one document. You could expand the getSelectedDoc() to put all selected documents into an java.util.ArrayList or something, and then use that arraylist to delete more than one at a time, but that could be dangerous depending on what you do because NotesDocuments are not serialisable. In that case, I recommend using the same code that you use for getSelected doc, use a for loop to get the document IDs, get the document, if the document is not null, then delete.
apropos getAllDocumentsByKey(with a vector)
The way this is currently set up, no Vector is necessary.
If you have a view with a category and sub category and you want to get all the documents in that sub category, then you must use a vector to get at it. If you include a simple string or a vector with only one value, then the documents in the sub category will not be returned. The vector can be thought of as "cat1", "subcat", "furtherSubCat"
Furthermore, there is no check here to see if the string returned from the document is empty. This should be done. There is also no check to see if the DocumentCollection is empty. This should also be done. My expectation is that there is an issue retrieving the collection based on above mentioned reasons.

Resources