htmltypescriptradio-buttonsvelte

Save button does not update immediately after radio button click


I need to implement the following functionality:

  1. There are two categories - "action" and "agent", each with two values, which are implemented with "radio button" objects
  2. In the beginning of the process, the radio buttons are unchecked
  3. There is a "save" button that should be disabled until the user chooses both the "agent" and the "action".
  4. When he chooses both the "agent" and the "action" - the save button should get enabled.

Problem

My problem is that the "save" button is being enabled if I check the radio button twice, e.g., if I chose the "action", then I need to press the "agent" twice for the "save" button to be enabled.

What am I missing?

Code example

I have the following code:

Script section:

<script lang="ts">
    $: agent = ['hand', 'tool']
    $: action = ['take', 'release']

    
    function onClickRB(){
        console.log('Tring to enable the button')
        console.log('agent: ' + agent)
        console.log('action: ' + action)

        if ((typeof agent) == "string" && (typeof action) == "string"){

            (document.getElementById("saveButton") as HTMLInputElement | null)!.disabled = false;
            
        }
    }
    function onSave(){
        
    }
</script>

Main section:

<main>

        <!-- svelte-ignore a11y-label-has-associated-control -->
        <div class="label-select">
            <label class='agent'>Agent
                <div>
                    
                    <input 
                        id='hand' 
                        type='radio'
                        name='Hand' 
                        value='Hand'
                        bind:group={agent} 
                        on:click={() => onClickRB()}
                    /><label>Hand</label>
                    
                    <input 
                        id='tool' 
                        type='radio'
                        name='Tool' 
                        value='Tool'
                        bind:group={agent} 
                        on:click={() => onClickRB()}
                    /><label>Tool</label>
                </div>
            </label>

            <label class='action'>Action
                <div>
                    
                    <input 
                        id='contact' 
                        type='radio'
                        name='Contact' 
                        value='Contact'
                        bind:group={action} 
                        on:click={() => onClickRB()}
                    /><label>Contact</label>
                    <input 
                        id='release' 
                        type='radio'
                        name='Release' 
                        value='Release'
                        bind:group={action} 
                        on:click={() => onClickRB()}
                    /><label>Release</label>
                </div>
            </label>
        </div>
        <button id="saveButton" disabled on:click|preventDefault={()=>onSave()}>Save</button>
</main>

Style section:

<style>
    main {
        text-align: center;
        padding: 0em;
        max-width: 240px;
        margin: 0 auto;
    }
    @media (min-width: 640px) {
        main {
            max-width: none;
        }
    }
    .label-select{
        display: flex;
        justify-content: center;
    } 
    .agent{
        font-size: larger;
        border: 2px solid gray;
    } 
    .action{
        font-size: larger;
        border: 2px solid gray;
    } 
</style>

Thanks in advance


Solution

  • This is the wrong approach. You already bind the values from the inputs via bind:group, you just have to define the disable condition and pass that to the button in the template.

    <script lang="ts">
      let agent: string | undefined = undefined;
      let action: string | undefined = undefined;
      $: disabled = agent == null || action == null;
      // ...
    </script>
    
    <button {disabled} >...
    

    REPL

    Also note that disabled buttons are not the greatest in terms of accessiblity. Would recommend using native HTML validation and not disable the button at all, i.e. just set required on all inputs and put everything in a form. If additional logic on the client is required, handle the form's submit event and use event.preventDefault().

    REPL