alpinejs / alpine Goto Github PK
View Code? Open in Web Editor NEWA rugged, minimal framework for composing JavaScript behavior in your markup.
Home Page: https://alpinejs.dev
License: MIT License
A rugged, minimal framework for composing JavaScript behavior in your markup.
Home Page: https://alpinejs.dev
License: MIT License
I am using livewire with alpinejs, which works smoothly for a dropdown menu inside each row of a livewire table, but after adding x-cloak directive, the livewire loaded pages includes the x-cloak directive and that is not been removed when new components are discovered by alpinejs.
Let us say I have a form:
<form>
<input type="text">
<button type="submit">Do something</button>
</form>
If I want to prevent the default submit, the following code does not work:
<form x-on:submit.prevent>
<input type="text">
<button type="submit">Do something</button>
</form>
And neither does:
<form x-on:submit="event.preventDefault();">
<input type="text">
<button type="submit">Do something</button>
</form>
Am I doing it incorrectly, or maybe it is not implemented yet (if so I would gladly try to contribute myself).
Hi,
i'm using alpinejs just to open and close the menu of the website with x-data
, x-show
and x-bind:style
to animate a few things.
Probably not directly related to this library but maybe someone can help me or maybe this will help someone else. Anyway It was working fine on local and then on the production server this error came out in the js console of the browser and of course the menu wasn't working.
EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "default-src 'self' http: https: data: blob: 'unsafe-inline'".
This was working in version smaller or equal to 1.5.0 and since 1.6.0 it's no longer working:
<div x-data="test(true)">
<button @click="toggle()">Press me</button>
<input type="text" x-bind:value="isSet" />
<input type="text" x-bind:value="getIsSet()" />
</div>
function test(status) {
return {
isSet: !!status,
toggle() {
this.isSet = !this.isSet
},
getIsSet() {
return this.isSet
}
}
}
Reading the isSet
value from the data-set is reactive and updated correct. But binding the return value from getIsSet()
, it's not updated โ even though is initialized correct. When running the same code with v1.5, it's working as expected.
You can test it in this fiddle.
I'm starting this issue for some conversations relating to custom directives / functionality for Alpine.
The related thread on Twitter can be found here:
https://twitter.com/assertchris/status/1214953080137158660?s=21
Take a look at the following examples:
Alpine.js - https://codepen.io/jreviews/pen/NWPMVMz
Vue.js - https://codepen.io/jreviews/pen/wvBjbNX
In Alpine.js, undeclared model object keys default to undefined, while in Vue.js they default to an empty string. Is it possible to have a similar behavior as Vue.js? It's ok to add the model keys to the object if there's a handful, but if there are dozens or hundreds it gets more complicated.
Hello,
It seems that after the transition to rollup and newer features, alpinejs is not working in IE11 with the current polyfills.
I am getting the error:
Expected ')'
at this line in utils.js
export function walkSkippingNestedComponents(el, callback, isRoot = true) {
I then tested on a branch after the transition to rollup (1.1.3) and got it to work by changing babel.config.js to the following
module.exports = {
presets: [
[
"@babel/preset-env",
{
targets: {
browsers: "> 0.5%, ie >= 11"
},
modules: false,
spec: true,
useBuiltIns: "usage",
forceAllTransforms: true,
corejs: {
version: 3,
proposals: false
}
}
]
]
};
this increases the build size, but gets it to work for testing purposes.
I then tested the same configuration on the current build (1.7) and I now get the following error
Uncaught (in promise) TypeError: Cannot create property for a non-extensible object
Seems like an error with the proxy polyfill when researching that error.
<script src="https://cdn.jsdelivr.net/npm/[email protected]/proxy.min.js"></script>
I also tested by adding Laravel Mix back and the same object error still occurs.
Wondering if anyone else has gotten a recent build to work with IE11?
Thanks.
I know IE11 is a pain, but considering it's still shipped with Windows 10 chances are it'll be around until 2023 or even 2025 :(
@calebporzio could you advise you don't just include the polyfills for IE11 in the core of alpine?
(to me this feels like the kind of "invisibility" alpine and livewire are all about)
Loving project-x!
I've been able to test out many of the things in stimulus and recreate them. One issue i'm not sure how to handle referencing repeating row elements.
Scenario: displaying the subtotal from a list of shopping cart items. I'd like to loop over a data-attribute value containing the subtotal of each line item.
Here's an example in VueJs
https://stackoverflow.com/questions/44063337/add-all-values-in-vuejs
In Stimulus, elements having the same name can be accessed through this.[name]Targets
and I would typically loop over the resulting array and sum the data attributes.
Perhaps $refs
can be expanded to access multiple items having the same name as an array?
Open to other ways as well. Thanks!
P.S. I wasn't sure the best place to ask this (github or twitter). A subtopic in the new livewire forum might be useful.
Looks very nice. Tried it immediately in the navigation section of my project. Works great already! But unfortunately I stumbled on some issues when trying to make a nested dropdown menu.
<div x-data="{ open: false }">
<button x-on:click="open = true">Open Dropdown</button>
<ul
class="hidden"
x-bind:class="{ 'hidden': ! open }"
x-on:click.away="open = false"
>
Dropdown Body
<div x-data="{ another: false }">
<button x-on:click="another = true">Open another Dropdown</button>
<ul
class="hidden"
x-bind:class="{ 'hidden': ! another }"
x-on:click.away="another = false"
>
Another dropdown Body
</ul>
</div>
</ul>
</div>
Opening the first dropdown works, but opening the second fails because of the error:
ReferenceError: another is not defined
First of all, this is awesome library!
I wanted to play with newly released transition feature but I could not make it work. I just copied the example code and modified it a bit.
You can see it here:
toggle x-if expression the console will receive
alpine.js:1 Uncaught TypeError: Cannot read property 'isSameNode' of null
at MutationObserver.observe.childList (alpine.js:1)
MutationObserver.observe.childList @ alpine.js:1
alpine.js:1 Uncaught TypeError: Cannot read property 'remove' of null
at alpine.js:1
at alpine.js:1
Is this a bug ? Or it's not supposed to using like this?
This might be something that goes a little against the project's philosophy, but I'll put it out there nonetheless.
I think it would be neat if we could (optionally) define a controller class/object/whatever for Alpine, that would bind to existing HTML in the same way Stimulus does.
I'm envisioning something like the following (basically a modified copy of Stimulus's conventions):
class MyController extends AlpineController {
data = { testInput: null, testCheckbox: null, submitted: false };
connected() { // lifecycle hooks
this.data;
this.$refs;
}
async submitForm($event) { // long-form event handlers
await fetch(...);
// do a million other things
this.data.submitted = true;
}
}
Alpine.controller('my-controller', MyController);
<div x-controller="my-controller">
<form @submit="submitForm"> <!-- all of the controller's methods and data in scope here -->
<input type="text" x-model="testInput">
<select x-model="testSelect">
...
</select>
<div x-show="submitted">We submitted the form!</div>
</form>
</div>
I'm doing something similar with an actual Stimulus + alpine combo, but there are some pain points (very verbose html, communication between a Stimulus controller and alpine).
I've looked through alpine's source, but I didn't grok it fully yet, so I'm unaware of any technical challenges that could arise, but would love your thoughts!
When using the dropdown component example from the docs, x-show="isOpen()"
doesn't update the DOM, even though the isOpen function does run. However, using x-show="show"
works correctly.
This works on previous versions, but not the latest one.
Example here https://codepen.io/jreviews/pen/povVRag
Hey again @calebporzio
I've watched this repository for a while now and noticed the growth of the entire thing, quite amazing!
Is there any reason why no CI has been integrated yet? With the amount of issues and especially PRs created, it might make sense to add a CI to automatically execute the already existing tests on new commits/PRs.
Personally, I use Travis CI (https://docs.travis-ci.com/) for such things, as it's free for open source projects and has a nice GitHub integration.
What do you think?
Regards
It would be great to be able to nest transitions. A common use case is a modal, where you want to fade-in the background before the content. This is an example in Vue.
Can you implement a support for templates and custom tags similar to this?
If we have a <button>click me</button>
, I want to add the disabled
attribute using a condition. I want something like <button x-toggle:disabled="myVar">click me</button>
. When myVar
is falsy, the attribute will not be rendered and viceversa. Instead of myVar
it can also be any javascript that return falsy or truthy values.
I'm currently getting this behaviour by using x-bind:class
but I was wondering if one could toggle attributes.
The @click event in the code below doesn't trigger after this.tasks
changes. It does work when the renderList
function runs on component initialization.
renderList() {
return this.tasks.map(task => {
return `
<div>
<span x-text="'${task}'"></span>
<button @click="removeTask('${task}')">Remove</button>
</div>
`
}).join('')
}
However, when adding the @click event to the parent 'div', then it works:
renderList() {
return this.tasks.map(task => {
return `
<div @click="removeTask('${task}')">
<span x-text="'${task}'"></span>
<button>Remove</button>
</div>
`
}).join('')
}
First of all, I love this. This declarative approach is why I fell in love with Vue.js in the first place, and the bigger and more robust Vue gets, the less I want to use it on small projects.
Okay so I'm trying to make buttons that hide themselves when you click them, and I must be doing something simple and dumb, but I can't get it to work. Here's my fiddle: https://jsfiddle.net/c6at2e7z/
Any ideas?
I took the "dropdown" example and tried to change it be class based
https://codepen.io/kevdotbadger/pen/ExaLExy
However, it's not working. Is changing the value in my classes object not allowed? Or does it not trigger a redraw?
I want to replace my data item with a object but it is not working.
Let's say I have the following HTML:
<body x-data="{task: {id: '', label: ''}}">
<section id="add-task-container">
<form x-on:submit.prevent>
<input type="text" x-model="task.label">
<button type="submit" x-on:click="$refs.listTasks.appendChild(taskToDOM(task, $refs.taskTemplate))">Add task</button>
</form>
</section>
<section id="list-tasks-container" x-ref="listTasks">
</section>
<template id="task-template" x-ref="taskTemplate">
<section class="task">
<input type="checkbox" class="task-check">
<p></p>
</section>
</template>
</body>
When trying, in my taskToDOM
function, to do something like this:
function taskToDOM(task, template) {
const div = template.content.querySelector('.task');
const node = document.importNode(div, true)
.....
}
I have got the following error:
Uncaught TypeError: Illegal invocation
I am not very used to JavaScript Proxies, so maybe I am doing something wrong?
Is there going to be a NPM package?
Hello,
first of all, thank you for this amazing piece of software!
I started playing around with and noticed that at least x-bind:class
doesn't watch nested keys. Code to reproduce:
<div x-data="{ foo: { bar: false }, baz: false }">
<!-- Doesn't work, the class doesn't get attached on click. -->
<p x-bind:class="{ 'works': foo.bar }" x-on:click="foo.bar = true">
Lorem ipsum dolor sit amet
</p>
<!-- Shows true when upper paragraph has been clicked. -->
<button x-on:click="console.log(foo.bar)">Check foo.bar</button>
<!-- Works, the class gets attached properly as soon as clicked. -->
<p x-bind:class="{ 'works': baz }" x-on:click="baz = true">
Lorem ipsum dolor sit amet
</p>
</div>
The button shows that the nested key is indeed being changed, but x-bind
doesn't seem to recognize this change.
As a workaround, one could just avoid nested keys or use functions to achieve this, but that doesn't seem very practical.
Any ideas?
Regards
As I understand it, the functions of the components must be global and located in the window
object. But then what about modules, iife and build tools like Laravel Mix? Tell me about usage and file structure, please.
Very nice framework! :-) Would be very nice to have "prevent" modifier on a click handler, that way it can be used on anchor-elements.
Example:
<a class="nav-link" href="#" x-bind:class="{ 'active': tab === 'view' }" x-on:click.prevent="tab = 'view'">View</a>
The modifiers you have in Livewire could serve as an example:
package.json
says Alpine.js is licensed under the MIT license, but there's no copy of the license in the repository. It's good practice to add a copy of the license to the repository to make this clear. This also lets GitHub detect it ๐
I'm have a component and then declaring nested components inside.
Once I use a data variable after a new nested component is declared, the variable doesn't work. Here's an example:
https://codepen.io/kjshah/pen/df81e5331e12140ac50ecb342dedfb61
<div x-data="values()">
<div class="font-semibold">This Doesn't Work</div>
<div x-data="{name: 'blue widget'}">
Name: <span x-text='name'></span>
</div>
<hr>
(total should show here)
Total: <span x-text="total"></span>
</div>
--------------------------------------------------
<div x-data="values()">
<div class="font-semibold">This Works</div>
Total: <span x-text="total"></span>
<div x-data="{name: 'blue widget'}">
Name: <span x-text='name'></span>
</div>
</div>
<script>
function values() {
return {
total: 1,
}
}
</script>
I'm using livewire and triggering an event that I'm trying to listen to in alpine. What's the best way to do this?
You get to keep your DOM, and sprinkle in behavior as you see fit
This project reminds me of KnockoutJs and StimulusJs (both which I'm a big fan). So I got curious to know a little bit more about the motivations behind it.
For someone like me, that likes the "traditional" approach of server-side rendering and progressive enhancement instead of javascript-centric applications is very interesting to see other frameworks providing this kind of experience to kinda "fill jquery's shoes".
Can I assume that this project relates to both ko and stimulus in regards of not trying to take control of the whole app and instead is meant to be used with a server-side rendering approach (or something like that)? And if so, what are the main differences from those aforementioned frameworks?
PS: Also, it seems that there's some hint of integration with turbolinks and wanted to ask if there are plans to integrate with unpoly as well.
I tried to create a simple TODO app and got my browser freezing.
[Violation] 'setTimeout' handler took ms
Please have a look here: https://codesandbox.io/s/priceless-hofstadter-ijk3t
Seeing if it would be possible for x-on
to listen to a custom event and pass the event to the expression function.
In the example below, I'm trying to pass data between components.
https://codepen.io/kjshah/pen/fe0ecb50b49d61a0eb55eaeb9c3bf7d2?editors=1011
It would be great if the following example could work, with cart-quantity-updated
being the custom event (listened to) and updateTotal(event)
being called when the event occurs.
<span x-text="total" x-on:cart-quantity-updated="updateTotal(event)"></span>
Are x-else
and/or x-unless
planned? Would be great to have them! Let me know if you want some help on these, happy to pair up or submit a PR :)
Hi @calebporzio,
thanks for the amazing work so far. I was having a go with alpinejs and I noticed that, when there are nested components, the internal component cannot access the scope of the external one.
For example,
<html>
<head>
<script src="https://cdn.jsdelivr.net/gh/alpinejs/[email protected]/dist/alpine.js" defer></script>
</head>
<body>
<div x-data="{ foo: 'bar', foo2: 'BAR' }">
<span x-text="foo"></span>
<div x-data="{ foo: 'bob' }">
<span id="s1" x-text="foo"></span>
<span id="s2" x-text="foo2"></span>
</div>
</div>
</body>
</html>
I would expect span#s2
to display 'BAR' or, in alternative, i would expect to be able to reference foo2 in the internal data structure.
I'm happy to work on a PR for this but I just wanted to check with you first in case this behaviour is expected and you do not want components to access external scopes.
Thanks,
Simone
Great project!
Probably the Readme.md#Use
section needs a .hidden
style to run, which I found in the index.html
file.
<style>
.hidden { display: none; }
</style>
Besides the index.html
won't work automaticly.
Well done, you guys! I'm giving up all these Vue, React and Stimulus ) will keep an eye out!
Does Alpine lifecycle methods, like stimulus connect/disconnect?
Hello,
I am trying to load alpine from webpack (laravel mix) given the instructions
import Alpine from 'alpinejs'
Alpine.start()
on my page, if i use this code
<div x-data="{}">
<div x-on:click="console.log('hello')">Click here</div>
</div>
i see 2 executions in my console log
This doesn't happen if I load alpine with the script tag outside of webpack.
Also, trying to organize alpine components in webpack, and wondering if there were any best practices.
I got it to work by assigning custom functions to the window object. not a problem, just want to make sure this is the proper way.
app.js
import * as product from './alpine/product'
window.product = product;
alpine/product.js
export function add() {
return {
name: 'blue widget',
}
and then declaring as follows
index.html
<div x-data="product.add()">
<div x-text="name"></div>
</div>
Thanks!
<template x-if="open">
<div>this will be removed from dom</div>
<div>this will stay in dom</div>
</template>
If i cover them in a div it is works. Maybe this is must be documented.
I am trying to do the following
<div x-ref="something"></div>
addChild() {
var btn = document.createElement("BUTTON");
btn.innerHTML = "CLICK ME";
this.$refs.something.appendChild(btn);
}
and I get this
Uncaught TypeError: Cannot read property 'something' of undefined
at Proxy.addChild (test-file:96)
at Proxy.open (test-file:53)
at eval (eval at <anonymous> (project-x.min.js:1), <anonymous>:1:15)
at project-x.min.js:1
at t.value (project-x.min.js:1)
at t.value (project-x.min.js:1)
at HTMLInputElement.<anonymous> (project-x.min.js:1)
In this example; there is a slider (let's say flickity), we want to create a custom UI that will track the active slide. AlpineJS would be good to do this because we can minipulate the UI based on the active slide.
Let's say for example on each slide we have a UI that has the title of the slide, we can use <div @click="activeSlide = 1; activeTitle = 'Projects'">Projects</div>
Then we can use x-watch to watch the activeSlide and run a function when it changes, I'm unsure of the best implementation for this x-watch:activeSlide="function"
or x-watch="{ activeSlide: function }
so for example we could do x-watch="{ activeSlide: $el.select(value) }"
value would be the value of the variable. I know the syntax is completely wrong, but it's the best way I can think of demostrating my thinking.
I am working on a Project-X Date Picker. I can define a date object by defining a method that returns the date object
today() { return new Date() }
where I run into issue is when I want to create mutable properties for the day, month and year. I tried this two ways. First I trying defining date method that returns a object that has 3 child objects (day, month and year) with each one of those containing a a selected and current property. This does work but I cannot mutate the properties.
date() {
return {
day: {
current: this.today().getDate(),
selected: this.today().getDate()
},
month: {
current: this.today().getMonth(),
selected: this.today().getMonth()
},
year: {
current: this.today().getFullYear(),
selected: this.today().getFullYear()
},
}
},
selectDay() {
this.date().day.selected = 20;
console.log(this.date().day.selected) //logs current day (12) instead of 20
}
Secondly I defined properties for each (daySelected, dayCurrent for example) but it tells me that today() is not a method
today() { return new Date() },
dayCurrent: this.today().getDate(),
daySelected: this.today().getDate()
I'm not sure if there is something I am missing here or something in Project-X needs to change.
I get an "Unhandled promise rejection" when used with Internet Explorer 11.
Unhandled promise rejection TypeError: Object doesn't support property or method 'forEach'
It might be out of the scope of the project, but wondering of the usefulness to remove event listeners on disconnect?
If using with turbolinks, pjax or unpoly, it seems there's a chance for a memory leak with stranded event listeners.
And if project-x is used in a turbolinks type of environment, would it be helpful to have init(), connect() and disconnect() functions that can sit inside the x-data function?
Hi, how i can get $refs in function?
function behavior() {
console.log($refs) // <- ??? it's window object
return {
isShow: false,
handleMouseMove(e, { img }) {
$refs.img.style.transform = `translate3d(${e.pageX}px, ${e.pageY}px, 0)`
}
}
}
Is it possible to add to alpinejs the loop like vue v-for
<ul id="example-1">
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
Thanks
Looking at adding an event for when a dom element enters the current viewport.
This can be done in one of two ways,
load
, scroll
, & resize
The issue with InteractionObserver is that it does not support IE 11. The polyfill would most likely be several times the size of alpine altogether, even gzipped.
The issue with MutationObserver is that it requires a lot more code (more to maintain), and requires some sort of throttle (usually 100ms) to not thrash on every scroll pixel. You can see a couple of examples here and here.
We could do something like x-enter
/ x-exit
and we could implement the once
feature as a future expansion. I'm not overly picky on this, and am fine with whatever syntax @calebporzio would prefer.
Ideally, I'd like to see it work similar to x-on
where it, the JavaScript expression set as it's value is executed.
The correct answer here might be to not push this feature inside core.
I'm going to start thinking about this a little bit more this week. If anyone would like to take a stab at it, go for it. I'll probably get more serious about it sometime next week.
This feature is a blocker for me to entirely replace a custom JavaScript implementation, which I really would like to nuke into oblivion.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.