I have a form with two datasources that are linked by using an outer join. It is written to the database by using Form Datasource Unit of Work framework.
As of now, the data gets written when moving from one datasource form control to another form datasource control. I want to only activate/write using Form Datasource Unit of Framework when a button is clicked.
Is there a way to prevent automated write function when moving from one Form Control to another?
First have a look on HowTo: Unit of work implementation for a Form to check you align with that. The official doc is Change Group and Optional Record Modes.
The writes are issued because you are "leaving" a record, see Event Method Sequences when Focus is Removed from a Record.
This is the sequence when validateWrite returns true:
leaveRecord return true
validateWrite return true
writing
written
leaveRecord return true
leaveRecord return true (again)
This is the sequence when validateWrite returns false:
leaveRecord return true
validateWrite return false
leaveRecord return false
So you can override validateWrite to silently return false, when you do not want to save. Be sure to call super() when you do want to save!
Or you can call leaveRecord yourself to force a write:
if (record_ds.leaveRecord(true))
{}
When calling record_ds.leaveRecord(true) please observe that it may not save the record, e.g. if validation fails. In that case leaveRecord will return false.
Observe that you are working "against" the standard working, this will make your form work differently than other forms.
Related
Trying to understand what the 'onlySelf' parameter does when passing to setValue.
this.form.get('name').setValue('', { onlySelf: true })
The documentation says: "If onlySelf is true, this change will only affect the validation of this FormControl and not its parent component. This defaults to false."
However I'm struggling to understand this. Still fairly new to the using Angulars' model driven forms.
Angular2 by default will check for the form control/form group validity cascadingly up to the top level whenever there's an update to any form element value, unless you say no. onlySelf is the tool to help you do that.
Say you have a loginForm that has a username field and a password field, both of them are required, like this:
this.userNameControl = this.formBuilder.control('Harry', Validators.required);
this.passwordControl = this.formBuilder.control('S3cReT', Validators.required);
this.loginForm = this.formBuilder.group({
userName: this.userNameControl,
password: this.passwordControl
});
After this code, this.loginForm.valid is true.
If you set the value of a control using the default setting (onlySelf = false), Angular2 will update the control's validity as well as form group's validity. For example, this:
this.passwordControl.setValue('');
will result in
this.passwordControl.valid === false
this.loginForm.valid === false
However, this:
this.passwordControl.setValue('', { onlySelf: true });
will only change passwordControl's validity only:
this.passwordControl.valid === false
this.loginForm.valid === true
Put it this way, let's say that you have a form, called mainForm which is valid. It has four controls on it and all four have a value. Now, you decide to update the value of one of your controls, let's say you update it to some incorrect value and you specify onlySelf: true. If you try to call this.mainForm.valid, you will get the result that your form is valid even though your control is not valid, and it's invalid state should not allow the form to be submitted. But because the forms valid property is reporting true, you will be submitting inconsistent values to the backend.
It might be confusing why you would have this property, but there might be occasions when you don't want to invalidate the form because of one value or control. Probably you have some advanced checks on the server and you want to correct the value on the server or you might depend on a value from some external web service that might not be available at the time. I'm sure there are number of scenarios but this is something from top of my head.
I have a form that loads a single record. The user does what they need to do on the form...in this case, they enter a date, and a button becomes available to click to advance the record to the next step in the process.
I have a public function that is logging the activity to tblActivity, and sets the record's new Status and Location. This Function takes 3 variables, and was working fine until today.
'I'm calling the function with this line from the button's Click event
LogActivity 15, Screen.ActiveForm, Me.Recordset
Public Function LogActivity(ByVal lSID As Long, Optional fForm As Form, Optional ByRef fRS As Recordset)
With fRS
Do Until .EOF
Debug.Print .Fields(5)
.MoveNext
Loop
End With
...
End Function
This should be printing the form's Status value, but fRS is passed in with no values. The form's recordset has values prior to being passed as the form has data. Some how it is getting lost in the pass. This was working fine, I have multiple buttons across 5 different forms that all call this same Function. Suddenly today, none of them can pass the recordset. I can think of nothing that was changed that would effect this. Most of the changes recently involved locking down fields and the appearance of buttons at the right time...nothing related to the recordset.
Naturally, this DB is supposed to go live on Monday.
Found the problem.
I had a backup from yesterday that was working fine.
One by one, I went through the changes I logged from yesterday and found that by changing some fields to .enabled = False and .locked = True is what was doing it. Apparently that was enough to clear all the values when passing.
Left the fields enabled, just locked them and it passes all values correctly.
Even though this was a failure on my part, I'll leave this up in case some one else makes the same mistake I made.
**** Update ****
I also found out that if I did a
fRS.movelast
fRS.movefirst
before anything else, it found the data. Not sure why it started happening, but these two things seem to have fixed it completely.
In my current project I have to deal with more complex forms. Fields (i'll name them 'A' and 'B') are automatically filled if a specific field (i'll name that one 'C') received user input. But also if the user inputs data into field A, the fields B and C are automatically filled out.
(This is only a simple example, the current logic is a bit more complicated)
What I have to take care of is that no cycles happen (C -> A -> C -> A -> ...). So I need to now if the current value change was due to user input or another field that had received input and then triggered the value change of the current field. And I also need to now in the second case which field exactly triggered the value change because then I must trigger other specific actions corresponding from who/what triggered that value change.
Is there a general approach in Vaadin to deal with this kind of form
structure? The problem at the moment is that I simply don't now who
or what triggered what ValueChangeEvent.
Are there frameworks to deal with this or am I overlooking an existing Vaadin pattern?
Handling of valueChange events in Vaadin is a bit of pain, since it always fires, no matter if the user has changed something, or the application has used setValue(....) on the component.
The only solution for this is to remember when you do a setValue(....) in your application and then disable the trigger code in the other components.
For example in this case (endless loop):
field1.addValueChangeListener( field2.setValue('Updated by field1');
field2.addValueChangeListener( field1.setValue('Updated by field2');
Change it that way:
boolean inTrigger= false;
field1.addValueChangeListener(
{
if (!inTrigger)
{
inTrigger= true;
field2.setValue('Updated by field1');
inTrigger= false;
}
});
field2.addValueChangeListener(
{
if (!inTrigger)
{
inTrigger= true;
field1.setValue('Updated by field2');
inTrigger= false;
}
});
That way you can prevent update loops and let execute your code exactly once.
I tried to condition Page-load rules (Custom criteria) on Data Element activation, in order to fire them only if Data Element are active.I mean the real Data Element activation in its Adobe DTM editing interface.
I attempted the condition below:if (typeof _satellite.getVar('DataElement_name') != 'undefined') {
return true;
} else {
return false;
}because I discovered that an inactive Data Element makes "getVar()" method return "undefined".This does not work, and the rule is fired anyway.This was my second chance, after a first attemp to use the built-in method "isRuleActive()".Unfortunately this seems to always return true, even if the Data Element is inactive.But then, I'm not sure if Data Element could be used with this method.My scenario concerns some Page-load rules built upon Data Elements, which are explicitly called with "getVar()" into their custom code.If those Data Elements are inactive, the rules will go wrong and javascript errors will come up.This is the reason why I'd like to add a Custom criteria condition to these rules, based on Data Element activation.Thanks
What are the possible returns of your data element?
You can try to use this method to check out the returns:
_satellite.dataElements.Your-data-Element-name.customJS();
I recommend that you make your data element return false and in your rules you can choose criteria for "data element value".
Hope this helps!
When I create a query in squeryl, it returns a Query[T] object. The query was not yet executed and will be, when I iterate over the Query object (Query[T] extends Iterable[T]).
Around the execution of a query there has to be either a transaction{} or a inTransaction{} block.
I'm just speaking of SELECT queries and transactions wouldn't be necessary, but the squeryl framework needs them.
I'd like to create a query in the model of my application and pass it directly to the view where a view helper in the template iterates over it and presents the data.
This is only possible when putting the transaction{} block in the controller (the controller includes the call of the template, so the template which does the iteration is also inside). It's not possible to put the transaction{} block in the model, because the model doesn't really execute the query.
But in my understanding the transaction has nothing to do with the controller. It's a decision of the model which database framework to use, how to use it and where to use transactions. So I want the transaction{} block to be in the model.
I know that I can - instead of returning the Query[T] instance - call Iterable[T].toList on this Query[T] object and then return the created list. Then the whole query is executed in the model and everything is fine. But I don't like this approach, because all the data requested from the database has to be cached in this list. I'd prefer a way where this data is directly passed to the view. I like the MySql feature of streaming the result set when it's large.
Is there any possibility? Maybe something like a function Query[T].executeNow() which sends the request to the database, is able to close the transaction, but still uses the MySQL streaming feature and receives the rest of the (selected and therefore fixed) result set when it's accessed? Because the result set is fixed in the moment of the query, closing the transaction shouldn't be a problem.
The general problem that I see here is that you try to combine the following two ideas:
lazy computation of data; here: database results
hiding the need for a post-processing action that must be triggered when the computation is done; here: hiding from your controller or view that the database session must be closed
Since your computation is lazy and since you are not obliged to perform it to the very end (here: to iterate over the whole result set), there is no obvious hook that could trigger the post-processing step.
Your suggestion of invoking Query[T].toList does not exhibit this problem, since the computation is performed to the very end, and requesting the last element of the result set can be used as a trigger for closing the session.
That said, the best I could come up with is the following, which is an adaptation of the code inside org.squeryl.dsl.QueryDsl._using:
class IterableQuery[T](val q: Query[T]) extends Iterable[T] {
private var lifeCycleState: Int = 0
private var session: Session = null
private var prevSession: Option[Session] = None
def start() {
assert(lifeCycleState == 0, "Queries may not be restarted.")
lifeCycleState = 1
/* Create a new session for this query. */
session = SessionFactory.newSession
/* Store and unbind a possibly existing session. */
val prevSession = Session.currentSessionOption
if(prevSession != None) prevSession.get.unbindFromCurrentThread
/* Bind newly created session. */
session.bindToCurrentThread
}
def iterator = {
assert(lifeCycleState == 1, "Query is not active.")
q.toStream.iterator
}
def stop() {
assert(lifeCycleState == 1, "Query is not active.")
lifeCycleState = 2
/* Unbind session and close it. */
session.unbindFromCurrentThread
session.close
/* Re-bind previous session, if it existed. */
if(prevSession != None) prevSession.get.bindToCurrentThread
}
}
Clients can use the query wrapper as follows:
var manualIt = new IterableQuery(booksQuery)
manualIt.start()
manualIt.foreach(println)
manualIt.stop()
// manualIt.foreach(println) /* Fails, as expected */
manualIt = new IterableQuery(booksQuery) /* Queries can be reused */
manualIt.start()
manualIt.foreach(b => println("Book: " + b))
manualIt.stop()
The invocation of manualIt.start() could already be done when the object is created, i.e., inside the constructor of IterableQuery, or before the object is passed to the controller.
However, working with resources (files, database connections, etc.) in such a way is very fragile, because the post-processing is not triggered in case of exceptions. If you look at the implementation of org.squeryl.dsl.QueryDsl._using you will see a couple of try ... finally blocks that are missing from IterableQuery.