filament icon indicating copy to clipboard operation
filament copied to clipboard

`KeyValue` `->reorderable()` doesn't work

Open sandersjj opened this issue 1 year ago • 5 comments

Package

filament/filament

Package Version

v3.2.16

Laravel Version

v10.41.0

Livewire Version

No response

PHP Version

PHP8.2.15

Problem description

KeyValue::make('meta')
    ->reorderable()

This should reorder the key/values and save them in the db as such. However when you change the order and reload the page or go back to the edit page. The ordering has not changed

Expected behavior

The Ordering set by the user should be respected

Steps to reproduce

  1. go to http://filament-issue.test/admin/products/1/edit
  2. Save an order.
  3. Go back to http://filament-issue.test/admin/products/1/edit
  4. Change the order and save.
  5. Reload and the order has not changed

Reproduction repository

https://github.com/sandersjj/filament-issue

Relevant log output

No response

sandersjj avatar Jan 28 '24 21:01 sandersjj

Duplicate of #9030? Please check your Livewire version

danharrin avatar Jan 29 '24 12:01 danharrin

Duplicate of #9030? Please check your Livewire version

I have checked it and I am running livewire v3.4.2.

This Pr has been merged in v3.4.0 so it didn't solve the issue yet.

sandersjj avatar Jan 29 '24 12:01 sandersjj

@sandersjj, have you found the fix yet?

joowdx avatar Mar 20 '24 07:03 joowdx

@sandersjj, have you found the fix yet?

No I ended up not using the KeyValue field.

sandersjj avatar Mar 20 '24 07:03 sandersjj

I think the problem itself is in trying to add the ordering to one-dimensional array.

json.org states that:

An object is an unordered set of name/value pairs.

That not only means that order of name/value pairs is (could be) not preserved, but also that two objects which differ only by order of name/value pairs are (should be) considered the same.

On the other hand, php.net states that:

An array in PHP is actually an ordered map.

The order is preserved for string keys, but numeric keys could not be ordered inherently.
Also, as we can see, Livewire tracks changes in JS objects with no regards to name/value pairs order, in order to minimize payload (and imho it's a good choice).

Thus, the KV component itself should either not have "ordering" feature, or change the storage mechanism to "array of objects".

For example, instead of storing as: { one: "One", two: "Two" } it could be: [ { key: "one", value: "One" }, { key: "two", value: "Two" } ]

This way, the ordering will be preserved both in frontend and backend. Here is the small demonstration: https://wirebox.app/b/41729

StyxUA avatar Apr 06 '24 00:04 StyxUA

change the storage mechanism to "array of objects".

For example, instead of storing as: { one: "One", two: "Two" } it could be: [ { key: "one", value: "One" }, { key: "two", value: "Two" } ]

@danharrin what do you think about this? do you think this can be implemented in v3 with backward compatible or only in v4?

wychoong avatar May 24 '24 08:05 wychoong

This has been handled in v4 (#13249) by updating the internal data structure as per #12943, and then masking that internal state with a new "cast" to avoid breaking changes to $get() and $set() etc.

danharrin avatar Jun 14 '24 10:06 danharrin