Coder Social home page Coder Social logo

livewire's Introduction

Livewire Logo

Total Downloads Latest Stable Version License

Introduction

Livewire is a full-stack framework for Laravel that allows you to build dynamic UI components without leaving PHP.

Official Documentation

You can read the official documentation on the Livewire website.

Contributing

Thank you for considering contributing to Livewire! You can read the contribution guide here.

Code of Conduct

In order to ensure that the Laravel community is welcoming to all, please review and abide by Laravel's Code of Conduct.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

License

Livewire is open-sourced software licensed under the MIT license.

livewire's People

Contributors

allcontributors[bot] avatar atholin avatar austenc avatar calebporzio avatar danharrin avatar danielcoulbourne avatar davidpiesse avatar defenestrator avatar driesvints avatar faustbrian avatar gdebrauwer avatar gehrisandro avatar iksaku avatar imliam avatar intellow avatar inxilpro avatar jasonlbeggs avatar jimmypuckett avatar joshhanley avatar lancepioch avatar luanfreitasdev avatar lucasromanojf avatar markjaquith avatar mattharcourt avatar nuernbergera avatar nunomaduro avatar perryvandermeer avatar philonl avatar taylorotwell avatar tillkruss avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

livewire's Issues

Quotes in strings lead to script errors

Describe the bug
The LiveWire script throws an error if you have certain quotes in your strings.

image

image

To Reproduce

Steps to reproduce the behavior:

  1. Insert the following string into a database column.

I THINK; or is it directed to?' said the Duchess, 'and that's the jury, in a rather offended tone, 'so I can't get out of his Normans--" How are you thinking of?' 'I beg your pardon!' said the King. 'Nearly two miles high,' added the Gryphon; and then at the Cat's head began fading away the time.

  1. Fetch the database column with a LiveWire component. I don’t know if you have to explicitly use it in the view though and assign it to an attribute so it gets serialized.

Expected behavior

The script shouldn’t throw an error and escape the string properly.

Screenshots

Desktop (please complete the following information):

  • OS: MacOS
  • Browser Microsoft Edge (Chromium)

Additional context

Looks like a potential security vulnerability that could be exploited. I don’t think it’s a mistake to have unescaped strings (seeded with Faker) in our tables. Would be interested in your opinion on it though.

Bound data is converted to array after render

Describe the bug
Livewire seems to convert bound data (collections, objects, Eloquent instances) into arrays after a render.

To Reproduce

  1. Create a livewire component and add a property public $user;.
  2. On mount: fetch a user and optionally log its class.
  3. Add an action that, when a button gets clicked, tries to fetch a related model via $this->user->relatedModel.

Expected behavior
An instance of the related model is fetched.

Actual behavior
An exception is thrown: Call to a member function relatedModel() on array.

Screenshots

image

Add component slots

Similarly to how Blade supports components with slots it would be nice if I could do something like:

@livewire(‘alert’)
	<strong>Whoops!</strong> Something went wrong!
@endlivewire

And of course support for named slots would be nice too. I think this would help by allowing components to be be reused. I am not sure how this would be implemented but I thought I'd create this issue to start some discussion around the idea.

All form validation errors are cleared after editing any input

Describe the bug
After submiting a form validated on backend which has errors, errors are displayed correctly. But, if we edit an input, all validation errors (of all fields) disappear.

To Reproduce

  1. Create a simple form, like this:
<div>
    <form wire:submit.prevent="postLogin">
        <div>
            <input type="email" placeholder="Email" wire:model="email"/>

            <div>
                @if($errors->has('email'))
                    <span>{{ $errors->first('email') }}</span>
                @endif
            </div>
        </div>
        <br/>
        <div>
            <input type="password" placeholder="Password" wire:model="password"/>

            <div>
                @if($errors->has('password'))
                    <span>{{ $errors->first('password') }}</span>
                @endif
            </div>
        </div>
        <br/>
        <input type="submit" wire:loading.attr="disabled" value="Submit"/>
    </form>
</div>
  1. The component's "postLogin" function should have a validation, like this:
public function postLogin()
{
    $this->validate([
        'email' => 'required|email',
        'password' => 'required'
    ]);
    //...
}
  1. Submit an empty form. The validation errors will appear
  2. Edit any field. All validation errors will disappear

Expected behavior
The validation messages should not disappear until next validation, or at least not disappear for all fields since only one of them is being edited

Desktop (please complete the following information):

  • OS: Linux Mint 18.3 MATE 64 bits
  • Browser: Chrome 75.0.3770.100 (64 bits)

Echo Event Listeners

For implementing Laravel Echo listeners we can use the current event system for listeners as is almost.

This tricky thing is naming them. We need to specify:

  • That it's echo (echo)
  • Channel Type (Public/Private/Presence/Notification/Whisper)
  • Channel Name (todos)
  • Event Name (either NewTodo or App\Events\NewTodo)
  • Method to fire (updateTodoList)

That's a lot for a key/value pair where the value is already the method name!

Some ideas for naming:

public $listeners = [
    'echo:todos,NewTodo' => 'updateTodoList', //public channel
    'echo-private:todos,NewTodo' => 'updateTodoList', //private channel
    'echo:public[todos,NewTodo]' => 'updateTodoList', // Use a : and []
    'echo|private:todos,NewTodo' => 'updateTodoList', // Use a | {This could be the same as Option 1}
];

What are your thoughts?

Implementing this is not to hard (spinning up Echo listeners in JS when a component is initialised); as always its in the naming.

Originally I had Echo Listeners separated from regular listeners but that seems wrong now.

We will also have to accommodate dynamic channel names (such as users.{userId} ). My original idea was to have a method that can be called in the mount() -ing of a component that registers these

$this->attachEchoPublicListener('todos.user.' . $user->id , 'NewTodo', 'updateList');

wire:loading not removed in case of request error

Describe the bug
When a backend error happens, wire:loading is not reverted from the element.

To Reproduce

  1. Implement the counter example
  2. Put a wire:loading.attr="disabled" on each + and - button
  3. Throw an exception from increment (or decrement) function
  4. Click the button that throws the exception
  5. An exception popup will be shown and, after closing it, the buttons will remain disabled, and the user will need reload the page

Expected behavior
It's expected that wire:loading is reverted not only after request success, but after request errors too

Desktop (please complete the following information):

  • OS: Linux Mint 18.3 MATE 64 bits
  • Browser: Chrome 75.0.3770.100 (64 bits)

Multiple keydown trigger actions on single element

Describe the bug
Cannot bind multiple keydown trigger actions to single element.

To Reproduce
I am building a calculator for a presentation demo. On a div wrapping the calculator button, I am adding multiple keydown event for each number 0-9. To use the app from the keyboard rather than clicking on each button in the UI. The last keydown event listed seems to be the only trigger action registered.

Expected behavior
I would except the ability to add multiple keydown trigger actions based on each specified like Vue with the latest one winning if there was a conflict.

Desktop (please complete the following information):

  • OS: Windows 10 Build 17763.557
  • Browser Chrome
  • Version 75.0.3770.100

Additional context

// resources/views/livewire/calculator.blade.php
<?php 

<div class="flex w-1/2 mx-auto justify-center">
    <div class="flex flex-col break-words bg-white border border-2 rounded shadow-md mt-8"
         wire:keydown.enter="calculate"
         wire:keydown.1="setValue(1)"
         wire:keydown.2="setValue(2)"
         wire:keydown.3="setValue(3)"
         ...did not add the rest since it is not working...>

        <div class="flex">
            @component('_calculator.button', ['color' => 'red', 'value' => 'C'])@endcomponent
            <input disabled class="text-right appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 mx-2 my-2 leading-tight focus:outline-none focus:bg-white focus:border-gray-500" type="text" value="{{ $currentNumber }}" placeholder="LIVEWIRE">
        </div>
        <div class="flex">
            @component('_calculator.button', ['color' => 'blue', 'value' => 7])@endcomponent
            @component('_calculator.button', ['color' => 'blue', 'value' => 8])@endcomponent
            @component('_calculator.button', ['color' => 'blue', 'value' => 9])@endcomponent
            @component('_calculator.button', ['color' => 'orange', 'value' => '/'])@endcomponent
        </div>
        <div class="flex">
            @component('_calculator.button', ['color' => 'blue', 'value' => 4])@endcomponent
            @component('_calculator.button', ['color' => 'blue', 'value' => 5])@endcomponent
            @component('_calculator.button', ['color' => 'blue', 'value' => 6])@endcomponent
            @component('_calculator.button', ['color' => 'orange', 'value' => '*'])@endcomponent
        </div>
        <div class="flex">
            @component('_calculator.button', ['color' => 'blue', 'value' => 1])@endcomponent
            @component('_calculator.button', ['color' => 'blue', 'value' => 2])@endcomponent
            @component('_calculator.button', ['color' => 'blue', 'value' => 3])@endcomponent
            @component('_calculator.button', ['color' => 'orange', 'value' => '-'])@endcomponent
        </div>
        <div class="flex">
            @component('_calculator.button', ['color' => 'blue', 'value' => 0])@endcomponent
            @component('_calculator.button', ['color' => 'blue', 'value' => '.'])@endcomponent
            @component('_calculator.button', ['color' => 'blue', 'value' => '='])@endcomponent
            @component('_calculator.button', ['color' => 'orange', 'value' => '+'])@endcomponent
        </div>
    </div>
</div>
// resources/views/_calculator/button.blade.php
<? php
<button
        class="flex-1 m-2 bg-{{ $color }}-500 hover:bg-{{ $color }}-400 text-white font-bold py-2 px-4  border-b-4 border-{{ $color }}-700 hover:border-{{ $color }}-500 rounded"
        @if (is_numeric($value))
            wire:click="setValue({{ $value }})"
        @elseif ($value == ".")
            wire:click="setValue('.')"
        @elseif ($value === 'C')
            wire:click="setValue('C')"
        @elseif ($value === '=')
            wire:click="calculate()"
        @else
            wire:click="setOperator('{{ $value }}')"
        @endif>
        {{ $value }}
</button>
// app/Http/Livewire/Calculator
<?php

namespace App\Http\Livewire;

use Livewire\Component;

class Calculator extends Component
{
    #TODO History
    public $previousNumber;
    public $currentNumber;
    public $operator;

    public function render()
    {
        return view('livewire.calculator');
    }

    public function setValue($value)
    {
        if ($value === 'C') {
            $this->currentNumber = NULL;
            return;
        }
        $this->currentNumber = (string) $this->currentNumber . (string) $value;
    }

    public function setOperator($function)
    {
        $this->operator = $function;
        $this->previousNumber = $this->currentNumber;
        $this->currentNumber = NULL;
    }

    public function calculate() {
        switch ($this->operator) {
            case "*":
                $this->currentNumber = $this->currentNumber * $this->previousNumber;
                break;
            case "/":
                $this->currentNumber = $this->previousNumber / $this->currentNumber;
                break;
            case "+":
                $this->currentNumber = $this->currentNumber + $this->previousNumber;
                break;
            case "-":
                $this->currentNumber = $this->previousNumber - $this->currentNumber;
                break;
        }
        $this->operator = NULL;
        $this->previousNumber = NULL;
    }

}
// web.php
<?php
Route::livewire('/calculator', 'calculator');

Allow for computed properties (eg: getFooAttribute)

Currently we can use the Livewire API to get when a property is updated (via updatedFoo) and we can use that to set another property. Using this as a way to work with computed properties seems more like a side effect instead of a first-class computed property.

I propose that we utilize a similar convention as Laravel with getFooAttribute() as the getter, which returns the value of that computed property. I could see some issues on making sure it is not re-computed on every render, but perhaps someone knows a way to do this. Also, it would be nice if it was just set as a public property with no assignment, along with the accessor function. No extra config needed.

class Capitalization extends Component
{
    public $input = '';
    public $output;

    public function render()
    {
        return view('livewire.capitalization');
    }

    // current way
    public function updatedInput($input)
    {
        $this->ouput = strtoupper($input);
    }

    /// proposed way
    public function getOutputAttribute()
    {
        return strtoupper($this->input);
    }
}

@livewireAssets not injecting

When I visit the resulting HTML, it is rendered as @livewireAssets. I checked the source that is current from Composer and it does not include this as a blade directive. Only the livewire() directive is available.

Steps to reproduce the behavior:

  1. Create a new Laravel app
  2. Install Livewire
  3. Follow the quickstart from the docs
  4. JS not injected

How to use route model binding properly with Livewire?

Sorry if the answer to this is super obvious, I am newish to Laravel and obviously new to Livewire! I am just looking for some general advice.

Is the below how you would expect to create a simple method to update a record in the database? Am I supposed to use mount with route model binding in this way? I.e. inject the model instance, get the id, assign the id to a public property and then use this id within the update function to get the model instance again?

namespace App\Http\Livewire;

use Livewire\Component;
use App\Project;

class ProjectsEdit extends Component
{
    public $id;
    public $title;

    public function mount(Project $project)
    {
        $this->id = $project->id;
        $this->title = $project->title;
    }

    public function update()
    {
        $attributes = $this->validate([
            'title' => 'required|min:10',
        ]);

        Project::find($this->id)->update($attributes);

        $this->redirect('/home');
    }

    public function render()
    {
        return view('livewire.projects-edit');
    }
}

I am loving Livewire, amazing work by Caleb!

Livewire breaks with import Vue from 'vue'

Describe the bug
Apparently, Livewire breaks when I use import Vue from 'vue' instead of window.Vue = require('vue'). I took me a while to figure out, so I pushed a repo with the code that is failing.

app.js: https://github.com/luisdalmolin/livewire-bug-report/blob/master/resources/js/app.js
main view: https://github.com/luisdalmolin/livewire-bug-report/blob/master/resources/views/welcome.blade.php
livewire component class: https://github.com/luisdalmolin/livewire-bug-report/blob/master/app/Http/Livewire/ComponentCreate.php
livewire component view: https://github.com/luisdalmolin/livewire-bug-report/blob/master/resources/views/livewire/component-create.blade.php

I can try to figure this out next week if not solve until there.

To Reproduce
Steps to reproduce the behavior:

  1. Clone this repo https://github.com/luisdalmolin/livewire-bug-report
  2. composer install && yarn install && yarn run dev
  3. Open in browser
  4. Type anything on any of the fields and you will get the Uncaught (in promise) TypeError: Cannot read property 'getAttributeNames' of null error on console

Expected behavior
Not throw the Uncaught (in promise) TypeError: Cannot read property 'getAttributeNames' of null error.

Screenshots

Desktop (please complete the following information):

  • OS: MacOS
  • Browser: Chrome

Tests fail on master branch

Hey @calebporzio,

after cloning the master branch I ran the test suite and this is the output:

➜  livewire-pr git:(master) ✗ ./vendor/bin/phpunit --filter=DestroyCommandTest
PHPUnit 7.5.14 by Sebastian Bergmann and contributors.

FFE                                                                 3 / 3 (100%)

Time: 134 ms, Memory: 18.00 MB

There was 1 error:

1) Tests\DestroyCommandTest::component_is_removed_without_confirmation_if_forced
Mockery\Exception\InvalidCountException: Method askQuestion(<Closure===true>) from Mockery_1_Illuminate_Console_OutputStyle should be called
 exactly 1 times but called 0 times.

/Users/gjakic/Code/livewire-pr/vendor/mockery/mockery/library/Mockery/CountValidator/Exact.php:38
/Users/gjakic/Code/livewire-pr/vendor/mockery/mockery/library/Mockery/Expectation.php:310
/Users/gjakic/Code/livewire-pr/vendor/mockery/mockery/library/Mockery/ExpectationDirector.php:119
/Users/gjakic/Code/livewire-pr/vendor/mockery/mockery/library/Mockery/Container.php:303
/Users/gjakic/Code/livewire-pr/vendor/mockery/mockery/library/Mockery/Container.php:288
/Users/gjakic/Code/livewire-pr/vendor/mockery/mockery/library/Mockery.php:204
/Users/gjakic/Code/livewire-pr/vendor/orchestra/testbench-core/src/Concerns/Testing.php:106
/Users/gjakic/Code/livewire-pr/vendor/orchestra/testbench-core/src/TestCase.php:51

--

There were 2 failures:

1) Tests\DestroyCommandTest::component_is_removed_by_destroy_command
Unexpected question "Are you sure you want to delete the following files?" was asked.

/Users/gjakic/Code/livewire-pr/vendor/laravel/framework/src/Illuminate/Foundation/Testing/PendingCommand.php:139
/Users/gjakic/Code/livewire-pr/vendor/laravel/framework/src/Illuminate/Foundation/Testing/PendingCommand.php:220
/Users/gjakic/Code/livewire-pr/tests/DestroyCommandTest.php:19

2) Tests\DestroyCommandTest::component_is_not_removed_when_confirm_answer_is_no
Unexpected question "Are you sure you want to delete the following files?" was asked.

/Users/gjakic/Code/livewire-pr/vendor/laravel/framework/src/Illuminate/Foundation/Testing/PendingCommand.php:139
/Users/gjakic/Code/livewire-pr/vendor/laravel/framework/src/Illuminate/Foundation/Testing/PendingCommand.php:220
/Users/gjakic/Code/livewire-pr/tests/DestroyCommandTest.php:35

ERRORS!
Tests: 3, Assertions: 14, Errors: 1, Failures: 2.

After playing around it for a while, it seems the test fail as the path to the repository on your local machine is hardcoded inside the test and will, therefore, break on anyone else's machine (and even inside another folder on your own machine).

I have shortened the question to "Are you sure you want to delete the following files?" in my PR commit d057420, omitting the file names entirely, getting all three tests to pass.

I think a better solution would be (something I couldn't figure out how to do myself) for the file output to change from:

/Users/calebporzio/Documents/Code/sites/livewire/vendor/orchestra/testbench-core/src/Concerns/../../laravel/app/Http/Livewire/Foo.php
to
app/Http/Livewire/Foo.php

and from:
/Users/calebporzio/Documents/Code/sites/livewire/tests/views/livewire/foo.blade.php
to
views/livewire/foo.blade.php

You can reproduce the error by cloning the repository to any other folder on your machine and running the test suite.

Kind regards,
g

Latest batch of commits breaking hydrator

@calebporzio I have an issue with Livewire that seems to be a BC since the last 4 days of commits.
Looks to be related to the changes of renaming class to component...

Screenshot 2019-04-26 at 10 40 09

Happy to debug and help out on this :)

Other notes:

  • Completely re-downloaded the repo & rebuilt etc. made no difference.

Hook into Livewire component attribute from the JS script tags

Hey @calebporzio,

I believe it would be useful to be able to target a public Livewire component attribute from the script tags within that specific component.

Let me give you a for instance: I'm a big fan of Editor.js. So let's say I create a Livewire component Editor.

<?php

namespace App\Http\Livewire;

use Livewire\Component;
use App\Models\Blog;
use Illuminate\Support\Str;

class Editor extends Component
{
    public $title;
    public $content;

    public function addBlog(){
        Blog::create([
            'title' => $this->title,
            'slug' => Str::slug($this->title),
            'content' => $this->content
        ]);
    }

    public function render()
    {
        return view('livewire.editor');
    }
}

And in the view:

<div>
    <script>
        import EditorJS from '@editorjs/editorjs';
        const editor = new EditorJS();
    </script>

    <!-- Some HTML goes here -->

</div>

Ideally, I'd like to bind the value of const editor to public $content, so that I could take the formatted text from Editor.js, but handle validation and persistence in Livewire.

I'm opening this feature request and plan on submitting a PR on it if my JS knowledge is to par.

Kind regards,
g

Dirty Inputs being identified for 'created_at' and 'updated_at'

Describe the bug
When rendering a component from a message dirty inputs will be flagged for props that show their 'created_at' and 'updated_at' values. Most commonly seen in prop that is an an array of models.

To Reproduce
Steps to reproduce the behavior:

  1. Create a component that has a prop which is an array of models.
  2. Display the array (foreach)
  3. Refresh the prop (re-get)

Expected behavior
These should not be shown as dirty inputs as nothing has changed

Screenshots
Screenshot 2019-05-03 at 12 37 05

Desktop (please complete the following information):

  • OS: MacOS - latest
  • Browser: Chrome
  • Version: 73

Additional context
Feels like the HandlesDirtyInput is not handling the hashing / auto conversion of these values from datetime to string...

Question/Bug: Emit calls all javascript livewire registered listeners?

First of all: Livewire is an awesome product, I am happy that I was able to support you by buying some fantastic stickers and maybe I'll be able to contribute to this repository.

I hope I can explain my question well enough ;-)

In javascript, I registered a listener to a button somewhere on the page which is not in a livewire component. Then I registered some event listeners on livewire as describe like https://livewire-framework.com/docs/events/.

$(document).ready(function(){
    $('#openModalButton').on("click", () => {
        livewire.emit('modal.show');
    });

    livewire.on('modal.showing', () => {
        console.log('Event: modal.showing');
    });

    livewire.on('modal.hiding', () => {
        console.log('Event: modal.hiding');
    });
});

When executing the livewire.emit('modal.show'); I expect that none of the listeners will be called, so the console should be empty. But the result is that both/all of listeners are called. This also happens when calling $this->emit('modal.show'); from PHP code within a component.

And when I look at the javascript code I thing that my thoughts that every listener is called are confirmed:
https://github.com/calebporzio/livewire/blob/83c75eda96d1326e404499dc4e7eceadd31ebb20/src/js/Store.js#L27-L37

I believe this:

Object.keys(this.listeners).forEach(event => { 
    this.listeners[event].forEach(callback => callback(...params)) 
}) 

Should be like this:

if (this.listeners[event]) {
    this.listeners[event].forEach(callback => callback(...params))
}

I hope I am heading in the correct direction?

v3 Released in Packagist

Describe the bug
v3 was tagged back in May, even though the newest version is (currently) v0.1. Composer/Packagist now download this old version by default if you follow the steps in the documentation.

To Reproduce
Steps to reproduce the behavior:

  1. Install the package using Composer

Expected behavior
I expected to download the most recently released version.

Wrong imports in some package files

When running npm run watch, my terminal show 3 compilation errors:

These relative modules were not found:

* ../store in ./src/js/connection/index.js
* ./component in ./src/js/index.js
* ./store in ./src/js/index.js    

Is is correct?
When i change it to ../Store, ./Component and fix other directories with the same typo, the errors disappear.

Can i send a PR fixing it and also adding some alias for js files?

Setup CI linting

Just as a reminder.

Describe the solution you'd like
Something like StyleCI or similar. So there's no fuss around code formatting once the repo is public.

wire:fired="log" not working as expected

Describe the bug
Wire listener not detecting event <div wire:fired="log"></div>

Expected behavior
When clicking <button wire:click="fired">Fire</button> I would expect <div wire:fired="log"></div> to call the log() method in the component class.

Screenshots
class
html

Desktop (please complete the following information):

  • Browsers: Chrome and Firefox

wire:loading delay

Is your feature request related to a problem? Please describe.
I want to show loading indicator only when request takes more than x milliseconds (usually 300 ms).

Describe the solution you'd like
Just like CSS transitions, wire:loading.300ms support would be great.

Describe alternatives you've considered
There is always the option of using JS, but I believe that's beside the point of this library.

Additional context
Turbolinks has same behaviour. The loading indicator is shown only if request takes more than 500ms.

How to set a custom error with livewire?

Hello,

i am trying to set a custom filter on my mount method with livewire.

my approach

public function mount()
{
 $this->errors = new ViewErrorBag;
 $this->errors->add('customError', 'customMessage');
}

But if i do a dd() in my view, i don't see the error, this might be easy, but i am struggling to get this to work

NonPublicComponentMethodCall thrown on test described in documentation

Describe the bug
Hey @calebporzio,

I'm going through the documentation and I've stumbled on a problem in the Testing section as both tests fail as described. I fixed one bug by submitting a pull request to the docs, but I'm having some difficulties with the other.

To Reproduce
I copy pasted the example as given in the documentation and fixed the values to what they should be for the test to pass.

Screenshot 2019-06-29 at 23 41 51

Screenshot 2019-06-29 at 23 42 17

Expected behavior
The test should have passed. Instead, it throws a NonPublicComponentMethodCall.

Here's the Error trace.
Tests\Feature\ExampleTest::can_increment
Livewire\Exceptions\NonPublicComponentMethodCall.

Testing Components can generate false positives from `wire:data`

Describe the bug
Calling assertSee on Livewire::test(Component::class) can produce false positives when looking for text on the page that exists within the json payload in wire:data.

To Reproduce
Steps to reproduce the behavior:

  1. Create a component Post through the artisan command
  2. Set up the route Route::livewire('/posts', 'posts') that lists a set of Posts with a title and body (just some basic data). Do not set up the template to show any Posts.
  3. Write a test that checks that the first Post in the list is present on the page by checking the title appears using assertSee.
  4. The test will pass.

Expected behavior
The test should fail because the first Post's title shouldn't be listed on the page.

Screenshots
N/A

Desktop (please complete the following information):

  • OS: MacOS
  • Chrome
  • Latest of both

Additional Info
I believe that because the models are being json encoded in wire:data, it ends up providing a false-positive when checking the DOM for text coming from the model.

route:cache does not work

Describe the bug
Livewire route uses a closure.

To Reproduce
type php artisan route:cache on the command line

Additional context
php artisan route:cache
Route cache cleared!

LogicException : Unable to prepare route [livewire/livewire.js] for serialization. Uses Closure.

Support Bootstrap Select (Selectpicker) Library

When I create a select input, I can easliy set wire:model=myVariable and the data binding works as expected.

However, when I use the Selectpicker library the data binding does not work when I make a selection.

I don't know much about how this library works, but here are a few things that might get someone started in the right direction:

  • Making a selection with this library doesn't actually change the selected attribute on the HTML <option>. That might get someone pointed in the right direction.
  • Also, I have found when using this library with Vue and other frameworks, I will regularly call $('.selectpicker').refresh() any time a variable is changed (for example, a form is submitted and the value is changed via Vue instead of via user input)

How to listen for document events like scroll?

Hi! Loving Livewire so far! Great job!

I wanted to build an infinite scroll component. So when I start scrolling I need to push more items to a list. How do I hook up to window events like scroll?

I tried a renderless vue component that fires scroll event. But livewire seems to not listen for custom events. And another concern is how do I stop firing ajax requests as soon as I reach the end of list?

route:cache does not include the Livewire endpoint

Describe the bug
The Livewire endpoint at /livewire/message is not cached when running php artisan route:cache

To Reproduce

  • Follow the Quickstart guide to get the example app up and running.
  • Verify that the counter works.
  • Run php artisan route:cache
  • Clicking + or - now results in a 404 response

Expected behavior
The Livewire endpoint is included in the route cache, and the app still works.

Errors validations disappears when livewire make a call to 'messages' endpoint

Describe the bug
Errors validations disappears when livewire make a call to 'messages' endpoint

To Reproduce

Hi, I'm testing Livewire with a simple form with validations. The inputs are lazy and when I submit the form it show sthe validations, but when I click outside of the input, the 'errors' disappears (livewire make an ajax to 'messages' endpoint).

In this gist I have the component and the blade files
https://gist.github.com/rodrigore/6f9ee280c0464200231b9e6e92697b89

Expected behavior
Errors objects in the 'messages' endpoint

Screenshots
livewire

Desktop (please complete the following information):

  • OS: Mac OS
  • Browser: Chrome

Question/Bug: wire:loading across multiple different Livewire components

If I have multiple livewire components living on one page and one of the components start a roundtrip to the server because I clicked on an element that has wire:click="xxx" all directives that have wire:loading start their loading state while I expected only the wire:loading directives to be active within the current component.

I have created a test where the component looks like this:

<div>
    <div wire:loading.class="bg-primary">
        <div class="p-5 border border-danger text-center">
            <button
                class="btn btn-primary"
                wire:click="startLoading">Start loading</button>
        </div>
    </div>
</div>

Called function on component:

    public function startLoading()
    {
        sleep(1); // Because of wire:loading.class the background will be blue for x seconds
    }

This is the current situation:
loading_clip

Is it designed to work like this? If so, then there is a bug that the directives with wire:loading outside the current component do not reset.

But I think the best result should be that only within the current component the wire:loading directives should be triggered.

Expected:
expected

[Question?] Remove the storage folder from git.

Wouldn't it be smarter to add the storage folder to the gitignore?
At this moment there is a log file in there which I believe normally isn't added to git by most projects/people.

A clear and concise description of any alternative solutions or features you've considered.
If you use the storage folder for more stuff it might be worth telling a bit more about it in the docs. But at this point, I am almost certain that it isn't used for anything besides the log file.

Hope to hear more about this.

Best regards,
Wouter.

Confirm modifier / modal

Is your feature request related to a problem? Please describe.
Although it's not the prettiest dialog, the vanilla javascript confirm() function can be a simple and useful method of confirming dangerous actions. Surely the confirm modal could be built as its own livewire component and used, but it might be nice if livewire provided a modifier that gave users an easy way to confirm something.

I tried something like this:

<button onclick="confirm('Are you sure?')" wire:click="removeItem({{ $product->id }})">

Although the confirm dialog does open first, the wire:click runs next regardless of whether you click "Cancel" or "OK". This is what I'd expect to happen given how Livewire works...

Describe the solution you'd like
What if we were to provide a modifier on the click (or other actions?) that allowed users to spawn a js confirm dialog?

<button wire:click.confirm="'Are you sure?', removeItem({{ $product->id }})">
Perhaps there's a nicer way to format or pass in those params too. Maybe the dialog has some default text and the message becomes an optional second param? Totally open to other ideas as well!

Describe alternatives you've considered

  • A livewire confirm dialog that's built in to the framework
  • Rolling your own confirm dialog
  • Not confirming actions... I like to live dangerously

dd() / dump() handler similar to the error popup window

I'm loving Livewire so far, and it's possible that I'm missing something, but while using it I've found it hard to debug issues and follow data flow around my app.

The Error popup which displays the normal Laravel error page as a modal is great, however, I think that something similar which works with dump() and dd() would be great to help with any issues I run into in development.

I'm not totally sure how something like this could be implemented but I'm happy to look into creating a pull request if it's something which others would find useful

Use cases for Livewire? Can it be used for SSR-rendered apps with Laravel

Thanks for this repo @calebporzio!

This isn't a bug or feature request, but more of a question after having seen all the videos at https://calebporzio.com/a-bunch-of-cool-new-things-in-laravel-livewire/ and after going through the quickstart guide (Which works wonderfully well, btw).

  1. When is it appropriate to use Livewire over Vue? Obviously, Livewire makes multiple Ajax requests to the server, so it's heavy on the server.
  2. For SSR-rendered apps using Laravel + Nuxt.js, where does / can Livewire fit in? Can Livewire replace Nuxt and something like Inertiajs?
    Thoughts appreciated!

Allow "wire:ref" to be assigned to multiple targets

Is your feature request related to a problem? Please describe.
I have a page with many buttons, several of which (but not all of which) I would like to have trigger the same loading state. It appears that the relationship between wire:target and wire:ref is 1 to 1 and doesn't allow 1 to many.

Describe the solution you'd like
Perhaps just allowing a wire:ref to be assigned to multiple things at the same time?

Describe alternatives you've considered
As of now, at least as far as I can tell, the only solution is to create a specific loading state for each button.

Additional context
It might also be nice to allow a loading state to have multiple targets specified for wire:target.

v3 tag makes composer pull wrong version

Describe the bug
There's a v3 that's making composer require calebporzio/livewire gets the wrong version.

To Reproduce
Run composer require calebporzio/livewire on a new project.

Expected behavior
Get the 0.1 version. I guess the v3 tag should be deleted.

Screenshots

Data types in component state change after component is re-rendered.

Describe the bug
An array of objects in the component state changes to an array of keyed arrays when the DOM is re-rendered.

To Reproduce
Steps to reproduce the behavior:

  1. Create a component that has a property that holds and array of objects.
  2. Add an input to the component that will add an object to that array.
  3. Cause a re-render of the component and notice the object in the array is now a keyed array.

Expected behavior
Data types stored in the state of a component should stay the same data type.

Screenshots
Screen Shot 2019-07-27 at 2 14 48 PM
Screen Shot 2019-07-27 at 2 15 02 PM

Desktop (please complete the following information):

  • Browser chrome

Nested component vanishes into thin air :-)

Describe the bug
A list component renders a table and every row contains a nested component. After refreshing the parent component all the nested components are not in the DOM any more.

To Reproduce
See the two components attached to this issue

If the subcomponent has a root html element other than DIV

<p>
    <b>X</b>
</p>

The problem exists.

If we change the root element to DIV everyhthing seems to work OK.

Expected behavior
Of course we need the nested components rendered again ....

Desktop (please complete the following information):

  • OS: Windows
  • Browser Chrome
<?php

namespace App\Http\Livewire;

use Livewire\Component;

class BugList extends Component
{
    public $data;

    public function render()
    {
        $this->data = [
            ['id' => 1, 'animal' => 'Cat'],
            ['id' => 2, 'animal' => 'Dog'],
            ['id' => 3, 'animal' => 'Horse'],
            ['id' => 4, 'animal' => 'Fly'],
            ['id' => 5, 'animal' => 'Turtle'],
        ];

        return view('livewire.bug-list');
    }
}
<div>

    <button class="btn btn-primary mb-4" wire:click="$refresh">Refresh and see subcomponent vanish</button>

    <table class="table table-responsive-lg table-hover">

        <thead>
        <tr>
            <th>Id</th>
            <th>Animal</th>
            <th>Sub Component</th>
        </tr>
        </thead>

        <tbody>
        @foreach($data as $record)
            <tr>
                <td>
                    {{$record['id']}}
                </td>
                <td>
                    {{$record['animal']}}
                </td>
                <td>
                    @livewire('bug-sub', $record['id'], key($record['id']) )
                </td>
            </tr>
        @endforeach
        </tbody>

    </table>

</div>
<?php

namespace App\Http\Livewire;

use Livewire\Component;

class BugSub extends Component
{
    public function render()
    {
        return view('livewire.bug-sub');
    }

    public function mount($id){

    }
}

Bad template

<p>
    <b>X</b>
</p>

Good template

<div>
    <b>X</b>
</div>

Cannot Complete Action on Route with Middleware

I created the counter component and it's working fine on most pages, but it doesn't work on a page with the following middleware:

Route::get('/properties/{property_id}/edit/floorplans', [FloorplanController::class, 'showSetFloorplans'])->middleware('canManageProperty');

And the canManageProperty middleware is:

$property = Property::findorfail($request->route('property_id'));
if ($request->user()->canManageProperty($property)) {
    return $next($request);
} else {
    abort(403);
}

When I try to use the counter component (or any livewire click action, I just tested on the quickstart component to make sure it wasn't any problem with my code), I get a popup modal with a 404. For some reason it's hitting that middleware, not finding a "property_id" on the route, and the findorfail is failing.

If I remove this middleware the component works.

Root div without attributes does not correctly render

If a blade file on a component is used in the following way:

<div>
    <h1>Hello World!</h1>
</div>

The livewire component metadata is not correctly rendered on the root div.

<div>wire:id="kDvBcnw9SsV5gqiO8wWw" wire:name="counter" wire:children="[]" wire:initial-data="{&quot;count&quot;:0}" wire:checksum="$2y$10$B0CUP117p8XNF.rQAZk/p.gqpMsMPQtL5MvmOpS.T84DWrBEDn26K" wire:listening-for="[]" wire:middleware="eyJpdiI6ImgzZ3R1TVFzM3B6VmptdTc4R2ZUTGc9PSIsInZhbHVlIjoiWHMzcGwzSFptdG80cnFhNVRaVW5leGVlSUhcL1NDOENoSEo0c1M5elJJNHc9IiwibWFjIjoiMzkyODBhOTczMGQ4ZmQwYjk2NDRkMTdjOTZkYWU2YTJkZGI1YTRlNzU3MDE5NTA5MjllNjRhODlmZTNiYzdiZiJ9"     <h1>Hello World!</h1></div>

If attributes are used on the root div or an extra space is used everything works as expected. See next two examples

<div >
    <h1>Hello World!</h1>
</div>
<div style="color:red">
    <h1>Hello World!</h1>
</div>

Using Crome on Windows

Does not work with closure middleware

Describe the bug
In my base controller class App\Http\Controller i'm using closure middleware

    /**
     * Controller constructor.
     */
    public function __construct()
    {
        $this->middleware(function ($request, $next)
        {
            $this->user   = auth()->user();

            view()->share('connectedUser', $this->user);
            view()->share('moduleName', $this->moduleName);
            
            return $next($request);
        });
    }

This causes this error

Serialization of 'Closure' is not allowed at LivewireManager.php line 79

$middleware = encrypt($this->currentMiddlewareStack(), $serialize = true);

Cannot submit form to add new model

Describe the bug
I tried creating a new "model" using three inputs that are "wired" to their respective public variables in the livewire component class.
On the form I added "wire:submit="storeShop" which I would expect trigger the storeShop function that will create a new "Shop" model, but it didn't work.

I made sure to add the quickstart code to the my project in the same "Component" and "view" and those do work.

To Reproduce
Steps to reproduce the behavior:

  1. Go to https://gist.github.com/wotta/0c2efa1153052184186833695685b33b
  2. Add those files to a fresh project
  3. Create a Shop model with the fields that I added.
  4. Register the livewire route.
  5. Go to 'project.test/shops'
  6. Fill the form
  7. See that the page gets refreshed and the url is : project.test/shops?

Expected behavior
I expected that the form wouldn't refresh the page but submit the function with the data that was filled in the input fields.

Screenshots
https://monosnap.com/file/s8qQqgmz9PgBokAzFylPrj3bjBkNXp

Desktop (please complete the following information):

  • OS: MacOS 10.14.3 Beta (18D39a)
  • Vivaldi | 2.6.1566.49 (Stable channel) (64-bit)
  • Revision | d126d99a97ff62b9503aa8f44003e70741c4d90f
  • JavaScript | V8 7.5.288.30
  • Flash | 32.0.0.223 /Library/Internet Plug-Ins/PepperFlashPlayer/PepperFlashPlayer.plugin
  • User Agent | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.145 Safari/537.36 Vivaldi/2.6.1566.49

I hope somebody can help me.

Best regards,
Wouter.

Emit events from template with bound data

Is your feature request related to a problem? Please describe.
It would be great to be able to emit an event from a template with bound data from the component. This would make it faster when you need to pass a variable with an event than doing it from the component side (and obviously one less request)

Describe the solution you'd like
Would think it'd be something like <button wire:click="$emit('addToCart', {{ $id }})">

Describe alternatives you've considered
The workaround is to do <button wire:click="addToCart"> and then have $this->emit() from within the php component class.

Not sure if this is possible, but seems like it could be a useful shortcut and common pattern?

Rapid events get "stuck"

When rapid events are done in succession, it seems that something is held stationary until the next event happens. For example, if I have a counter (like in the docs) and I click twice very quickly, the count is incremented by one (not desired result). This is not just a matter of speed though because if I click increment one more time, the number goes up by two!

To Reproduce
Steps to reproduce the behavior:

  1. Create the simple counter as outlined in the docs
  2. Click the increment in rapid succession (counting the number of clicks)
  3. Verify that the number has not increased to the desired number
  4. Click the button once more
  5. Verify that it went up more than the desired amount

I expect this to not go up twice on the last click. If there is a lag in the rapid clicking, that is fine (for me, at least). But firing the next event(s) as a package deal could produce very bad results. It seems better to be conservative.

  • OS: Mac
  • Browser Chrome
  • Version 75.0.3770.142

Change event target value

When trying to add a wire:change binding on a select field, I wasn't seeing a clear way to get the resulting value it was changed to. Typically in JS you'd do something like event.target.value.

Here's how I'm doing the action in the template:

<select wire:change="updateQuantity({{ $product->id }})">

Describe the solution you'd like
It would be great to have access to the new value it was changed to, or perhaps even some data from the js event on the PHP (component class) side. Perhaps this would just be for change events / handlers?
The method signature for change handlers could be something like:

function updateQuantity($value) {
...
}

Describe alternatives you've considered
Emitting my own event any time an option within the select is clicked. Seems like it might work, but doesn't seem as intuitive as how you'd use a javascript change event.

Inputs lose focus if DOM **before** input is removed when Livewire updates

Describe the bug
When DOM nodes before an input are removed due to a Livewire update, the input your are typing in loses focus.

Here's a GIF showing the DOM change, but not be removed (the alert box), this works fine:

livewire-error-2 2019-07-26 21_05_05

Here's a GIF showing the DOM after the input be removed, this works fine:

livewire-error-3 2019-07-26 21_05_39

Here's a GIF showing the DOM before the input be removed, this causes the focus in the input to be lost:

livewire-error-1 2019-07-26 21_05_25

Expected behavior
Input is able to keep focus while DOM around it is removed/modified.

Desktop (please complete the following information):
OS: Mac OS
Browser: Brave

Global / Prop State Store

I have several components with each needing some access to one or another's data. In Vue you might use vue-x to store some global props that all could get and set. Currently I have to repeat myself in each component that needs the data.

I am thinking along the lines of the ability to add a trait to a LivewireComponent that provides access to some global store of data. This could then be accessed inside a component

public function mount()
{
    // Get a value from the store
    $current_page = $this->store->getCurrentPage();
    // Set a store value
    $this->store->setCurrentPage(420);
}

This could also fire off events to the event bus such as

$this->store->setCurrentPage(420);
// fires off 
$this->emit('current-page.updated')

--
To define a store there would need to be a class that implements the Store interface and is registered in a provider before any components

use Livewire\Store;

class LwStore implements Store {}

AppServiceProvider.php

public function boot()
{
    Livewire::store(LwStore::class);
    Livewire::component(TodoList::class);
}

A Store would be a stripped down class that has props, events and get / set methods. They can be overridden in PHP for custom functionality.

The Store/States data would be store in the PHP session so it is persisted and not needing to be constantly sent back and forth to the front end JS.

The alternative to this would usually be wrap everything in one big component - but that seems a worse option than using any components.

Also I know Store is an already used name internally so maybe State is better?

Happy to try and hack at it if you think its a good idea :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.