Select to view content in your preferred language

Editable field with calculated expression

2368
8
07-03-2023 02:47 PM
GustavoMiralesSilva
Occasional Contributor

Hey there folks,

Is it possible to have a calculated expression on a field, and still let it be edited?

The case is: When a user create a new feature, there's a field that contains data that needs to be inputed manually (needs to be editable), but it would be very useful if the user received an "sugestion" on what needs to be writen.

That "sugestion" is obtainable with a Arcade expression, but when I use a calculated expression on a field, and mark it as editable, the expression doesn't get executed, only when it's not editable.

Appears to me that the field can't have both capabilities, am I right? Or there's a workaround?

Thanks.

8 Replies
JustinReynolds
Frequent Contributor

Ideally that would be solved with a hintExpression. That would allow for dynamic hints, but this isn't a capability of FM maps yet. If you don't need the hint to be dynamic then all you need to do is define the placeholder text on the field.

To address the other part of the question with regards to form calculations that are editable, the answer is that is natively possible to configure in Field Maps Designer if you are using AGOL or Enterprise 11.x.

You would need an additional expression on the field to make it work.  

The rules are as follows:

  • A field that is editable, will not calculate.
  • A field that is not editable, will calculate.
  • An editableExpression can be used to define when a field is editable and when it is not... and by extension when it will calculate and when it is not.
  • The editableExpression is a constraint and so it must return true (for editable, but not calculable) or false (for not editable, but calculable).

    The extent of your editableExpression will depend on what you need and it may need a helper field and it may not.

    The most basic case is to check if the field is null or empty.  If it is, then return false and calculate your hint text.  If it is not empty (because it has your hint text or a user entered value) then return true to make the field editable and suppress the form calculation. And  so, if the user nulls the field again, your hint text reappears due to the calculation and then becomes editable again.
- Justin Reynolds, PE
GustavoMiralesSilva
Occasional Contributor

It kinda works, but the field becomes editable only after saved and selected for editing. I'm using AGOL.

The editableExpression I've used is:

 

if ($originalFeature["field_name"] == null || IsEmpty($originalFeature["field_name"])) {
  return false
} else {
  return true
}

 

 

The calculated expression is:

 

var intersect_layer = Intersects(
  FeatureSetByName($map, "Roads"),
  BufferGeodetic($feature, 1, "kilometers")
);

var segment_start;
var segment_end;
var lower_dist = 1;

for (var f in intersect_layer){
  var road_dist = Round(Distance(f, $feature, "kilometers"),2);
  if (road_dist < lower_dist) {
        segment_start= f.start;
        segment_end= f.end;
        lower_dist = road_dist;
  }
};

return Concatenate([segment_start, ' - ', segment_end]);

 

 

It appears that the editableExpression is only checked when the form is opened, and changes to the field won't change the field state, only after saving an reopen. Is there a way to make it "reload" the editableExpression? I'd like to be possible for the user to edit the field value on the fly, and not needing to save and reopen (that would be hard to explain to the users).

Note: This is meant for using with the Smart Forms in MapViewer, not the FieldMaps App.

Thanks.

0 Kudos
JustinReynolds
Frequent Contributor

Original Feature may not be doing what you think it is.  $OriginalFeauture is only applicable if the edit context is "UPDATE".  On "INSERT" the object is null or does not exist, so the way you have written your editable expression is only valid when editing an existing feature.  Also, $OriginalFeature does not change state during editing... it is fixed to the state of the feature as last submitted to the database, hence the original state of all the fields when you start an editing session will not change during the current edit session... only after submitting the feature.

Your logic can be probably just be simplified to the following

 

//editableExpression

if (IsEmpty($feature.field_name)) { return true };
return false;

 

 If, however, you want to mess with $originalFeature, it is probably best to only do so if the edit context is "UPDATE". So check the editType before accessing $originalFeature.

 

//editableExpression

if ($editcontext.editType == 'UPDATE') {
    // Lock manual editing, be sure to set equal to itself in the form calculation.
    if (!IsEmpty($originalFeature.field_name)) { return false }; 
};

// on INSERT or on UPDATE if field is Empty
if (IsEmpty($feature.field_name)) { return true };
return false;

 

 

//formCalculation

if ($editcontext.editType == 'UPDATE') {
    // Maintian the $originalFeature field value by setting it to itself
    if (!IsEmpty($originalFeature.field_name)) { return $originalFeature.field_name }; 
};

// else if not UPDATE or original field IsEmpty on UPDATE then we do the things below.

var intersect_layer = Intersects(
  FeatureSetByName($map, "Roads"),
  BufferGeodetic($feature, 1, "kilometers")
);

var segment_start;
var segment_end;
var lower_dist = 1;

for (var f in intersect_layer){
  var road_dist = Round(Distance(f, $feature, "kilometers"),2);
  if (road_dist < lower_dist) {
        segment_start= f.start;
        segment_end= f.end;
        lower_dist = road_dist;
  }
};

return Concatenate([segment_start, ' - ', segment_end]);

 

 

- Justin Reynolds, PE
0 Kudos
GustavoMiralesSilva
Occasional Contributor

Wouldn't be the other way around?

//editableExpression

//If empty return false, so the expression get executed
//If not empty, enable the editing
if (IsEmpty($feature.field_name)) { return false};
return true;

Sorry, but I can't get this to work the way I want to.

I've tried with both $originalFeature and $feature, and you're right, using $feature will change the state of the field, but for me here what's happening, in order:

On Inserting:

  • When creating a new record, the field is editable, but with no values;
  • If I try to change the location of the created point, the expression gets executed and the calculated value appears on the field, but editing is disabled;
  • If I move the point, again, the field gets editable, but the value is erased;
  • If I type something in the field value, and erase it, the field gets filled with the expression result, but editing is disabled (This is why I used $originalFeature, it gets executed right away, even though the state won't change);

On Updating:

  • If saved, and opened again for update, the field is with the value left when saved, and editable.

This way, to get this to work, the user have to:

  1. Insert a feature and save;
  2. Reopen the same feature and edit the field to the desired value and save.

If it can't be done, it's ok, I'll leave this out. Just wanna make sure because it could be very useful.

0 Kudos
bcunningham04
Emerging Contributor

@GustavoMiralesSilva 

 

Just an FYI. I don't know if something changed in a new release of AGOL since last summer, but I was able to accomplish what I believe you were looking to do.

// editableExpression

if ($feature.attributename == null) {
  return false
}
else {
  return true
}
 
This is allowing the auto calculate to happen, and then open the field for editing if the user needs to modify the auto calculated value.
 
I have a use case where 90% of the time, the auto calculated value is what's needed, but the other 10% of the time the user needs to input their own value. I was wanting to do the auto calculate to save time for the 90%, but still allow editing for the other 10%. That syntax above in the editableExpression is appearing to accomplish that for me.
 
Thanks,
Brian
JessyBeasley
New Contributor

If you have the time, would you mind confirming that this setup/logic is similar to yours? When I implement, I am not seeing this functionality- it will either prevent editing still or, the calculation no longer is triggered. You're not using the FM Designer beta, right? 

  • User answers Q1 (required) as yes or no
  • If Q1==yes, Q2 will auto calculate with an expression
  • If Q1==no, Q2 will be editable by user
  • Q2 has both the editable expression and a calculation expression with a conditional based on Q1's response
//edit expression

if ($feature.Q2 == null) {
return true
}
else {
return false
}
//calculate expressions

var yesno = $feature.Q1
if(yesno == 'yes'){
    return $feature.otherAttribute
}

 

 

0 Kudos
JustinReynolds
Frequent Contributor

Hi Jessy,

I think you have some logic crossed.

To have the following logic, your expressions for Q2 would look like the following:

  • User answers Q1 (required) as yes or no
  • If Q1==yes, Q2 will auto calculate with an expression
  • If Q1==no, Q2 will be editable by user
  • Q2 has both the editable expression and a calculation expression with a conditional based on Q1's response
/* Q2, Editable Expression - edt_q2 */

if (Lower($feature.Q1) == 'yes') { return false }; /* false -> Allow Calc */
return true; /* true -> Allow User to Edit */
/* Q2, valueExpression, val_q2 */

/* 
  Note: 
    As long as there is an editableExpression checking the yes/no field
     there is no need to check it again in the value expression.
*/
return $feature.otherAttribute;
- Justin Reynolds, PE
0 Kudos
JessyBeasley
New Contributor

Thank you for the reply, but I get the same behavior with this logic, too. I may continue to play around with it, however it seems I’m running low on things to try. Again, I appreciate your time! 

0 Kudos