Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue when setting option values via function #52

Open
MasterPuffin opened this issue Jan 6, 2025 · 7 comments
Open

Issue when setting option values via function #52

MasterPuffin opened this issue Jan 6, 2025 · 7 comments

Comments

@MasterPuffin
Copy link

Hello,
I found another issue:
I have an object where I use one value for a select field. When the value is set to null and initializing sprae, the dropdown is empty. When I now set the available values to an empty array and then push entries to the available values via a function, now the dropdown has selected a value. However if I now read from the original object the value set by the dropdown is still null.

Please see the following example code to reproduce this issue

<div id="container">
  <select
          :value="object.defaultmode">
    <option :each="option in options"
            :value="option.uid"
            :text="option.name"></option>
  </select>
    <button :onclick="()=>{toggle()}">Toggle</button>
    <button :onclick="()=>{dump()}">Dump</button>
</div>
const defaultOptions = [
    {uid: '1', name: 'Option 1'},
    {uid: '2', name: 'Option 2'}

]

const container = document.querySelector('#container')

const state = sprae(container, {
    options: defaultOptions,
    object: {defaultmode: null},
    toggle() {
        if (state.options.length > 0) {
            state.options = []
        } else {
            state.options = defaultOptions
        }
    },
    dump() {
        console.log(JSON.parse(JSON.stringify(state.object)))
    }
})
@dy
Copy link
Owner

dy commented Jan 6, 2025

Thanks for the catch @MasterPuffin. Please try v11.0.3 - it must be fixed there.

Unfortunately I cannot see more reliable workaround than mutation observer. It's specific case of selects - they automatically change own value if children added/changed/removed, and no input/change event is produced, so that's something outside of sprae scope.

Watch out: state gets updated in a tick.

@MasterPuffin
Copy link
Author

The issue is fixed wirh 11.0.3.
However I want to have the select blank after the change. I wrote the following function to do this

(async () => {
    new Promise(resolve => setTimeout(resolve, 0));
    state.object.defaultmode = null
 })();

It has to be this complex, because, as you mentioned, the update happens after one tick.

@dy
Copy link
Owner

dy commented Jan 7, 2025

Have you tried without delay @MasterPuffin ? It should not force you to do that, it should just work.
The only limitation this imposes is that state.object.defaultmode is not immediately reflected when you change options like state.options = [] or state.options = defaultOptions

@MasterPuffin
Copy link
Author

I just tested it again to make sure, but without the delay it doesn't work for me.

@dy
Copy link
Owner

dy commented Jan 7, 2025

Hmm, that's not a way to go. Is that the test-case above? Would you be able to write basic example when it fails? I will try to make it sync if that's indeed the cause.

@dy dy reopened this Jan 7, 2025
@MasterPuffin
Copy link
Author

I managed to reproduce the issue in a test case

<div id="container">
    <select class="form-control"
            :value="object.defaultmode">
        <option :each="option in getAvailableOperationmodes(object.operationmodes)"
                :value="option.uid"
                :text="option.name"></option>
    </select>
    <div :each="option in object.operationmodes">
        <button :onclick="()=>{toggle(option)}">Toggle <span :text="option.name"></span></button>
    </div>
    <button :onclick="()=>{dump()}">Dump</button>
</div>
const defaultOptions = [
    {
        "uid": "1",
        "name": "Test",
        "enabled": true,
    },
    {
        "uid": "2",
        "name": "Test 2",
        "enabled": true,
    }
]

const object = {
    "defaultmode": null,
    "operationmodes": defaultOptions
}

const container = document.querySelector('#container')

const state = sprae(container, {
    object: object,
    toggle(option) {
        option.enabled = !option.enabled;
        if (!object.defaultmode) {
            (async () => {
                await new Promise(resolve => setTimeout(resolve, 0));
                state.object.defaultmode = null
            })();
        }
    },
    dump() {
        console.log(JSON.parse(JSON.stringify(state.object)))
    },
    getAvailableOperationmodes(objects) {
        return objects.filter(o => {
            return o.enabled
        })
    }
})

I use the latest sprae.umd.min.js without any other code, if that matters.

@dy
Copy link
Owner

dy commented Jan 8, 2025

Can you elaborate this part:

if (!object.defaultmode) {
            (async () => {
                await new Promise(resolve => setTimeout(resolve, 0));
                state.object.defaultmode = null
            })();
        }

What are you trying to achieve/test here? Normally it's supposed object to be only passed to sprae once and forgotten, instead work with state.object.
I played around with your example - and besides this part it works as expected. I want to understand where the struggle is.

Also - I've updated to v11.0.4 with better mutation observer init order, IDK if it will make difference but you can test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants