Open roger120981 opened 6 months ago
@roger120981 Certainly! I'm working on some examples right now.
Will show:
That said, it should be as straightforward as installing using npm install
and using these libraries in Vue components. No magic here, it should just work ;)
Any more examples you'd like to see?
@Valian I have been working in the geospatial industry for years, and many times a dashboard is needed to visualize different indicators coming from the backend. It would be interesting to integrate some example with libraries like maplibrejs or deckgl into this stack, I know there is a wrapper called vue-maplibre-gl, even if it is simple it is fine for me, I just want to see the possibilities of live-vue for future projects. Thanks
I am really looking forward to the forms examples. How do we combine the server validation with a client side input component. I hope it will not be regular JS way - but - nearer to the Ecto, Phoenix way.
I'm thinking what would be the best way to solve it.
Probably I could implement Jason.Encoder
for changeset and add some utils to extract errors for a given (possibly nested) field 🤔
Hmm... can we not use phx-data and phx-events - and - render the inputs in a regular phoenix form? Your solution looks definitely workable - but - I am worried - we are moving more and more away from the regular Phoenix Development approach. That is when the maximum benefit from the library can be derived. My two cents. Sorry, if it is not making sense.
data |> Ecto.Changeset.cast(...) |> to_form(as: "form")
<.input field={form[:field]}>
component. form[:field]
basically extracts id, name, errors and value from changeset. Your <.input>
component makes use of it: def input(assigns) do
~H"""
<div phx-feedback-for={@name}>
<.label for={@id}><%= @label %></.label>
<input
type={@type}
name={@name}
id={@id}
value={Phoenix.HTML.Form.normalize_value(@type, @value)}
class={[
"mt-2 block w-full rounded-lg text-zinc-900 focus:ring-0 sm:text-sm sm:leading-6",
"phx-no-feedback:border-zinc-300 phx-no-feedback:focus:border-zinc-400",
@errors == [] && "border-zinc-300 focus:border-zinc-400",
@errors != [] && "border-rose-400 focus:border-rose-400"
]}
{@rest}
/>
<.error :for={msg <- @errors}><%= msg %></.error>
</div>
"""
end
In other words, it simply updates classes and render errors.
phx-change
or phx-submit
. It collects all the inputs and their values into an object and pushes it as an event to LiveView, so you can validate / handle submit. So this is a small overview how it works with LiveView. What can we accomplish with LiveVue?
<.vue>
, phoenix no longer is responsible for rendering that component. We can't directly use components from Elixir (unless we'll go with slots, but it's not always an option).phx-submit
etc in Vue. So we can and should make it working. To render form in Vue and make use of easy live validation from Phoenix, we'd need to:
<.vue form={@form}>
. It would require serializing form to JSON. LiveVue
js library to render these forms, mimicking LIveView behaviour (naming, ids, errors etc).<script setup lang="ts">
import {useForm} from 'liveVue';
const props = defineProps<{form: any}>();
const form = useForm(props.form);
</script>
<template>
<form phx-submit="submit">
<input type="text" :id="form['field'].id" :name="form['field'].name" value="form['field'].value">
</form>
</template>
This is just a quick sketch, but I believe it might be the best apprach. Maybe we could provide some built-in components for rendering inputs.
@cvkmohan how do you like it? do you have any other ideas?
That is a detailed example @Valian. Thanks a lot.
I am not sure about the difficulties - but - the best DX comes from using even the form component from phoenix
only.
<.input>
is a phoenix functional component. If we can replace the call with a vue component
- That will give the best experience for the developer.
If we can put up such workflow, we will be leaving the extract id, name, errors and value to the regular workflow itself.
Loud thinking - can we have an <.vue_input>
component that interacts with Phoenix.HTML.FormField
structure in both directions.
I think the main point of contention in handling forms in LiveVue application would be - what is the lowest atomic unit - Is it form
or form_component
(Each input unit)
If we make form
to be the atomic unit - advantage would be - entire Vue Input Component System would be at disposal for developer. DateRange, Tree, Tags - you name it - it will be accessible to the application. However, the disadvantage would be that the Form-Ecto communication that is built as a protocol will be broken. So, we need to bridge that gap. As you said, Json encoding - and - translating the to-and-fro messages in realtime.
If we make the form_component
as the atomic unit - advantage would be - we can completely rely on Phoenix built-in form handling and use a mixture of Phoenix Function Components and Vue Components to build the form. It is a very seamless way for the application developer in the development flow. The disadvantage is - every Vue Input Component needs to be put in a wrapper at the least to correspond to the protocol.
So, both approaches have their positives and negatives.
One wild thought that occurred to me is - if we are using a Vue UI library like shadcn
etc. - style the basic input components
using styles that match shadcn
using CSS - and - then build forms using Phoenix LiveView itself for Input Components - and - use Vue Components for everything else.
I was just thinking aloud for anyone following thread. If it is not relevant please feel free to delete.
Btw, I'm playing with radix-vue/shadcn-vue and it seems to work with default setup (tailwind based), at least, Button and Accordion work. Now I'm going to make it work with UnoCSS and get rid of tailwind.
@Valian First thanks for an a amazing library!
Second, I was wondering if we can make phoenix and liveVue work in an ionic mobile app, I've been researching for a couple of days, but so far have not found anything similar.
Phoenix isn't the best idea for a mobile app, but it's a great fit for a web app I am building, that needs a mobile port.
@OmarGoubail It's an interesting challenge.
In the past I used Capacitor to convert Vue.js app into mobile one. It worked really well, but it has an assumption all the assets are available in a single directory (index.html, scripts, images etc) and routing is handled by the frontend.
LiveVue is designed to be used within LiveView, so it's a normal server send HTML than later gets interactive thanks to Vue and a persistent websocket connection.
I don't have a solution to your problem, but maybe instead of using LiveVue you might want to look into eg. https://hexdocs.pm/live_state/readme.html and try to incorporate it into ionic mobile app? It could let you use a familiar server-state approach and keep your existing framework? Another option is to use LiveView Native, but I'm not sure how production-ready it is.
@Valian I appreciate the reply, I have not found a single resource or managed to get it working till now, I think I will just have to use a separate front end framework.
Thank you for pointing me to live state, it's an interesting project, will definitely explore it, and I will definitely keep an eye on LiveNative they don't support android just yet, but the project is very exciting.
For anyone interested, I've added a WIP example_project
to the repository. You should be able to run it as any other phoenix project.
Once it will be a bit more polished I'll deploy it somewhere 😉 but for now can be used as an easy way to play with the library and test changes.
Would be really great to see how to setup https://vuetifyjs.com for example.
Well it should work out of the box :)
Install it, import and use in Vue components. Nevertheless, might be good to include it in the example project. Would be amazing if you could try to contribute a PR @lalabuy948 !
Hi @Valian I created repo since it's yet not working I didn't make a proper PR to yours. It's fresh app with live_vue
.
At the moment I got stuck with vuetify config, there is an issue with loading css properly on vite side. Since I am backend guy those configs for me way over complicated 😅, if someone could take a look would much more appreciated. Once it will be finalised I will submit proper PR.
Essentially I tried to use vite-plugin-vuetify
as vuetify
recommends, but no luck. Same as creating custom one, it's under assets/plugins/vuetify.js
.
// vite.config.js
import vuetify from "vite-plugin-vuetify";
// import vuetify from "./plugins/vuetify";
@lalabuy948 I created a PR to your repo where I got it mostly working (SSR doesn't work yet, but hopefully will be soon). See more here https://github.com/lalabuy948/LiveVueVuetifyjs/pull/1
Added PR
Is it possible to create a small example that integrates third-party libraries such as vue-flowbite or shadcn?