Is it possible to implement custom transformers? - google-app-maker

Is it possible to implement custom transformers to perform non-trivial transformations, preferably both ways?

Unfortunately, App Maker doesn't have a mechanism to add custom transformers.
However, you can use client scripts to transform your bindings. For example, if you have a label that bound to #datasource.item.name, you can create Client Script with a function:
function nameTransformer(name) {
return name + ' after transformation';
}
and change your binding to nameTransformer(#datasource.item.name). That function can contain more complex logic.

Related

Custom Header with token in PASOE Business Class Entity with Web Service?

I have a PASOE Business Class Entity setup as a Web Service. I'm trying to determine how to create a custom header that will allow me to pass in a hashed token. Is this something that I need to upgrade to 11.7.4 for DOH(OpenEdge.Web.DataObject.DataObjectHandler)? Or is this something that I simply add into a method that's defined in the class? Apologies, for the lack of code to illustrate my situation, but I'm not sure where to begin.
If you're using a Business Entity with the web transport then you're using the DOH, and the below applies. If you're using the rest transport then you are not using the DOH, and are more limited in your choices.
There is doc available on the DOH at https://documentation.progress.com/output/oe117sp/index.html#page/gssp4/openedge-data-object-handler.html - it's for 11.7.4 but largely applies to all versions (that is, from 11.6.3+). This describes the JSON mapping file, which you'll need to create an override to the default, generated one.
If you want to use the header's value for all operations, then you may want to use one of the DOH's events. There's an example of event handlers at https://github.com/PeterJudge-PSC/http_samples/blob/master/web_handler/data_object_handler/DOHEventHandler.cls ; you will need to start that handler in a session startup procedure using new DOHEventHandler() (the way that code is written is that it makes itself a singleton).
You can now add handling code for the Invoking event which fires before the business logic is run.
If you want to pass the header value into the business logic you will need to
Copy the generated mapping file <service>.gen to a <service.map> , in the same folder. "gen" files are generated and will be overwritten by the tooling
In the .map file, add a new arg entry. This must be in the same order as the parameters to the BE's method.
The JSON should look something like the below. this will read the value of the header and pass it as an input parameter into the method.
{ "ablName": "<parameter_name>",
"ablType": "CHARACTER",
"ioMode": "INPUT",
"msgElem": {"type": "HEADER", "name": "<http-header-name>"}
}

Where to define record methods in a Redux app

I am building an app with React + Redux + Immutable JS and am running into some architectural problems. To illustrate I will use my user record as an example. The user object is an Immutable Record, defined in the user reducer. Now I would like to define some methods for this user (for example, isCurrentUser(userId), which would return a boolean and can be called on any user instance). From what I gather, the state should simply be plain objects though (reference: How to put methods onto the objects in Redux state?)
However, since this method wouldn't change the state of the application it doesn't make sense to use the typical Redux flow either. Is it acceptable for me to define methods within my Immutable Records, or should I be defining some helper methods in a separate JS file. Or maybe there's something else I haven't thought of?
You can create a new layer called 'services' and put this methods inside it. So, you can have a services/UserSession that is used like.:
{ isCurrentUser } from './services/UserSession'
isCurrentUser(user)
Does it help you?

In Meteor.js, what's the difference between method-based database API design and the subclass approach?

Namely, what are the advantages and disadvantages of the following approaches to building a server-side database API in Meteor?
Method-based
import Db from 'Db';
Meteor.method({"insert": (data) => {Db.insert(data)});
Subclass-based
import {Mongo} from "meteor/mongo";
class MyCollcetion extends Mongo.Collection {
insert: (data) => {super.insert(data);}
}
This problem has been solved below; there is a similar question for further reading: Meteor method vs. deny/allow rules
This is mainly a matter of ease vs control. Subclassing may be easier for simple things, and methods are more powerful.
This can also be affected by your state of mind (or affect it): CRUD vs. action-based mutation.
insert/update/remove go well with a CRUD state-of-mind, while you can associate methods with action-centric RPC mutators.
Eventually, this is a matter of personal preference, so I will try to give a short factual description and let the readers to decide based on their taste.
Subclassing
By default, Meteor automatically generates mutation methods (insert, update, remove) when a collection is instantiated.
Those methods are called behind the scenes when calling MyCollection.insert(mutator, cb) on the client side (outside client-side method code). When arriving to the server, the data are first passed through allow/deny rules and then executed.
When subclassing, you override those methods and get a 'hook' into the process.
Using methods
When defining a Meteor method you get full control of the process.
You set the parameters and the name of the method and you can perform the validation and authorization as you wish.
You can also create a method stub for client-side use, which generates optimistic UI until the results of the method server execution are received.
You can use something like a validatedMethod to get some extra validation logic and modularity to your method.
You can also prevent the creation of the default mutation methods by setting a false value for the defineMutationMethods option when instantiating the collection. You can also forbid direct mutation from the client by supplying the appropriate deny rules.
While subclassing allows you to use MyCollection.insert(...), etc. on the client, you need to call the method name with the arguments that you defined in order to mutate data.

Passing value between two components in angular2-meteor project

I am using angular2-meteor.
When I try to pass a value between two components (when the value change in the first component, create an event in second component and use this new value), I have two ways right now:
One way is meteor way: using this.autorun and Session.get.
Another way is angular2 way: using Injectable service with EventEmitter.
Which way should be prior? Or is there any other better way? Thanks
Now I used angular2-meteor a while.
Although the angular2-meteor tutorial has no example so far about using or choosing Angular 2 service or Meteor Session.
But I feel angular 2 takes the lead in the front end, while meteor makes reactivity easier and also handle all back end things.
So I went with angular2 way using service to share between components. And service is very powerful like #todd-w-crone said.
If anyone has better answer, I will switch to accept that one.
I find it practical to create a new service called App.states.ts which is accessed globally and mimics Session (get / set).
I commonly import this service to all necessary components to get or set new value such as User.status, company.profile, lastProduct, etc.
Since this service is #injectable it can also make use of other services, in case a value hasn't been set already.
This allows me to ask for a variable in a component appState.getLastModifiedItem(), then in app.states.ts I'll write this function to pass this.modifiedItem or either:
Request another service item.service.ts to fetch data
Call another function with itemCollection.findOne({...}) and return such value.
You can configure Mongo queries as you want and either store static data in appState or keep subscription items in appState.
Do take into consideration that all subscriptions handled by an #injectable within a component are imported by such component. Be wary of conflicting subscriptions between components/services.

How to mix multiple domain objects in a single form?

I have 3 domains :
- EligibilityInclusion
- EligibilityExclusion
- EligibilitySummary
I build also eligibility.gsp (mix use of 3 templates : _inclusion, _exclusion, _summary ; and I'm also using JQueryUI tab to render each domain in one tab).
Everything fine for viewing, but now I would like to use only one controller to create, edit, list and show.
How can I handle 3 domains via only one controller?
(for example, I would like to use EligibilityController to handle my 3 domains)
What is the best usage:
- binding multiple objets?
- use command objects?
Unfortunately command objects don't help with the input model for a view, they are specifically designed to aide the output model for the binding and validation of request parameters. However you can roll your own View Model based on a command object if you are prepared to delve into some meta programming to to achieve the data binding for the creation of the view model.
Here's a basic approach. The following code constructs the Command Object which you can then pass as the model to the view in the controller:
class ItemCommand {
// attribute declarations ...
public void bindData(def domainInstance){
domainInstance.properties.keySet().each { prop ->
if(prop == "class"){
// not needed
} else if(prop == "metaClass") {
// not needed
} else if(this.properties.containsKey(prop)){
this."${prop}" = domainInstance."${prop}"
}
}
}
This will allow you to bind the data from different domain objects by calling bindData for each of the domain objects.
This is the essence of the solution I use. You will need to store the ids of the different domain objects (and the version attribute) as hidden fields if you intend to do updates to the domain objects.
You can't just submit multiple objects, if some of them have same field names, right?
I'd try to join the 3 objects into single Command with 3 fields, like: inclusionInstance1, inclusingInstance2, summaryInstance1, and name fields in gsp-s respectively, like name='command.inclusionInstance1.name'. Assigning command.properties = params should work when submitting the form.

Resources