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.
Related
This is going to sound very weird but it will make the code for this app very compact.
Is there a way to call a .operator conditionally. Here is an example
say I have a class with three values that I can do a . on.
class A {
int intOne;
int intTwo;
int intThree;
}
to get the intOne in class A you can do A.intOne right....
but what if you you wanted the string at the right of the . to conditionally be there.
A."conditionalvariable"
so if a user clicks a button say button A then the conditional variable will be A.intOne.
and if the user clicks button b then the value of "conditionalvariable" will be intTwo and therefore you will be getting the data.
please assume that I am not stupid, and I am needing this exact thing for a specific use case. If you post an answer that is not this exact solution it will not be accepted.
example:
var a;
switch (name) {
case "intOne":
a = A.intOne;
break;
...
}
//this is not an acceptable answer
I realize that this would be an "answer" to this question, but it actually isn't I need the exact thing stated because I am using streams.
here is that use case I was talking about. I could explain away all day as to why I need it this way, but either way this either does exist or doesn't so a simple no this doesn't exist is an acceptable answer.
return StreamProvider.value(
value: classDataNotif.homework,
)
based on what is clicked before this widget the "homework" will need to change to "notes", or "tests".
You cannot do a switch above this because it will be calling the stream to early and cause the widget to crash. doing a switch inside the widget and copying code over would defeat the purpose. in order to make the code as compact and as easy to write as possible i need the string at the right of the . operator to change.
thanks in advance :)
Ok, I've been stuggling with this one for a while, and have spent a lot of time trying different things to do something that I have done very easily using PHP.
I am trying to iterate over a list while keeping track of a variable locally, while spitting out HTML attempting to populate a table.
Attempt #1:
#{
var curDate : Date = null
for(ind <- indicators){
if(curDate == null || !curDate.equals(ind.getFirstFound())){
curDate = ind.getFirstFound()
<tr><th colspan='5' class='day'>#(ind.getFirstFound())</th></tr>
<tr><th>Document ID</th><th>Value</th><th>Owner</th><th>Document Title / Comment</th></tr>
}
}
}
I attempt too user a scala block statement to allow me to keep curDate as a variable within the created scope. This block correctly maintains curDate state, but does not allow me to output anything to the DOM. I did not actually expect this to compile, due to my unescaped, randomly thrown in HTML, but it does. this loop simply places nothing on the DOM, although the decision structure is correctly executed on the server.
I tried escaping using #Html('...'), but that produced compile errors.
Attempt #2:
A lot of google searches led me to the "for comprehension":
#for(ind <- indicators; curDate = ind.getFirstFound()){
#if(curDate == null || !curDate.equals(ind.getFirstFound())){
#(curDate = ind.getFirstFound())
}
<tr><th colspan='5' class='day'>#(ind.getFirstFound())</th></tr>
<tr><th>Document ID</th><th>Value</th><th>Owner</th><th>Document Title / Comment</th></tr>
}
Without the if statement in this block, this is the closest I got to doing what I actually wanted, but apparently I am not allowed to reassign a non-reference type, which is why I was hoping attempt #1's reference declaration of curDate : Date = null would work. This attempt gets me the HTML on the page (again, if i remove the nested if statement) but doesn't get me the
My question is, how do i implement this intention? I am very painfully aware of my lack of Scala knowledge, which is being exacerbated by Play templating syntax. I am not sure what to do.
Thanks in advance!
Play's template language is very geared towards functional programming. It might be possible to achieve what you want to achieve using mutable state, but you'll probably be best going with the flow, and using a functional solution.
If you want to maintain state between iterations of a loop in functional programming, that can be done by doing a fold - you start with some state, and on each iteration, you get the previous state and the next element, and you then return the new state based on those two things.
So, looking at your first solution, it looks like what you're trying to do is only print an element out if it's date is different from the previous one, is that correct? Another way of putting this is you want to filter out all the elements that have a date that's the same date as the previous one. Expressing that in terms of a fold, we're going to fold the elements into a sequence (our initial state), and if the last element of the folded sequence has a different date to the current one, we add it, otherwise we ignore it.
Our fold looks like this:
indicators.foldLeft(Vector.empty[Indicator]) { (collected, next) =>
if (collected.lastOption.forall(_.getFirstFound != next.getFirstFound)) {
collected :+ next
} else {
collected
}
}
Just to explain the above, we're folding into a Vector because Vector has constant time append and last, List has n time. The forall will return true if there is no last element in collected, otherwise if there is, it will return true if the passed in lambda evaluates to true. And in Scala, == invokes .equals (after doing a null check), so you don't need to use .equals in Scala.
So, putting this in a template:
#for(ind <- indicators.foldLeft(Vector.empty[Indicator]) { (collected, next) =>
if (collected.lastOption.forall(_.getFirstFound != next.getFirstFound)) {
collected :+ next
} else {
collected
}
}){
...
}
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!
I'm building a form with Yii that updates two models at once.
The form takes the inputs for each model as $modelA and $modelB and then handles them separately as described here http://www.yiiframework.com/wiki/19/how-to-use-a-single-form-to-collect-data-for-two-or-more-models/
This is all good. The difference I have to the example is that $modelA (documents) has to be saved and its ID retrieved and then $modelB has to be saved including the ID from $model A as they are related.
There's an additional twist that $modelB has a file which needs to be saved.
My action code is as follows:
if(isset($_POST['Documents'], $_POST['DocumentVersions']))
{
$modelA->attributes=$_POST['Documents'];
$modelB->attributes=$_POST['DocumentVersions'];
$valid=$modelA->validate();
$valid=$modelB->validate() && $valid;
if($valid)
{
$modelA->save(false); // don't validate as we validated above.
$newdoc = $modelA->primaryKey; // get the ID of the document just created
$modelB->document_id = $newdoc; // set the Document_id of the DocumentVersions to be $newdoc
// todo: set the filename to some long hash
$modelB->file=CUploadedFile::getInstance($modelB,'file');
// finish set filename
$modelB->save(false);
if($modelB->save()) {
$modelB->file->saveAs(Yii::getPathOfAlias('webroot').'/uploads/'.$modelB->file);
}
$this->redirect(array('projects/myprojects','id'=>$_POST['project_id']));
}
}
ELSE {
$this->render('create',array(
'modelA'=>$modelA,
'modelB'=>$modelB,
'parent'=>$id,
'userid'=>$userid,
'categories'=>$categoriesList
));
}
You can see that I push the new values for 'file' and 'document_id' into $modelB. What this all works no problem, but... each time I push one of these values into $modelB I seem to get an new instance of $modelA. So the net result, I get 3 new documents, and 1 new version. The new version is all linked up correctly, but the other two documents are just straight duplicates.
I've tested removing the $modelB update steps, and sure enough, for each one removed a copy of $modelA is removed (or at least the resulting database entry).
I've no idea how to prevent this.
UPDATE....
As I put in a comment below, further testing shows the number of instances of $modelA depends on how many times the form has been submitted. Even if other pages/views are accessed in the meantime, if the form is resubmitted within a short period of time, each time I get an extra entry in the database. If this was due to some form of persistence, then I'd expect to get an extra copy of the PREVIOUS model, not multiples of the current one. So I suspect something in the way its saving, like there is some counter that's incrementing, but I've no idea where to look for this, or how to zero it each time.
Some help would be much appreciated.
thanks
JMB
OK, I had Ajax validation set to true. This was calling the create action and inserting entries. I don't fully get this, or how I could use ajax validation if I really wanted to without this effect, but... at least the two model insert with relationship works.
Thanks for the comments.
cheers
JMB
I'm reposting this question from an earlier post because when I originally asked it, it was unclear. I wasn't sure what I actually needed, and that caused the responses I was getting to be not applicable.
Original: YUI Datatable - Get ID of DOM Element after page has loaded and use it in other YUI events
My question is this:
I have a YUI Datatable. I have a rows per page drop down. I need to create an event, or event handler, or utilize one that exists, that will handle the following:
When(ever) the drop down displaying the rows per page changes, the event handler should get the id of that drop down and pass it to another function to use as an argument. My datatable has two rowsPerPageDropDown (aka rppDD) elements. I need this functional for both of them.
Preferably, it would also do this when the page loads, but for now that's extra credit.
I know that the id of "top" rppDD element is currently "yui-pg0-0-rpp12" but my problem extends from the fact that if I add any code to this page, that id will change (to "-rpp13" or something similar). That throws off the rest of my functions. So I want to just grab the id (whatever it may be) at run time and use it that way rather than hard coding it in.
The second function will run immediately after the drop down changes. It will use the id of the drop down to get the currently selected value and assign it to a variable to be used with a third function.
Here's what I have so far: In the earlier thread, it was suggested that I use the event rowsPerPageChange. This works only to a certain degree. Placing a simple "hello world" alert within that event handler proves that it only alerts when the page loads. Whenever I click and change the drop down to something else it no longer alerts.
Below is the function(s) and code I'm using to test this:
var getRppValue = function() {
YAHOO.util.Event.addListener("rowsPerPageChange", getRppValue.prototype.handleOnAvailable());
}
var rppDD_ID = "";
getRppValue.prototype.handleOnAvailable = function() {
alert("hello world");
alert(this.id); //should alert "yui-pg0-0-rpp12"
//rppValue = this.id;
}
var rppEvent = new getRppValue();
Near as I can tell this event only fires/gets handled when the page initially loads. At that time, the first alert alerts "hello world" as expected. The second alert shows "undefined". The intention is that the second alert should alert whatever the id of the rppDD element is ("yui-pg0-0-rpp12").
For reference, the function I plan on passing the id into is as follows. It is intended as I mentioned above to assign the current value of [the|either|both] rppDD element(s) to the variable oRPP. It then calls the endDrag() function (which utilizes oRPP):
If I were to hard code the id it would be:
function getRPP_0(){oRPP = g("yui-pg0-0-rpp12").value;endDrag();};
I want it to by dynamic:
function getRPP_0(){oRPP = g(rppDD_ID).value;endDrag();};
Any help / suggestions are appreciated.
As we saw on the chat, you had this:
var onRPPChange0 = YAHOO.util.Event.addListener("yui-pg0-0-rpp12", "change", getRPP_0);
var onRPPChange1 = YAHOO.util.Event.addListener("yui-pg0-1-rpp24", "change", getRPP_1);
function getRPP_0(){oRPP = g("yui-pg0-0-rpp12").value;endDrag();};
function getRPP_1(){oRPP = g("yui-pg0-1-rpp24").value;endDrag();};
And you wanted to be able to access the element being changed in the function.
Fortunately, event handlers provide the element on which the event is happening in the this object.
So, this works:
var onRPPChange0 = YAHOO.util.Event.addListener(
"yui-pg0-0-rpp12", "change", function() {
// Notice that "this" is the element on which the event was fired
oRPP = this.value;
endDrag();
};
This way, you can generalize your function easily without hardcoding the IDs.