Roam icon indicating copy to clipboard operation
Roam copied to clipboard

Use of attribute($currentfeature,'name') in filters

Open TonyFMCMC opened this issue 6 years ago • 10 comments

Am I using the appropriate format for the following filter for a list in RoamConfig? This is from the form.config file.

- _id: f738cb26-b726-44cf-81b1-ecdc22b331f4
  config:
    allownull: true
    layer:
      filter: format_date(  "Task date" ,'yyyyMMdd')=format_date( attribute(  $currentfeature
        ,'Datestamp'),'yyyyMMdd')
      key: team-project
      layer: Allocations
      value: id
    orderbyvalue: false
  default: ''
  default_events:
  - capture
  field: teamallocationid
  hidden: false
  name: select team
  read-only-rules:
  - never
  rememberlastvalue: false
  required: true
  widget: List

I am trying to filter the list based on an earlier entered field on the form ('Datestamp'), but when the form is run in Roam, there are consistently no options in the list apart from 'No selection'. The expression attribute( $currentfeature,'Datestamp') works fine as an expression in a text field but I'm not sure what it is doing in the filter. The Allocations table is an SQL server view (non-spatial), and the table on which the form is built is an SQL server spatial table. Or is there a better way to do this?

Roam v2.6

TonyFMCMC avatar Aug 01 '18 08:08 TonyFMCMC

I have a similar issue. Only been able to get the list filter to work if the parent field is already pre-populated - I can't get ROAM to detect entered values from other fields except in the Events tab (but that will only let you set values, rather than filter lists).

she-weeds avatar Aug 09 '18 00:08 she-weeds

Another user has informed me that he doesn't think Roam supports cascading list-boxes like I have described and that he has raised this limitation with the developers too. It seems to me to be the attribute() function failing.

TonyFMCMC avatar Aug 13 '18 01:08 TonyFMCMC

However, editing the form.py file to include a handler for (in this case) when the date changes, and in the handler changing a filter on a list effectively cascades the information. Just not through Roam Config Manager.

    def uisetup(self):
        """
        Called when the UI is fully constructed.  You should connect any signals here.
        """
        self.boundwidgets['Datestamp'].valuechanged.connect(self.changed_date_handler)

        
    def changed_date_handler(self,value):
        """
        When the date changes, limit the allocations available to those on that date
        """        
        myconfig=self.boundwidgets['TeamAllocationID'].config
        myconfig['layer']['filter'] =""" format_date(  "Task date" , 'yyyy-MM-dd')='""" +value[:10]+"'"
        self.boundwidgets['TeamAllocationID'].setconfig(myconfig)
        self.boundwidgets['TeamAllocationID'].updatefromconfig()

TonyFMCMC avatar Sep 12 '18 03:09 TonyFMCMC

@TonyFMCMC , you are an absolute legend! Thank you so much for sharing that snippet, it works like a charm.

To anyone else reading who is as unfamiliar with Python as me, the filter allows for your whole range of standard QGIS 2.18 expressions as long as they're escaped appropriately. So you can use ILIKE or regexp_match or whatever to filter by partial matches e.g.

myconfig['layer']['filter'] =""" "field" ILIKE '%""" +value+"""%'"""

she-weeds avatar Oct 22 '18 23:10 she-weeds

One issue I am running into with the suggested solution is that selected options don't "stick" when you edit the record in ROAM (you are required to re-select from the filtered list). I don't know enough to figure out what extra line(s) are required to overcome this.

she-weeds avatar Nov 18 '18 23:11 she-weeds

I had such a problem when the type of the field in the database and the result of the key field did not match exactly. But I am not sure in your case, sorry!

TonyFMCMC avatar Nov 20 '18 00:11 TonyFMCMC

I found out why the selection from the cascaded list wasn't "sticking" - it was because I had used a MultiList control. It works using the List control (in both 2.6 and 2.7.1). It appears that when you go back to edit a feature, the previously saved value doesn't match up to the cascaded list options in the way it normally does with a MultiList control.

she-weeds avatar Jan 04 '19 02:01 she-weeds

Glad you found the solution to that! And Happy New Year!

TonyFMCMC avatar Jan 06 '19 23:01 TonyFMCMC

Hmm, Now I think I understand what you meant, although I don't understand why changing to a list control worked for you (it didn't for me). After creating a polygon, saving it as a draft, then selecting the polygon and editing it, the value in the TeamAllocationID field in my form is blank ( the value hadn't "stuck"), even though in my database the field was still populated. It seems that when the change handler is executed it prevents loading of the field value into the widget, so I had to add a class variable and use the load() form method to temporarily store the value from the database and then restore it into the widget value in the loaded() form method. Roam version 2.6.

    def __init__(self, *args, **kwargs):
        super(Form, self).__init__(*args, **kwargs)
        self.TeamAllocationIDtemp=None      #This is necessary it seems because resetting the filter 
                                            #in self.changed_date_handler seems to prevent loading the value into the widget

    def uisetup(self):
        """
        Called when the UI is fully constructed.  You should connect any signals here.
        """
        self.boundwidgets['Datestamp'].valuechanged.connect(self.changed_date_handler)

    def load(self, feature, layers, values):
        """
        Called before the form is loaded. And before uisetup(). This method can be used to do pre checks   
        and halt the loading of the form if needed.
        """
        self.TeamAllocationIDtemp=values['TeamAllocationID']      # Store the TeamAllocationID
        

    def featuresaved(self, feature, values):
        pass
        

    def deletefeature(self):
        return False

    def featuredeleted(self, feature):
        pass

    def loaded(self):
        """
        Called after the form is loaded into the UI.
        """
        self.boundwidgets['TeamAllocationID'].setvalue(str(self.TeamAllocationIDtemp))

    def accept(self):
        return True
        
    def changed_date_handler(self,value):
        """
        When the date changes, limit the allocations available to those on that date
        """
        myconfig=self.boundwidgets['TeamAllocationID'].config
        myconfig['layer']['filter'] =""" format_date(  "Task date" , 'yyyy-MM-dd')='""" +value[:10]+"'"
        self.boundwidgets['TeamAllocationID'].setconfig(myconfig)
        self.boundwidgets['TeamAllocationID'].updatefromconfig()

TonyFMCMC avatar Jan 16 '19 02:01 TonyFMCMC

Fantastic Tony, that solves the issue even with a MultiList control! This has made a notable difference to our reporting workflow. Just as I'd finalised the forms on my last day at work before heading off for a while... :-) I'll be sure to incorporate it in the next version. This is really excellent. Thank you for sharing your solution with the community and happy new year to you too!

On Wed, 16 Jan 2019 at 13:50, TonyFMCMC [email protected] wrote:

Hmm, Now I think I understand what you meant, although I don't understand why it worked for you. After creating a polygon, saving it as a draft, then selecting it and editing it the value in the TeamAllocationID field in the form is blank (hadn't "stuck"), even though in the database the field was still populated. It seems that when the change handler is executed it prevents loading of the field value into the widget, so I had to add a class variable to temporarily store the value from the database and then restore it into the widget value in the loaded() form method.

def __init__(self, *args, **kwargs):
    super(Form, self).__init__(*args, **kwargs)
    self.TeamAllocationIDtemp=None      #This is necessary it seems because resetting the filter
                                        #in self.changed_date_handler seems to prevent loading the value into the widget

def uisetup(self):
    """
    Called when the UI is fully constructed.  You should connect any signals here.
    """
    self.boundwidgets['Datestamp'].valuechanged.connect(self.changed_date_handler)

def load(self, feature, layers, values):
    """
    Called before the form is loaded. And before uisetup(). This method can be used to do pre checks
    and halt the loading of the form if needed.
    """
    self.TeamAllocationIDtemp=values['TeamAllocationID']      # Store the TeamAllocationID


def featuresaved(self, feature, values):
    pass


def deletefeature(self):
    return False

def featuredeleted(self, feature):
    pass

def loaded(self):
    """
    Called after the form is loaded into the UI.
    """
    self.boundwidgets['TeamAllocationID'].setvalue(str(self.TeamAllocationIDtemp))

def accept(self):
    return True

def changed_date_handler(self,value):
    """
    When the date changes, limit the allocations available to those on that date
    """
    myconfig=self.boundwidgets['TeamAllocationID'].config
    myconfig['layer']['filter'] =""" format_date(  "Task date" , 'yyyy-MM-dd')='""" +value[:10]+"'"
    self.boundwidgets['TeamAllocationID'].setconfig(myconfig)
    self.boundwidgets['TeamAllocationID'].updatefromconfig()```

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/DMS-Aus/Roam/issues/414#issuecomment-454632134, or mute the thread https://github.com/notifications/unsubscribe-auth/AoB9ELZpAjJrRmz4zT5EFl1kShoIPkp8ks5vDpOQgaJpZM4VqB62 .

she-weeds avatar Jan 16 '19 12:01 she-weeds