How to make my validator conditional based upon SSJS check (Xpages)? - validation

I have a function to call which component on my XPage performs a submit to the server:
//Used to check which if a component triggered an update
function submittedBy( componentId ){
try {
var eventHandlerClientId = param.get( '$$xspsubmitid' );
var eventHandlerId = #RightBack( eventHandlerClientId, ':' );
var eventHandler = getComponent( eventHandlerId );
if( !eventHandler ){
return false;
}
var parentComponent = eventHandler.getParent();
if( !parentComponent ){
return false;
}
return ( parentComponent.getId() === componentId );
} catch( e ){ /*Debug.logException( e );*/ }
}
I have a validator which is called normally via expression language:
validator="#{applicationValidators.valPhone}"
I would like to make the validator conditioned by a check if the submit is done by the element/component with the btnSave id on it e.g.
<xp:this.validator><![CDATA[#{javascript:if (submittedBy('btnSave')){
return applicationValidators.valPhone();
}}]]></xp:this.validator>
but the valPhone funktion expects some inputs which are injected automatically if I call the method via EL:
public void valPhone(FacesContext facesContext, UIComponent component, Object value)
Is there a way to include the submittedBy function in the EL or must I supply the objects when calling the function in SSJS cause for now I get the error message:
Error while executing JavaScript action expression Script interpreter
error, line=2, col=38: Java method 'valPhone()' on java class
'org.acme.projectx.test.ApplicationValidators' not found
When I apply the objects e.g.
applicationValidators.valPhone(facesContext,getComponent("inpPhone"),getComponent("inpPhone").getValue());
it does run the validator method but does not seem to know how to handle the response (in my case I throw a ValidatorExeption with a message.
Error while executing JavaScript action expression Script interpreter
error, line=4, col=31: Error calling method
'valPhone(com.ibm.xsp.domino.context.DominoFacesContext,
com.ibm.xsp.component.xp.XspInputText, java.lang.String)' on java
class 'org.acme.projectx.test.ApplicationValidators' Phone is not
valid
Phone is not valid is the string message that I included in the FacesMessagge that I throw in the ValidatorExeption.

I'd take a totally different approach:
create a page controller class
call a method in the controller when the button is clicked
do your validation based on your value(s) in that method
if validation fails create a message in the validation error stack
I don't have a reference right now but this would be much easier to program and control in general.

Related

Wakanda callMethod synchronous mode

I'm trying to use callMethod() from a method executed on the server.
In this case, I should be able to call it in synchronous mode. However, through trial and error I have found that in this context (i.e. on the server), the method requires three parameters rather than the two mentioned in the docs.
It requires
the first parameter to be a string
the second parameter to be an array
the third parameter to be an object
I've tried quite a few combinations with these parameters but nothing seems to work. At the same time, Wakanda doesn't throw an error as long as the parameters are in the correct form.
Any ideas would be more than welcome.
TIA
Let's suppose we have two variable, one containing the name of the dataClass and the second the name of the dataClass's method :
var myDataClass = "User";
var myMethod = "addUser";
To use the dataClass 'User' and call the method 'addUser' you can do it this way :
var currentClass = ds.dataClasses[myDataClass];
currentClass[myMethod]()
The method callMethod() is a clientSide method, it should be used on prototyper Js files.
try to use it on a button.click event :
button1.click = function button1_click (event)
{
ds.User.callMethod({method:"method1", onSuccess:myFunction, onError:failure});
function myFunction(){
return true;
}
function failure(){
return false;
}
};
To call method in a serverSide js File in a synchronous mode, you can just make the call in this manner :
var test = ds.User.method1();

grails 2.4.2 - timepoint of validation of domain object

I have got a domain class with some custom validators like the following:
class Domain {
String attribute1
OtherDomain attribute2
static constraints = {
attribute2 nullable: true, validator: {OtherDomain od, Domain d ->
if (od) {
log.debug "entering validation"
// certain validation here
}
}
}
For updating I have got a simple action in the corresponding DomainController:
#Transactional
def update(Domain domainInstance) {
log.debug "entering update()"
// rest of update
}
I'm wondering why in my debuglog I get the debug messages in the following order:
entering validation
entering update()
The problem is that the validation fails at this point (StackOverflowError). I know the reason for this error and I know what to do to circumvent this error (doing so within update action). However, I don't know why there is a validation before the programme even gets into the update() action. And I don't know how to prevent a validation at this point.
Do you have any suggestions?
The reason you see the "entering validation" message before "entering update()" is because you have declared a command object of type Domain. This means that Grails will bind any request parameters to domainInstance and then call validate() on it, before the action is executed. This allows you to write code like this:
#Transactional
def update(Domain domainInstance) {
// at this point request params have been bound and validate() has
// been executed, so any validation errors will be available in
// domainInstance.errors
if (domainInstance.hasErrors() {
// do something
}
log.debug "entering update()"
}

Fallback callback when calling unavailable function

Is it possible to set a fallback callback which is called when the user wants to call a function which does not exists? E.g.
my_object.ThisFunctionDoesNotExists(2, 4);
Now I want that a function is getting called where the first parameter is the name and a stack (or something like that) with the arguments passed. To clarify, the fallback callback should be a C++ function.
Assuming your question is about embedded V8 engine which is inferred from tags, you can use harmony Proxies feature:
var A = Proxy.create({
get: function (proxy, name) {
return function (param) {
console.log(name, param);
}
}
});
A.hello('world'); // hello world
Use --harmony_proxies param to enable this feature. From C++ code:
static const char v8_flags[] = "--harmony_proxies";
v8::V8::SetFlagsFromString(v8_flags, sizeof(v8_flags) - 1);
Other way:
There is a method on v8::ObjectTemplate called SetNamedPropertyHandler so you can intercept property access. For example:
void GetterCallback(v8::Local<v8::String> property,
const v8::PropertyCallbackInfo<v8::Value>& info)
{
// This will be called on property read
// You can return function here to call it
}
...
object_template->SetNamedPropertyHandler(GetterCallback);

Backbone.js Backbone.wrapError function

This questions was about Backbone 0.9.2
Since upgrading to Backbone 0.9.10 we've chosen to override Backbone.sync instead and it works like a charm.
December 2012 - (v0.9.9) Backbone.wrapError has been removed.
February 2013 - It looks like WrapError will be brought back in the next version of Backbone, but overriding backbone.sync is the way to go.
(sorry for the long read)
I'm modifying the Backbone.wrapError function and I'm baffling by a line. I know what the line does, but not WHY it is necessary.
resp = model === originalModel ? resp : model;
resp ends up being the textStatus/errorType ie: "error" "timeout"
"parse error"
model is the XHR request object
originalModel is a reference to the Backbone.Model instance which ultimately called this function
I have a good grasp on what Backbone.wrapError does, what it returns and how it is used but I can't seem to understand the purpose of the above line.
Backbone's documentation states that wrapError will 'Wrap an optional error callback with a fallback error event,' which is true. Additionally, I've learned is that Backbone.wrapError is called 4 times in the library from within the fetch, save, destroy and reset functions in order to ensure that AJAX errors do not go unnoticed by the library. For example, if an AJAX error callback is passed into the fetch method it will be executed with a few parameters passed along, if not, the model will trigger an error event with the same few parameters passed along.
Sample call:
options.error = Backbone.wrapError(options.error, model, options);
Backbone.wrapError:
Backbone.wrapError = function(onError, originalModel, options) {
return function(model, resp) {
resp = model === originalModel ? resp : model;
if (onError) {
onError(originalModel, resp, options);
} else {
originalModel.trigger('error', originalModel, resp, options);
}
};
};
The problem that arises with this line (resp = model === originalModel ? resp : model;) is that model and resp correspond to the first 2 parameters within the jQuery/Zepto error callback parameter list. The first problem I have is with the naming of these parameters (model, response), because while debugging I've seen that those 2 parameters are jqXHR/xhr and textStatus/errorType. The textStatus/errorType parameters usually end up being "error" but (according to the docs) can also be "timeout" "parse error" etc. The comparison of model === originalModel makes no sense to me. A hard comparison on an XHR object and a Backbone.Model instance will always fail, and model will be stored into response (resp), which is fine because the model is actually the XHR response object... this line just seems pointless to me, but I went ahead and included it in my modified wrapError method.
Because model === originalModel always evaluates to false, the line seems to be an elaborate version of resp = model; which is useless, because you could just remove the line entirely and the model parameter could be passed into originalModel.trigger('error', originalModel, resp, options); instead of resp.
Is there any instance where model === originalModel could possibly evaluate to true?
Anybody with more experience in Backbone.js, AJAX have an answer/explanation of why this line is necessary?
TLDR/CLIFFS:
The weird little line below is used to determine weather the error callback was triggered from a failed validation at the model level, or from a failed AJAX call from the fetch, save, or destroy methods (which all call Backbone.sync). If the failure is from validation, it does not change the resp variable because resp should already hold useful information returned by validate (such as an errors array or a string about the error). If the failure is from a bad AJAX request, the XHR object is stored into resp because the XHR is the most informative item available. Unfortunately, the XHR is passed into this function as model and Backbone documentation fails to point out that this parameter does not always represent a model. Resp is meant to hold useful response information about the error(s), and is sent to the error callback or a thrown error event.
Okay. I learned some things about this weird line.
resp = model === originalModel ? resp : model;
In Backbone there are AJAX errors and Validation errors. Conveniently, Backbone funnels both errors into the same function -- the AJAX error callback. The problem is that the arguments passed into these functions are inconsistent. When there is an AJAX error an XHR object is available, but not during a validation error.
If there is no callback present, Backbone will throw and 'error' event with the same parameters that would have been passed into the error callback. (line 7 and 9 below).
After a successful AJAX request, your JSON data can be optionally passed through the model's validate function. In Backbone, the validate function should return false or nothing at all when there are no errors. When there ARE errors, it is typical to return an array such as ['invalid username', 'password too long', 'etc...'] Anything returned from validate (usually an error messages array) is passed into the 'wrapped' error callback as the resp parameter and the model itself is passed as model!
The _validate function is a bit sloppy and has multiple return statements, but when validation fails, line 9 is hit. Line 9 of the _validate function passes this (the model), error (returned from the models validate method), options (ajax options, success, error, timeout etc). This differs from an AJAX error which will pass in xhr (xmlhttprequest object), errorType ('error' 'timeout' 'parse error' etc), options (ajax options).
validate error: error(model, validate_return_value, options)
ajax error: error(xhr, errorType, options)
1 _validate: function(attrs, options) {
2 if (options.silent || !this.validate) return true;
3 attrs = _.extend({}, this.attributes, attrs);
4 var error = this.validate(attrs, options);
5 if (!error) return true;
6 if (options && options.error) {
7* options.error(this, error, options);
8 } else {
9 this.trigger('error', this, error, options);
10 }
11 return false;
12 }
The strange line of code above is necessary because, this one function handles errors from 2 different methods. AJAX and Validation. Those 2 send it different parameters, so this is meant to normalize them and throw events with consistent parameter lists.
When a validation error occurs, the model does not change so the model that is passed into the error callback is exactly equal to the originalModel. The purpose of the resp parameter is to hold information about the error itself. When there's an AJAX error, 'timeout' 'parse error' or 'error' are simply not as informative as the XHR object.
That weird little line determines weather the error callback was accessed from _validate or through a normal AJAX error such as a 404. When it is accessed from validate, resp is the value returned from validate. It should be informative, and useful data for the front-end templates to display. When the resulting error is from a HTTP error, the most useful information about that error is the XHR object which is passed into this function as the MODEL parameter.
A hopefully simplified approach to the wrapError and validate functions
Backbone.wrapError = function(ajax_error_callback, model_or_xhr, ajax_options) {
return function(model_or_xhr, error_info) {
if there was an ajax error, error_info = the xhr object
if there was a validation error, error_info = whatever was returned from validate
if there's an error callback {
run the error callback with (the original model, error_info, ajax_options) as parameters
if there is not an error callback
throw an event called 'error' with (the original model, error_info, ajax_options) as parameters
}
};
};
original:
Backbone.wrapError = function(onError, originalModel, options) {
return function(model, resp) {
resp = model === originalModel ? resp : model;
if (onError) {
* onError(originalModel, resp, options);
} else {
originalModel.trigger('error', originalModel, resp, options);
}
};
};
The * shows that error callback called from here

Using only a controller in FW1 without a view

I have an Ajax request that sends some data to a page and expects back a truthy or falsey value depending on if the data was saved. In my controller I do everything and set the content to a true or false value. I really don't want to create a view just to output 1 variable, so I was wondering if there was a way that I don't have to use a view and only use the controller to output simple strings.
I believe you cannot disable views completely, but there's a pretty simple workaround: you can create one view and use it for many actions.
Let's say we've created the view views/main/ajax.cfm, what could be inside it? Obviously, simplest way is:
<cfoutput>#HTMLEditFormat(rc.response)#</cfoutput>
Personally I like returning JSON, it allows me to have status field, plus data, if needed. This way my view looks like this:
<cfheader name="Content-Type" value="application/json" />
<cfoutput>#SerializeJSON(rc.response)#</cfoutput>
Any way, now in our action we need to do something like this:
// prevent displaying the layout
request.layout = false;
// force special view
variables.fw.setView("main.ajax");
// init response (according to the choice made earlier)
rc.response["status"] = "OK";
rc.response = "";
There's one more gotcha for this. Sometimes you don't want AJAX page to be accessed directly (like opened in browser), or vise-versa -- want to do some debugging when it is.
There's a cool helper isAjax in CFWheels framework, it is easy to port to the FW/1. It could be as simple as adding method like this to controller:
/*
* Check if request is performed via AJAX
*/
private boolean function isAjax() {
return (cgi.HTTP_X_REQUESTED_WITH EQ "XMLHTTPRequest");
}
Actually, that setup code above is also helper method in my apps:
/*
* Set up for AJAX response
*/
private struct function setAjax() {
// prevent displaying the layout
request.layout = false;
// force special view
variables.fw.setView("main.ajax");
local.response["status"] = "OK";
return local.response;
}
So in my action code whole check looks like this, which is pretty compact and convenient:
if (isAjax()) {
rc.response = setAjax();
}
else {
return showNotFound();
}
Hope this helps.
You can't output directly from a Controller: its job is just to call the Model and pass data to the View, so you'll need a view template to do the outputting.
However, you can avoid having to create a separate view for each controller method by using the framework's setView() method. This allows you to override the convention and apply a single view to multiple controller methods. So you could set up a generic "ajax view" and then use it to output the data from any of your controllers:
views/main/ajax.cfm
<!---Prevent any layouts from being applied--->
<cfset request.layout=false>
<!--- Minimise white space by resetting the output buffer and only returning the following cfoutput --->
<cfcontent type="text/html; charset=utf-8" reset="yes"><cfoutput>#rc.result#</cfoutput>
controller.cfc
function init( fw )
{
variables.fw=arguments.fw;
return this;
}
function getAjaxResponse( rc )
{
rc.result=1;
fw.setView( "main.ajax" );
}
function getAnotherAjaxResponse( rc )
{
rc.result=0;
fw.setView( "main.ajax" );
}
You can use onMissingView in you Application.cfc to handle the response for ajax calls, this way you don't need to perform any extra logic in your controller methods.
// Application.cfc
function onMissingView(rc) {
if(structKeyExists(rc, "ajaxdata") && isAjaxRequest()) {
request.layout = false;
content type="application/json";
return serializeJSON(rc.ajaxdata);
}
else {
return view("main/notfound");
}
}
function isAjaxRequest() {
var headers = getHttpRequestData().headers;
return structKeyExists(headers, "X-Requested-With")
&& (headers["X-Requested-With"] eq "XMLHttpRequest");
}
// controller cfc
function dosomething(rc) {
rc.ajaxdata = getSomeService().doSomething();
}
This checks if the request context has an ajaxdata key, and is a genuine ajax request, then returns the serialize data. If it doesn't then it renders the main.notfound view

Resources