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

Question about interactions between client and server and vue componenets executing JS code #838

Open
JovanVeljanoski opened this issue Oct 28, 2024 · 5 comments

Comments

@JovanVeljanoski
Copy link
Collaborator

JovanVeljanoski commented Oct 28, 2024

Hi,

This might be a strange question/request but please bear with me..

I've found out that for some cases, having something executed by the front-end is "better" than on the server side. An example that comes to mind is, say your application needs to play a sounds. If you are gonna deploy this, it seems to me easier to write some JS code to play sound using the browser capabilities, than fight with device ports etc.. one is gonna do the sounds generation on the server side.

Solara allows this actually, with the @component_vue one can make a, say button that when pressed plays a sounds. An example of this is (kind of pseudo code)

@solara.component_vue("play_audio.vue")
def PlayAudio(audio_data: list[bytes], label: str = 'Listen', style: str = ''):    ...

And the corresponding vue component will be something like

<template>
  <div>
    <audio ref="audioPlayer" :src="audioSrc" style="display: none;"></audio>
    <v-btn @click="playAudio" :disabled="!audioSrc" :color="color" :style="style">
      <v-icon left>mdi-volume-high</v-icon>
      {{ label }}
    </v-btn>
  </div>
</template>

<script>
export default {
  props: {
    audio_data: {
      type: Array,
      required: true
    },
    label: {
      type: String,
      default: 'Listen'
      },
    color: {
      type: String,
      default: 'primary'
    },
    style: {
      type: String,
      default: ''
    },
  },
  
  data() {
    return {
      audioSrc: null,
    };
  },
  
  playAudio() {
   // implementation of this
    },
    
 // whatever else is needed for the JS to work
</script>

This kind of approach works fairly well and I am very happy that solara provides this functionality!

My problem is the following:

  • It is kind of once-directional. If I make a component in this way, it is can not communicate with the rest of the solara (python) code. For instance, say I want to play some sound with the approach above, but at the same time I want to.. for example disable some button that is written in solara.Button() way (so in python).
  • Of course I can make the entire "UI" in vue, and then I can disable another button when the play button is played. But that is just writing fronted code (from my basically 0 knowledge of that), and is kind of moving away from the power/elegance of solara.
  • Is it possible to write some kind of JS function.. that can be executed from solara.Button(on_click) instead? Maybe somehow wrapped in python. That will allow for making solara.task that I find useful for things. And one can "wrap" it so that, some things can be executed on the server, and relevant stuff can be dispatched to the browser.
  • Ultimately (pretty sure this is not possible.. and maybe completely along the wrong lines of thinking.. but sometimes I think it would be awesome if.. the @component_vue could be made 2-directional with the python server.. i.e... you dispatch something to the frontend (clinet) a computation is done there, or some process or whatever, and the result can be sent back to the server for something else to be updated (like a state, or whatever needs to happen next).

I hope at least some of these things make sense..

looking forward to some kind of answer / advice / or pointing in the right direction. Thank you!

@maartenbreddels
Copy link
Contributor

Hi Jovan,

another good question.
I am working on documentation that elaborates a bit more on that. But given that our docs at https://solara.dev/documentation/api/utilities/component_vue didn't have examples, I expanded this a bit at #844

However, I think that most of the questions are answered by #847 especially by the last example on the vue component howto.

@JovanVeljanoski
Copy link
Collaborator Author

JovanVeljanoski commented Nov 6, 2024

Thanks! That's very helpful. I am still not sure how the changes are propagated back to the server from the vue component though, i don't think there is an example in the documentation for that.

But I think I did find an example from you somewhere ( i think it was the example of the local_storage access), and maybe that has a hint.. will analyze it more in depth when I have a chance!

Thank you!

Edit: Feel free to close this if you see fit (or when the associated docs PRs are merged, or whenever you thing appropriate)

@JovanVeljanoski
Copy link
Collaborator Author

Hi again,

Since I could not find an example of the following.. can maybe someone try to explain what I am doing wrong (or if what I am trying to do is possible).

Link to pycafe example

Basically, i have a vue component, and when I click a button I want some output to be synced to a solara reactive component.

In this case, i would like a simple thing.. the component is a textbox and a button, so when the button is clicked, the value of the input field to be synced to a reactive variable.

If this is possible, would be nice to have an explicit example on this. My apologies if this is covered in an example somewhere that i have missed

@iisakkirotko
Copy link
Collaborator

Hey!

The issue you're running into has to do with naming of the arguments - argument names like on_foo are automatically tied to the corresponding argument foo, and will be called whenever the value of foo changes on the javascript side. However, you're not actually changing the value of value, which means that on_value never gets called. Note that on_foo from python doesn't actually get mapped to functions on_foo in javascript.

The easiest fix is therefore to change from calling this.on_value in the vue template to simply assigning to this.value, which will trigger on_value in python, like I've done in this py.cafe project.

Another option would be to make use of one of the other type of magic argument, event_bar, which will get mapped to a function bar in javascript. You can find the same example using this method here.

@JovanVeljanoski
Copy link
Collaborator Author

Hi!

Thank you @iisakkirotko ! This was exactly the explanation I was looking for! Thank you again!
If this can somehow find its way into the docs, would be amazing!

(feel free to close this issue when/if you see fit)

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

3 participants