Select to view content in your preferred language

how to set custom default values on new object in Edit widget

2703
7
Jump to solution
04-06-2017 01:07 PM
DavidWendelken
Frequent Contributor

I know how to set default values in an ArcGIS service at design time.

However, I need to intervene in the creation of a geometric item at run time to dynamically decide what the default values should be.

For example:

User picks a template for a point-based service and clicks on the map to create the point. 
The widget decides where that point is and determines the latitude/longitude of the point.
The widget decides what the default attribute values should be for the new point based upon the service definition.

***At this point, I want to intercept the creation of the point and alter some of the default values ***

The widget displays the attribute values in an editor and the point on the map for the user to edit.

Ideally, I would like to intercept in such a way that if a different widget somehow created a point, the same intercept code would be invoked and the appropriate default values would be assigned at run time thru an event handler.

Failing the ability to hook into an event at the correct point in time, what routine would folks recommend implementing the code hook from?

Tags (1)
0 Kudos
1 Solution

Accepted Solutions
DavidWendelken
Frequent Contributor

I'm pretty close to a solution that will work for me.   I have to integrate in a call to a web service (preferably asynch) before I'm done.

But assuming you can compute the values you need without doing all that, here's what will work.

The solution was complicated by an unexpected "feature" of the product.   When I am using the edit widget and click on the map, a point is actually created in the database and ONLY THEN is the user asked for input on the attribute values.

I had assumed that an object was created in memory, displayed on the map, the user was asked for input on the attribute values, and ONLY THEN was the database record inserted.  That's not as nice an arrangement when it comes to improving data quality as what I expected, but such is life.

Once that misconception was corrected, I needed to find a way to intercept between the request to insert the records and the actual insert.  It turns out that the javascript api FeatureLayer class has an event that I can attach a custom function to.   I can change the attribute values in that custom function at runtime and the changed values will be written to the database before the user is given a say on attribute values.

And, of course, I had to find the correct place to update that feature layer's event handler.

The good and bad portion of this approach is that any object that gets the featureLayer in question from the map object should have this set of rules applied once the edit widget has been opened.  In theory, that would apply to other widgets that change the data, but I haven't proven that (yet).


I recommend cloning the edit widget set of files and making your own custom edit widget, just in case you ever need to fall back to plain vanilla edits.

Here goes:
(in the edit widget   'widget.js' file)

// The widgets.js file is one long list of variables and function definitions.  I popped in this code after the

// comment "Methods for prepare to create Editor" as a convenient place to put it.
onBeforeApplyEditsForMyFeatureLayer: function (toDoList) {

  var iMax = 0;

  if (toDoList) {

    if (toDoList.adds && toDoList.adds.length > 0) {
      iMax = toDoList.adds.length;

      for (var i = 0; i < iMax; i++) {

        // Use the attribute names, algorithms, and values that meet your needs.

        toDoList.adds.attributes.MyAttributeName = 'my custom run-time defined value';

      }
      // Repeat above code for toDoList.updates and toDoList.deletes as desired.

    }

  }

},


Then I modified the _getLayerInfosParam function in the same file.

_getLayerInfosParam: function() {
  // ... some code at the start of the function that you leave alone until you get to here...
  array.forEach(layerInfos, function (layerInfo) {

    var layerObject = this.map.getLayer(layerInfo.featureLayer.id);
    // insert this if statement here using the appropriate id for the feature...
    if (layerObject && layerInfo.featureLayer.id === 'MyFeatureId')  {

      on(layerObject, 'before-apply-edits', lang.hitch(this, this.onBeforeApplyEditsForMyFeature));

    }

    // ... some more code after the change you must made, that you also leave alone. 

    // Existing closing braces are shown below for clarity
  }
  // ... more code after the change that you leave alone.
},

Hope this helps someone else.

View solution in original post

7 Replies
DavidWendelken
Frequent Contributor

I've been doing some more research into the edit widget code.  

It appears that the actual creation of the point isn't an edit widget task, that appears to be an event tied to the map.

(The previous statement is not to be considered "a statement of fact", it's my best current working guesstimate...)

If anyone knows the name of the javascript file and the name of the routine where a map-click gets turned into a point in the database, feel free to chime in.   I'll keep digging.

0 Kudos
RickeyFight
MVP Regular Contributor

Are you hosting your own data? 

If so, have you tried adding templates on the mxd?

You can set the attributes here

DavidWendelken
Frequent Contributor

Yes, we are using templates and are setting some default values that way.
However, they are static default values, i.e., always put an "X" in field_x.

In this case, I need to put in values that are calculated at runtime depending upon the location of the point.

If that's possible to do with templates, I missed that in the documentation.   Is it?


0 Kudos
DavidWendelken
Frequent Contributor

I'm pretty close to a solution that will work for me.   I have to integrate in a call to a web service (preferably asynch) before I'm done.

But assuming you can compute the values you need without doing all that, here's what will work.

The solution was complicated by an unexpected "feature" of the product.   When I am using the edit widget and click on the map, a point is actually created in the database and ONLY THEN is the user asked for input on the attribute values.

I had assumed that an object was created in memory, displayed on the map, the user was asked for input on the attribute values, and ONLY THEN was the database record inserted.  That's not as nice an arrangement when it comes to improving data quality as what I expected, but such is life.

Once that misconception was corrected, I needed to find a way to intercept between the request to insert the records and the actual insert.  It turns out that the javascript api FeatureLayer class has an event that I can attach a custom function to.   I can change the attribute values in that custom function at runtime and the changed values will be written to the database before the user is given a say on attribute values.

And, of course, I had to find the correct place to update that feature layer's event handler.

The good and bad portion of this approach is that any object that gets the featureLayer in question from the map object should have this set of rules applied once the edit widget has been opened.  In theory, that would apply to other widgets that change the data, but I haven't proven that (yet).


I recommend cloning the edit widget set of files and making your own custom edit widget, just in case you ever need to fall back to plain vanilla edits.

Here goes:
(in the edit widget   'widget.js' file)

// The widgets.js file is one long list of variables and function definitions.  I popped in this code after the

// comment "Methods for prepare to create Editor" as a convenient place to put it.
onBeforeApplyEditsForMyFeatureLayer: function (toDoList) {

  var iMax = 0;

  if (toDoList) {

    if (toDoList.adds && toDoList.adds.length > 0) {
      iMax = toDoList.adds.length;

      for (var i = 0; i < iMax; i++) {

        // Use the attribute names, algorithms, and values that meet your needs.

        toDoList.adds.attributes.MyAttributeName = 'my custom run-time defined value';

      }
      // Repeat above code for toDoList.updates and toDoList.deletes as desired.

    }

  }

},


Then I modified the _getLayerInfosParam function in the same file.

_getLayerInfosParam: function() {
  // ... some code at the start of the function that you leave alone until you get to here...
  array.forEach(layerInfos, function (layerInfo) {

    var layerObject = this.map.getLayer(layerInfo.featureLayer.id);
    // insert this if statement here using the appropriate id for the feature...
    if (layerObject && layerInfo.featureLayer.id === 'MyFeatureId')  {

      on(layerObject, 'before-apply-edits', lang.hitch(this, this.onBeforeApplyEditsForMyFeature));

    }

    // ... some more code after the change you must made, that you also leave alone. 

    // Existing closing braces are shown below for clarity
  }
  // ... more code after the change that you leave alone.
},

Hope this helps someone else.

DavidWendelken
Frequent Contributor

The sample code I marked as a solution works great if the code necessary to determine the values is all synchronous.

If appears that the before apply edits method is called synchronously and does not respond to deferred functions. 

I'm trying to find a way around it.  If the esri code that called this method used the dojo when method all would be well...

0 Kudos
DavidWendelken
Frequent Contributor

The only way I've found around the async issue is to undertake only synchronous actions in the event handler.   I built a small service in C# that I can call synchronously that gets the necessary info. 

If there is a way to synchronously call a javascript function and have that function make async calls, but not return a value until the async calls return a value, I would love to know how. 

0 Kudos
DavidWendelken
Frequent Contributor

One other thing that came to me as a surprise was to learn that the before apply edits event fires after you change a field and leave it.

So, if you edit 3 different fields on the record, the event fires three times.  Golly.

0 Kudos