Surface - A component-based library for Phoenix LiveView

Hey Surface users! Is there a way to validate only the current field in the form? The one that user interacts with. In LiveView you can achieve it by adding the data attribute. Does anyone know how to do it in Surface?

 def error_tag(form, field) do
  Enum.map(Keyword.get_values(form.errors, field), fn error ->
    content_tag(:span, translate_error(error),
      class: "form-error",
      phx_feedback_for: input_name(form, field),
      data: [phx_error_for: input_id(form, field)]
    )
  end)
end

Check the built-in ErrorTag component.

I did and everything looks right :confused: For the interested, Iā€™ve moved the discussion here Form validation: validate only the field you interact with Ā· Issue #480 Ā· surface-ui/surface Ā· GitHub

to play around with stateless components (phx 1.6rc, LV 0.16), is it surface master or ms_function_components branch ?

I believe itā€™s master if you want to play around with Surface.Component.

Itā€™s more about using Surface.Component the same way as function components from LV 0.16, as with master it seems not be possible to use Surface.Component components in ~H blocks, e.g. for dead views. If function components (from LV) work in Surface.LiveComponent components, it would be great, Iā€™ve not tried this with master yet.

@odix67 itā€™s possible to use stateless Surface.Component components in dead views as long as you use ~F instead of ~H. So make sure you import Surface and use the version on master.

In the near future, you will be able to use Surface components in ~H too but only after LV incorporates other core features from Surfaceā€™s component model, for instance, slots, which is already on the roadmap.

2 Likes

@msaraiva, thank you for your reply, thatā€™s good news. Iā€™ve also played around with LV function components using them in stateful surface components (using the ms-function-component branch) with partly success, at least function components seem to work just with attributes, but those with a ā€œslotā€ (inner_content) are failing with ** (CaseClauseError) no case clause matching: {[]}, but I think, here it is not the right place to discuss this, isnā€™t it ?

Hello,

Two questions from a very inexperienced elixir/phoenix dev:

  1. Will Surface once include a data table as shown as https://datatables.net/ ? Or will this never be possible without a JS framework?

  2. Is there a least viable but complete example available (as code of a phoenix app)? I would like to see one component in action and then read the code to be able to conclude whether I understand how to use it. (edit: or even a tutorial).

Iā€™m going to give a shoutout to this project because I think itā€™s an AMAZING example of surface in action!! (nothing to do with me, just looked at the code quite a bit before I jumped into surface)

Note Iā€™ve not looked at the code in a year, itā€™s possible it doesnā€™t show off all the latest innovations of surface, but I think you will be very impressed with his tables and how the graphs update in response to clicks elsewhere, etc!

3 Likes

Indeed thatā€™s a good find!

1 Like

Thank you. I am working on a reboot of that one. Back when I did it I was new to LiveView and there are things I would like to do differently now- both in backend and frontend.

3 Likes

I was working on this one for Spawnfest. (That code isnā€™t as polishedā€¦ yet)

While it was planned and done in the span of 48 hours, I realize given time and guidance i can pull if off. I will be using the Covid19 Dashboard reboot as test-bed for that. UIKit is a great UI framework and getting a Surface wrapper for it was easier than I feared.

3 Likes

Hey! This sounds excellent! Note that I hit an error following the instructions in the readme. Using a Mac, recent elixir/erlang, I do ā€œmix deps.getā€, then ā€œmix devā€ and it ends like this:

Generated surface_catalogue app
** (ArgumentError) unknown application: :lotus
    (elixir 1.12.3) lib/application.ex:893: Application.app_dir/1
    (surface 0.5.0) lib/mix/tasks/compile/surface.ex:139: Mix.Tasks.Compile.Surface.app_modules/1
    (surface 0.5.0) lib/mix/tasks/compile/surface.ex:59: anonymous fn/2 in Mix.Tasks.Compile.Surface.get_colocated_assets/0
    (elixir 1.12.3) lib/enum.ex:2385: Enum."-reduce/3-lists^foldl/2-0-"/3
    (surface 0.5.0) lib/mix/tasks/compile/surface.ex:16: Mix.Tasks.Compile.Surface.run/1
    (mix 1.12.3) lib/mix/task.ex:394: anonymous fn/3 in Mix.Task.run_task/3
    (mix 1.12.3) lib/mix/tasks/compile.all.ex:92: Mix.Tasks.Compile.All.run_compiler/2
    (mix 1.12.3) lib/mix/tasks/compile.all.ex:72: Mix.Tasks.Compile.All.compile/4

However, notwithstanding that, this sounds really interesting. I think surface potentially makes for the ultimate ā€œwikiā€ language. Iā€™ve been chasing various ideas for static websites for many years, and itā€™s always a problem to use wiki shortcuts as you inevitably get boxed in when you want to wrap more complex UI components. The surface approach is great for hiding all the implementation details within the fewest XML alike enclosing blocks.

How do you rate UIKit vs Bulma/Bootstrap for this use case though? There seems like a reasonable amount of overlap? Iā€™m not familiar with UIKit, what is itā€™s advantage?

Which means I did a pretty bad job at writing that Readme :facepalm: Iā€™ll get back to you later today on this.

Is rendering a Phoenix Component in a Surface View possible?

defmodule AppWeb.Shared do
   def logo(assigns)
        <img src={Routes.static_path(@conn, "/images/logo.svg")}/>
   end
end

defmodule AppWeb.Shared.Components.Navbar do
   use AppWeb, :surface_component
  
   def render(assigns) do
    ~F"""
        <.AppWeb.logo />
    """
   end 
end

Something like this is possible?

you have to use the master branch for doing this, as already answered in post 169

1 Like

Not sure if they are same. The link you gave suggests that we use sigil F instead of sigil H. Once we use sigil H, that component is not usable in regular heex.
My question was how to use a phoenix component inside surface component.

ok, this is more or less answered in followup post (170), as the mentioned branch is already merged into master, give it try.

1 Like

Dear @odix67 , Thanks for pointing to the correct resource.
I can confirm that it is indeed working. We can call Phoenix component inside surface component.
For all others, my sincere apology for posting a question with out verifying existing knowledge base.