woutdp / live_svelte

Svelte inside Phoenix LiveView with seamless end-to-end reactivity
https://hexdocs.pm/live_svelte
MIT License
1.01k stars 38 forks source link

LocalStroage and Session Storage not defined #77

Closed Maxino22 closed 10 months ago

Maxino22 commented 10 months ago

I was trying to use data i stored in the svelte store on a new liveview it however came as blank and navigating back the data was logged on the console am still new to liveview and i;m geussing the two are independed i tried calling the client session storage or local storge but neigther works ...

I have been looking for ways to pass data within liveview minus saving in the database initially am handling a multi stage form how would you go through now that livesvelte is in picture.. sessionStorage is not defined

ReferenceError: sessionStorage is not defined
    at /home/maxino/Value_8/Realest8/realest8_platform/priv/svelte/server.js:9897:3
    at $$render (/home/maxino/Value_8/Realest8/realest8_platform/priv/svelte/server.js:9261:18)
    at Object.render (/home/maxino/Value_8/Realest8/realest8_platform/priv/svelte/server.js:9269:20)
    at render2 (/home/maxino/Value_8/Realest8/realest8_platform/priv/svelte/server.js:9938:22)
    at callModuleFunction (/home/maxino/Value_8/Realest8/realest8_platform/deps/nodejs/priv/server.js:32:23)
    at getResponse (/home/maxino/Value_8/Realest8/realest8_platform/deps/nodejs/priv/server.js:44:26)
    at Interface.onLine (/home/maxino/Value_8/Realest8/realest8_platform/deps/nodejs/priv/server.js:53:39)
    at Interface.emit (node:events:514:28)
    at [_onLine] [as _onLine] (node:internal/readline/interface:422:12)
    at [_normalWrite] [as _normalWrite] (node:internal/readline/interface:616:22)
Maxino22 commented 10 months ago

I am trying to use local storage as opposed to hooks but it crashes with local storage not defined these are all in the svelte folder

woutdp commented 10 months ago

Since you're rendering on the server it doesnt have access to localstorage or sessionstorage. There's 2 options:

  1. Call any localstorage/sessionstorage code inside the svelte onMount function. This ensures it's only called on the client.
  2. Or disable Server Side Rendering (SSR)

Option 1:

<script>
  import {onMount} from "svelte"

  onMount(async () => {
    // Interact with sessionstorage or localstorage here
  })
</script>

Option 2:

<.svelte name="YourComponent" ssr={false} socket={@socket} />

Let me know if that works :)

Maxino22 commented 10 months ago

thanks the example really helped

Maxino22 commented 10 months ago

Hi @woutdp just a question I have data as props on my svelte session storage I want to have an event that will enable me to save property to my db but first things first I just want to be able to get the data from my storage and log it on the handle event.

defmoduleExampleWeb.AddSingleUnit do
  use  ExampleWeb, :live_view
  alias Example.Property.Properties
  alias Example.Property.Utilities

  def mount(_params, _session, socket) do
    property = %Properties{}
    _utilities = %Utilities{}
    {:ok, assign(socket, property: property)}
  end

  def render(assigns) do
    ~H"""
    <.svelte name="property_manager/AddUtilities" props={%{property: @property}} socket={@socket} />
    """
  end

  def handle_event("go-back", _params, socket) do
    {:noreply,
     socket
     |> push_navigate(to: ~p"/properties/add-single-unit")}
  end

  def handle_event("save-property", _params, socket) do
    IO.puts(socket)

    {:noreply,
     socket
     |> put_flash(:info, "adding to db")}
  end
end

This is my example setup on the phoenix side

and without going into too much detail when the page loads i read the data from session storage

<script>
  export let Property
  export let utilities

  beforeUpdate(()=>{
    if (sessionStorage.getItem("Property") === null){
      window.location.href = "/properties/add-single-unit"
    } else{
      Property = JSON.parse(sessionStorage.getItem("Property"))
    }
  })

</script>

<button phx-click="save-property" class="btn py-1 px-7">Save</button>

That button when submitted is what i was hoping will pass the set item when i log the socket am getting this error

[error] GenServer #PID<0.1884.0> terminating
** (Protocol.UndefinedError) protocol String.Chars not implemented for #Phoenix.LiveView.Socket<id: "phx-F4Gy7OfUfSsfvw3j", endpoint: Realest8Web.Endpoint, view: Realest8Web.PropertyManagerLive.PropertyLive.AddSingleUnitUtilities, parent_pid: nil, root_pid: #PID<0.1884.0>, router: Realest8Web.Router, assigns: %{__changed__: %{}, flash: %{}, live_action: :new, property: %Realest8.Property.Properties{__meta__: #Ecto.Schema.Metadata<:built, "properties">, id: nil, property_name: nil, slug: nil, address: nil, type: nil, unit_ownership: nil, manager_id: nil, inserted_at: nil, updated_at: nil}}, transport_pid: #PID<0.1875.0>, ...> of type Phoenix.LiveView.Socket (a struct). This protocol is implemented for the following type(s): Atom, BitString, Date, DateTime, Decimal, Float, Hex.Solver.Assignment, Hex.Solver.Constraints.Empty, Hex.Solver.Constraints.Range, Hex.Solver.Constraints.Union, Hex.Solver.Incompatibility, Hex.Solver.PackageRange, Hex.Solver.Term, Integer, List, NaiveDateTime, Phoenix.LiveComponent.CID, Postgrex.Copy, Postgrex.Query, Time, URI, Version, Version.Requirement
    (elixir 1.14.5) lib/string/chars.ex:3: String.Chars.impl_for!/1
    (elixir 1.14.5) lib/string/chars.ex:22: String.Chars.to_string/1
    (elixir 1.14.5) lib/io.ex:767: IO.puts/2
    (realest8 0.1.0) lib/realest8_web/live/property_manager_live/property_live/add_single_unit_utilities.ex:25: Realest8Web.PropertyManagerLive.PropertyLive.AddSingleUnitUtilities.handle_event/3
    (phoenix_live_view 0.19.5) lib/phoenix_live_view/channel.ex:401: anonymous fn/3 in Phoenix.LiveView.Channel.view_handle_event/3
    (telemetry 1.2.1) /home/maxino/Value_8/Realest8/realest8_platform/deps/telemetry/src/telemetry.erl:321: :telemetry.span/3
    (phoenix_live_view 0.19.5) lib/phoenix_live_view/channel.ex:221: Phoenix.LiveView.Channel.handle_info/2
    (stdlib 4.0) gen_server.erl:1120: :gen_server.try_dispatch/4
    (stdlib 4.0) gen_server.erl:1197: :gen_server.handle_msg/6
    (stdlib 4.0) proc_lib.erl:250: :proc_lib.wake_up/3
Last message: %Phoenix.Socket.Message{topic: "lv:phx-F4Gy7OfUfSsfvw3j", event: "event", payload: %{"event" => "save-property", "type" => "click", "value" => %{"value" => ""}}, ref: "31", join_ref: "4"}
State: %{components: {%{}, %{}, 1}, join_ref: "4", serializer: Phoenix.Socket.V2.JSONSerializer, socket: #Phoenix.LiveView.Socket<id: "phx-F4Gy7OfUfSsfvw3j", endpoint: Realest8Web.Endpoint, view: Realest8Web.PropertyManagerLive.PropertyLive.AddSingleUnitUtilities, parent_pid: nil, root_pid: #PID<0.1884.0>, router: Realest8Web.Router, assigns: %{__changed__: %{}, flash: %{}, live_action: :new, property: %Realest8.Property.Properties{__meta__: #Ecto.Schema.Metadata<:built, "properties">, id: nil, property_name: nil, slug: nil, address: nil, type: nil, unit_ownership: nil, manager_id: nil, inserted_at: nil, updated_at: nil}}, transport_pid: #PID<0.1875.0>, ...>, topic: "lv:phx-F4Gy7OfUfSsfvw3j", upload_names: %{}, upload_pids: %{}}

is there s better approch to this i typically want to pass the props update them and save Kindly assist

woutdp commented 10 months ago

Hi @Maxino22

There's a couple of things I see that might be causing the issue:

  1. Make sure property is lowercase in your Svelte file: export let Property -> export let property
  2. Make sure the property you're passing is JSON serializable. You can test this by doing something like Jason.Encode!(property) inside the mount. This should not crash. More on this here
  3. Make sure to use IO.inspect instead of IO.puts to print the socket in your handle_event function
Maxino22 commented 9 months ago

Thank you very much I had actually figured it out.. Thank you for your work and the help