Hide form block based on parameters from listed record

Without visual elements, it’s hard :sweat_smile:

So, let’s try to dig in: those specific users have something in common, something that we could group them together in any way?

I can group them as needed do you want them on the same airtable field ?

Here is some graphical info

image

Ok, thanks! The lookup fields are related to a “link to another record” field type that is inside the users table?

I can’t refer to the user’s table for this to work, If I could, then it would be a matter of setting up permission groups.

Your use case is a tough one! I don’t think I have the solution (without custom code)
Let me suggest this thread, it might help: Hide or show blocks based on a record's attributes

That kind of helps is just that I have to find a way to evaluate if the loggedin users email, is present on one of those 3 airtable fields from the listed record.

Custome code is very welcome my dear.

Well, here it’s 1am in Paris, so no today for me :sweat_smile: and as I am a very beginner with Javascript…

=> Let’s make it simple: @Julien_Berawen or @dcoletta how to arrange this custom code (see above) with that specific use case?

I’m so tempted to replace “data value” by {LOGGED_IN_USER:EMAIL} … But 99% chance to be a bad idea :grin:

1 Like

Thank you so much for your help, I was thinking the same about replacing values :sweat_smile:
we are probably at the same javascript level…where trial and error is usually the way to go.

One thing I can say, this is very important for securing forms in softr apps. Very very.

If not, anyone logged in, could edit other users’ records, just by reading the record ids.

I can make the logic on airtable, to void such as malicious form submissions, but I want to actually prevent them from filling out the form.

Thanx again, and you better get some sleep.

Is this a situation where you are hiding some information for cosmetic purposes, or is it a matter of information security?

If the latter, then this problem isn’t amenable to a custom code solution. To be secure the data filtering needs to happen in the server.

Thank you David,

I don’t intend to hide info from my tables. I intend to hide a softr block which is kind of a static bloc, the form block

It doesn’t matter if people inspect the page and find the block. I just don’t want the form to work.

Also, I plan to add a second validation on the backend, to void malicious or not authorized submissions.

Hi guys,

@acjnas If the number of users who need to see the form is fixed and will always be three, you could use the code snippet in the post that @matthieu_chateau refered to and amend the condition like this :

if (
(document.querySelectorAll('div[data-mappedto="user_1"][data-value={LOGGED_IN_USER:EMAIL} i]').length > 0) || 
(document.querySelectorAll('div[data-mappedto="user_2"][data-value={LOGGED_IN_USER:EMAIL} i]').length > 0) || 
(document.querySelectorAll('div[data-mappedto="user_3"][data-value={LOGGED_IN_USER:EMAIL} i]').length > 0)
)

(I haven’t tested this exact syntax, it might require some light adaptation regarding the way you use {LOGGED_IN_USER:EMAIL} as a dynamic value for your condition).

For a more generic solution that could handle more or less users, I would first create a new airtable field that would concatenate all emails and use the presence of the logged-in user’s email within that field as a condition :

if (document.querySelectorAll('div[data-mappedto="users_who_should_see_the_form"][data-value*={LOGGED_IN_USER:EMAIL} i]').length > 0)

where users_who_should_see_the_form is the new field with all the emails.

Keep in mind that this would require that you first “display” on the page the values you use as conditions (user_1, user_2 and user_3 in the first option, users_who_should_see_the_form in the second option).
You can insert them and render them invisible with hidden or collapse.

You should check first that your fields render the needed value as a string for the email adress, if they’re lookups they might not and have their value send the user’s recordId instead. To do that, after you’ve inserted the fields on your page, you can use the Inspector within your browser and check if the data-value attribute on your fields is indeed an email (or several emails within a string in the second option).

Also keep in mind @dcoletta 's warning as this is in no way a secure solution to prevent unauthorized users to input data in your form.

2 Likes

Thanx for the help Julien.

Before testing the script, I simply added a new email field to the table: ‘validEmail’ and manually entered the user email address that I expect to grant permission to access the form.

I have the need to hide two form blocks: form-es and form-en

Then I went to page custom code ==> footer and added this code:

<script>
//Hide form if 'validEmail' is different from logged-in user email
    
    document.addEventListener("DOMContentLoaded", function() {    
        var waitForData = setInterval(function () {
            if (typeof $ != 'undefined') {
                if (document.querySelectorAll('div[data-mappedto="validEmail"][data-value*={LOGGED_IN_USER:EMAIL} i]').length > 0) {
                    
                    var form1 = document.getElementById('form-es');
                    var form2 = document.getElementById('form-en');
                    form1.style.display = 'none';
                    form2.style.display = 'none';

                    
                    clearInterval(waitForData);
                }
            }
        }, 100);
    });
</script>

Then no matter the case, every logged-in user to my app can access the form.

Hey folks,

would this work ?

<script>    
    document.addEventListener("DOMContentLoaded", function() {    
        var waitForData = setInterval(function () {
            if (typeof $ != 'undefined') {
                const recordId = getUrlParam('recordId');
                if (window.records && window.records[recordId] && window.records[recordId].record.fields['fieldName'] === 'YourValue') {
                    
                    var form1 = document.getElementById('form-es');
                    var form2 = document.getElementById('form-en');
                    form1.style.display = 'none';
                    form2.style.display = 'none';

                    
                    clearInterval(waitForData);
                }
            }
        }, 100);

        function getUrlParam(name) {
            const url = new URL(window.location.href);
            let param;
            for(var key of url.searchParams.keys()) {
                if(key.toLowerCase() === name.toLowerCase()) {
                param = url.searchParams.get(name);
                break;
                }
            }
        
            if(!param && name.toLowerCase() === 'recordid') {
                param = getRecordIdFromPath();
            }
            return param;
        }
        
        function getRecordIdFromPath() {
            let pathName = window.location.pathname;
            if (pathName.indexOf('/r/rec') !== -1) {
                pathName = pathName.substr(pathName.indexOf('/r/rec') + 3);
                if (pathName.indexOf("/") !== -1) {
                pathName = pathName(0, pathName.indexOf('/'))
                }
                return pathName;
            }
            return undefined;
        }
    });
</script>

You need to play with FieldName, YourValue and Form Ids.

2 Likes

Hey,

  1. For future reference, the code that ended up solving @acjnas’ problem :
<script>
//Hide forms if 'validEmail' includes the logged-in user's email
    
    document.addEventListener("DOMContentLoaded", function() {    
        var waitForData = setInterval(function () {
            if (typeof $ != 'undefined') {
                var userEmail=window['logged_in_user']['softr_user_email'];
                if (document.querySelectorAll('div[data-mappedto="validEmail"][data-value*=' + CSS.escape(userEmail) + ' i]').length > 0) {
                    
                    var form1 = document.getElementById('form-es');
                    var form2 = document.getElementById('form-en');
                    form1.style.display = 'none';
                    form2.style.display = 'none';

                    
                    clearInterval(waitForData);
                }
            }
        }, 100);
    });
</script>
  1. @artur That looks very promising ! Does that mean we can use window.records[recordId].record.fields['fieldName'] to query any field from the current recordID, even though that specific field is not part of the page ? Is there a way to circumvent that to prevent users from querying any field on the table ?
2 Likes

Right now if the user can see the record the fields will be accessible, although in two weeks only visible fields will be available.

3 Likes

Thank you guys for your prompt help.

I tried both approaches Arthur’s and Julien’s they both work perfect.

Right now I need to fetch fields from the record that shouldn’t be visible to public , so I can not rely on the rendered divs and html, but rather in the fields from record.

Also as Julien suggested I am concatenating all emails that should access the form into one field named ‘validEmails’ and making use of the includes() method I will validate a wider access to the form.

This script, opens several possibilities inside my softr app; lets say an admin user can manage up to 5 businesses, now admin can securely add collaborators to help him manage any of his businesses.
AMAZING!

I can’t wait to showcase this app, but for now is work in progress. (77% ready).

1 Like

Hey @Julien_Berawen (and @artur) - I have a follow up on this if you guys wouldn’t mind weighing in.

I’m in the middle of putting a portal together and I used this method earlier in the week on a different page to hide a few sections based on whether or not the user belonged to a particular program (a profile type page but viewed not as the logged in user) and it’s working great.

I’m now putting together another list details page that has several elements that I’d like to show or hide based on a set of rules that involve attributes from the record. I started with an identical scenario to the one that I already have working (hide if value is “-” - reads a checkbox field from airtable) using both the solution here form Julien and the alternate from Artur and neither one are working out.

This is what I have:

<script>
   document.addEventListener("DOMContentLoaded", function() {    
        var waitForData = setInterval(function () {
            if (typeof $ != 'undefined') {
                if (document.querySelectorAll('div[data-mappedto="Allow Reschedule"][data-value = "-" i]').length > 0) {

                    var schSession = document.getElementById('schedule-session');
                    var reschSession = document.getElementById('reschedule-session');

                    schSession.style.display = 'none';
                    reschSession.style.display = 'none';

                    clearInterval(waitForData);
                }
            }
        }, 100);
    });
</script>

Similarly, this also did not work -

<script>    
    document.addEventListener("DOMContentLoaded", function() {    
        var waitForData = setInterval(function () {
            if (typeof $ != 'undefined') {
                const recordId = getUrlParam('recordId');
                if (window.records && window.records[recordId] && window.records[recordId].record.fields['Allow Reschedule'] === '-') {
                    
			    	var scheduleButton = document.getElementById('schedule-session');
				    var rescheduleButton = document.getElementById('reschedule-session');
                    scheduleButton.style.display = 'none';
                    rescheduleButton.style.display = 'none';

                    
                    clearInterval(waitForData);
                }
            }
        }, 100);

        function getUrlParam(name) {
            const url = new URL(window.location.href);
            let param;
            for(var key of url.searchParams.keys()) {
                if(key.toLowerCase() === name.toLowerCase()) {
                param = url.searchParams.get(name);
                break;
                }
            }
        
            if(!param && name.toLowerCase() === 'recordid') {
                param = getRecordIdFromPath();
            }
            return param;
        }
        
        function getRecordIdFromPath() {
            let pathName = window.location.pathname;
            if (pathName.indexOf('/r/rec') !== -1) {
                pathName = pathName.substr(pathName.indexOf('/r/rec') + 3);
                if (pathName.indexOf("/") !== -1) {
                pathName = pathName(0, pathName.indexOf('/'))
                }
                return pathName;
            }
            return undefined;
        }
    });
</script>

While I’m testing, I have the values it needs to read (this one and a few others I’ll use when I figure out what is wrong here hah) in details block at the bottom of the page fully visible:

Definitely stumped here :sweat_smile: the ability to do this is kind of central to the brief :smiley: When I tested it on that other page and it worked fine I got excited.

Any ideas? I’m going to keep tinkering but any insight would be most helpful <3

Hi @bryan.stafford, I can’t speak for @artur 's snippet, I let him answer himself, but as for mine, I think the issue probably lies with the fact that Softr’s recent updates to blocks have impacted the DOM’s structure for the sites, and the objects no longer bear the “mapped to” data attribute, hence rendering that version of the selector obsolete.

If you can provide a screenshot of the source code of your page at the point where your condition sits, I could try to give you an updated version for the selector. But Artur’s solution might still be more resistant to such changes in the future.