Unexpected behavior with credentials

If I add a click-handler in oneditprepare and update my credentials in a callback like:

$("#node-config-input-newMachineUser").click(function () {                
                //do stuff
                $.ajax({
                    type: 'post',
                    url: url, 
                    data: params, 
                    dataType: 'json',            
                    success: function(res) {
                        $('#node-config-input-machineUserId').val(res.id);
                        $('#node-config-input-clientId').val(res.oauth2ClientId);            
                        $('#node-config-input-clientSecret').val("dummySecret");                        
                    }
                });
            })

the credentials are gone...

However, if I a register my click-handler directly on the button it works... do I miss something?

    <div class="form-row">
        <button type="button" id="node-config-input-newMachineUser" onclick="newMachineUser()" class="red-ui-button">Create New Machine User</button> 
    </div>
<script type="text/javascript">
    function newMachineUser() {
        // do stuff
        $.ajax({
            type: 'post',
            url: url, 
            data: params, 
            dataType: 'json',            
            success: function(res) {
                $('#node-config-input-machineUserId').val(res.id);
                $('#node-config-input-clientId').val(res.oauth2ClientId);            
                $('#node-config-input-clientSecret').val("dummySecret")
            }
        });
    }
</script>

oneditsave is called when the dialog is being closed. Adding a click handler at that point in time doesn't make any sense - it will never be called because you can't click the button in a dialog that has closed.

I suspect you mean to add the click handler in the oneditprepare function that is called when the dialog is being created.

Oops, that was simply stated wrong on my side. Of course I added the handler in oneditprepare . I just updated the post.

Still, the problem remains.

I'm not sure it this information matters but this is a config-node.

@Dunken please don't delete and repost replies - it triggers duplicate notifications which isn't okay.

We'll need more information to understand what's happening here. Can you share you node's HTML so we can see how you are defining the node properties and credentials?

What have you don't to try to debug this yourself? Have you confirmed the click handler is being called? Have you verified the inputs values are being updated by the code?

I'm sorry for the deletes and I also mixed up a few things... Let me start from scratch :slight_smile:

I have a config-node where I want to create a machine-user in the background. First I thought I would introduce a button inside the editor dialog. For this I attached the click-handler in oneditprepare (I also tried in html itself but result is the same as expected). This is working as expected which means that the ajax-callback stores the credentials in the three cred-fields.

Here's the code for this:

oneditprepare: function() {
            var node = this;

            $("#node-config-input-newMachineUser").click(function () {                
                //do stuff
                $.ajax({
                    type: 'post',
                    url: url, 
                    data: params, 
                    dataType: 'json',            
                    success: function(res) {
                        $('#node-config-input-machineUserId').val(res.id);
                        $('#node-config-input-clientId').val(res.oauth2ClientId);            
                        $('#node-config-input-clientSecret').val("dummySecret");                        
                    }
                });
            })        
        },

While this is great it has one drawback: if the user clicks on cancel button after the create button the user is already created (I first wanted to delete user in oneditcancel but this didn't work either as this doesn't point to the context in oneditcancel...).

Anyway instead of using an extra button at all I turned to simply do stuff when a user click on "Add". I moved the code from the click-handler to oneditsave:

        oneditsave: function() {
            // do stuff
            $.ajax({
                type: 'post',
                url: url, 
                data: params, 
                dataType: 'json',            
                success: function(res) {
                    $('#node-config-input-machineUserId').val(res.id);
                    $('#node-config-input-clientId').val(res.oauth2ClientId);            
                    $('#node-config-input-clientSecret').val("dummySecret");                        
                }   
            });
        },

While the success-callback gets called as excpected (and the three fields set), this.credentials is empty afterwards. This means when I open up again the editor the three fields set in the callback are empty.

You cannot do asynchronous work like that in oneditsave. By the time it completes, the dialog will have been closed and none of the inputs will exist.

1 Like

OK, that makes sense. Then I would fall back to my first solution (add button and use click handler). However, what's best practice how to do handle a Cancel? I definitively need to clean-up in this case. As I mentioned this is almost empty in oneditcancel (it actually only contains the id of the node itself) but even if it would be populated I guess the same restriction applies and I can't do any asynchronous calls in oneditcancel...

Surely I could provide a clean-up button but I don't like to leave this to up to the user...

You can make async calls in oneditsave and oneditcancel - you just cannot interact with the edit dialog when they complete.

So it would seem for the cancel case, you can fire off the request to remove the credentials without needing to do anything when it completes.

OK, that also make sense :slight_smile: Then I'm back to the problem with this... for some reason I don't have access to this.credentials or anything else but the id...

image (4)

FYI: console.log(RED.nodes.node(node.id)); returns null

Could it be because it's a config-node?

BTW, those calls don't HAVE to be async, you should be able to force them to wait. Obviously that causes a pause to the user.

And triggers a number of deprecation warnings in most modern browsers.

Just because you can, doesn't mean you should. :wink:

Sheesh, some warnings are meant to be ignored :rofl:
Sometimes sync IS better than async :wink:

Just because you can, doesn't mean you should. :wink:

I would stick with this advice. :slight_smile:

Any idea about my oneditcancel issue? I guess I could also store everything I need in a global (e.g. window) context... seems like the last resort to me though...

As you're talking about config nodes, there are two possible scenarios here.

  1. you have clicked 'add new config node'
  2. you are editing an existing config node

If you cancel adding a new config node, then there is no node available to cancel - in that scenario the current code does call it with this set to an object with just the id of the node that would have been added.

If you cancel the edit of an existing node, this will be set to the full node object.

I can vaguely remember why it was done like this - the rationale being you are cancelling creating the node so why do you need access to any of the properties you are throwing away? In the cases were we interact with remote APIs to generate resources for the node, we use the node's id as the key, so that's all we needed to undo whatever was done.

Having said that, I can't see a strong reason not to pass in the full node object for that scenario. Something we can look at for the imminent 2.1.4 release.

  1. you have clicked 'add new config node'

That's my scenario.

In the cases were we interact with remote APIs to generate resources for the node, we use the node's id as the key, so that's all we needed to undo whatever was done.

So you're saying instead of keeping my own id's I should always use the node-id as the identifier of resources created in the backend?

Something we can look at for the imminent 2.1.4 release.

Highly appreciated. Too late for me for the moment. Any strong reason not to store stuff in window?