My application connects to a websocket and stores the websocket's messages in an array messages, which I display using x-for:
In the script:
messages = [];
ws = new WebSocket("...");
ws.onmessage = (event) => {
data = JSON.parse(event.data)
messages.push(data)
}
However, this does not update the view of the messages I have in the html file.
When modifying the messages object from anywhere else in my script (i.e., not the callback), the changes are reflected and the view is updated.
What am I doing wrong?
As a reproducible (but different) example: https://codepen.io/mr_trizzle/pen/PoPaowm?editors=1011.
I guess the issue is the same.
Clicking the addFour via @click button works, but the button using an eventhandler does not.
Hii @tristndev, are you setting up and connecting to the WebSocket inside of your x-init callback?
No, it's just in the regular javascript I attached to my html.
Since Alpine "clones" the original data object and stores an observable copy, any modifications made to the original object won't be reflected in the component. That's why it's not re-rendering upon modification.
You could setup the WebSocket connection inside of x-init and then reference this.messages instead of messages.
function data() {
return {
messages: [],
ws: undefined,
init() {
this.ws = new WebSocket()
this.ws.onmessage = (event) => {
data = JSON.parse(event.data)
messages.push(data)
}
}
}
}
<div x-data="data()" x-init="init">
<!-- component contents -->
</div>
This approach will ensure you're modifying the data on the component, not an outside object which Alpine has no reference to.
This works - thanks!
Is there any other way however to make sure I reference the right object?
Calling the init() function from the html file rather than from the script leaves me feeling a bit... weird?
Not currently, a couple of people have mentioned a similar frustration.
If you were to initialise the WebSocket on click of a button or similar, you could setup this.ws then but I imagine you want to do it as early as possible, which is the purpose of x-init.
This works - thanks!
Is there any other way however to make sure I reference the right object?
Calling theinit()function from the html file rather than from the script leaves me feeling a bit... weird?
There isn't a way to use x-init without setting it up in the template, the premise of Alpine is to be very much markup and directive driven.
If I remember correctly, there was an issue to auto-call an "init" function defined in your component but it got parked.
Great, thank you both, @ryangjchandler and @HugoDF - especially for your quick replies!
Feel free to close the issue.