Livewire & Laravel 8: updating global components - laravel

I’m fairly new to the components & livewire game so I’m getting very confusing when I need to update a component value from other sources. Let me explain:
I’m using a default Laravel 8 installation with Livewire - no JetStream.
My navigation file (the default one that comes with the installation) has 3 individual components containing: total of points achieved, total of lives and remaining lives.
Loads like:
<x-points>0</x-points>
<x-lifes>0</x-lifes>
<x-remaining-lifes>0</x-remainung-lifes>
My question: how do I update any of those components when I execute actions from different sources like:
user answer a question (file Answer.php)
User clicks on an action at the footer of my application (let’s call this Regenerate.php)
User request tips so I need to subtract (Tips.php)

I would change your three main blade components for livewire componentes:
<livewire:points></livewire:points>
<livewire:lifes></livewire:lifes>
<livewire:remaining-lifes></livewire:remaining-lifes>
So for example, let's create the points and answer components.
// Points.php livewire component
public int points = 0;
public $listeners = ['loadUserPoints'];
public function render() { ... }
public function loadUserPoints()
{
$this->points = user()->points()->sum('total');
}
// points.blade.php livewire component
<div wire:init="loadUserPoints">{{ $points }}</div>
Now let's abstract the answer component.
// answer livewire component (very abstracted)
public function save()
{
user()->answers()->create($this->data);
// this will be listened by the points component
// that will run its query and update your frontend
$this->emit('loadUserPoints');
}
So livewire works mainly for events, you have to use it to pass data cross multiple components. To update your frontend as an SPA you're not gonna use blade components, you have to use livewire component or a lot of javascript to handle the DOM.

Related

Laravel Livewire pagination with bootstrap links not displaying

I'm using Laravel Livewire with bootstrap 4. I'm trying to use pagination but the links aren't displaying at the bottom of the table. I don't think the issue is in my blade file or in the livewire component itself, as I can see in the response that there's no pagination links() method available by doing this:
$x = User::paginate(5);
dd($x);
Which yields this result, and contains no reference to links
In my livewire component I'm including the trait: use WithPagination;, and I'm also including the protected $paginationTheme = 'bootstrap'; line as well.
At the bottom of my div just after the table element I have included:
{{ $users->links() }}
Everything I'm doing seems to be "by the book" in terms of what the docs say, but the links just don't display. It's limiting the number of rows on the page as well, just no links.
On your Livewire component:
use Livewire\WithPagination;
Inside class use the trait:
use WithPagination;
Then set the pagination theme:
protected $paginationTheme = 'bootstrap';

Fire an event from Laravel controller and listen on Livewire component

I'm trying to figure if i could emit an event from a Laravel regular controller and define a listener on a Livewire component. There's my journey so far:
I've generated the event:
php artisan make:event NewOrder
then, on the Controller method placeNewOrder i'm triggering the event like this:
event(new NewOrder())
On the Livewire component i define a varible $showNewOrderNotification and the listener:
public $showNewOrderNotification = false
protected $listeners = ['NewOrder' => 'notifyNewOrder'];
and setting the method notifyNewOrder
public function notifyNewOrder()
{
$this->showNewOrderNotification = true;
}
the livewire view is only showing an alert when the $showNewOrderNotification variable is true:
#if($showNewOrderNotification)
<div class="alert alert-danger text-uppercase">
New Orders !!!
</div>
#endif
This should be pretty straight forward but for some reason the listener is not getting the event.
I appreciate all the help.
user1 = order processor
user2 = customer
Scenario 1:
If user2 places a new order and you're trying to update user1's interface, you'll need to look into broadcasting to get your livewire component to pickup the event for user1.
https://laravel.com/docs/8.x/broadcasting
https://laravel-livewire.com/docs/2.x/laravel-echo
Scenario 2:
If user2 places a new order and you're trying to update user2's interface, it would probably be best to just convert the controller to an entire livewire component and avoid the controller all together. It can be done just storing session variables and checking for those variables using wire:init in your livewire blade view, but much easier to just do it all in a livewire component to begin with.

How to disable personal teams in Laravel / Jetstream when using Inertia?

I followed an article here:
https://devlan.io/disabling-personal-teams-in-laravel-8-and-jetstream-1fd083593e08
Basically to disable personal teams in Laravel / Jetstream. Now the article gives the example of how to achieve this using Livewire but I am using Inertia. The Livewire template needs this to be changed from this:
#if (Laravel\Jetstream\Jetstream::hasTeamFeatures()
To this:
#if (Laravel\Jetstream\Jetstream::hasTeamFeatures() && Auth::user()->isMemberOfATeam())
How would I achieve this in Inertia? I have had a look around the web, but because I am new to this stack I am completely stumped.
Thanks in advance.
This is a conditional made in Blade templates. Since Inertia doesn't work with Blade, instead it uses some JavaScript framework (Vue, React, Svelte), what you need to do is to run this conditional somewhere in the Laravel side (Controller, Middleware) and set a variable that you'll pass your client side component to conditionally render the teams html stuff.
If you want to have this flag available to all the pages in your app, you can do this through the HadleInertiaRequests middleware.
class HandleInertiaRequests extends Middleware
{
public function share(Request $request)
{
return array_merge(parent::share($request), [
'has_teams' => Laravel\Jetstream\Jetstream::hasTeamFeatures() && Auth::user()->isMemberOfATeam()
]);
}
}
Then, your component, you can use that variable to render the teams part or not (Example using Vue):
<div v-if="$page.props.has_teams">
<!-- Teams... -->
</div>

Using Laravel Inertia.js, Vue and Blade in parallel?

Is there a way to use Laravel Blade for one part of a multipage site (e-commerce), and Inertia/Vue for some specific pages (like the basket and the admin pages)? Not mixing the two on the same pages, as I see it done with other commentaries.
The first category is a load of pages that are merely static, need fast loading and robust SEO referencing (product pages and catalogues). The second do not need to be indexed, but need a lot of user interactions.
I have tried a few things with my first project, but I don’t seem to be able to call Laravel routes when Inertia is active. Plus it would not really make sense to load all Inertia and Vue in the Blade pages. So as a starter I guess I would need to load the Inertia + Vue code only on the Vue pages (admin and basket). And I guess there are a lot of other issues to take care of.
Or maybe scrap Inertia.js, and just load vanilla Vue.js on the Vue pages? But then that means loading the router and the datastore as well...
Many thanks for any idea on the best way to proceed!
E.
You can mix pages as you want:
1. For Inertia pages.
// View:
<inertia-link href="/dashboard">dashboard</inertia-link>
// Laravel controller:
public function index(Request $request)
{
return Inertia::render('Dashboard/Index', [
'data' => [
// ...
],
]);
}
2. Blade pages.
// View:
dashboard
// Laravel controller:
public function index(Request $request)
{
return view('dashboard.index', [
'data' => [
// ...
],
]);
}

Why creating a route with angular-fullstack creates a component?

Im using angular-fullstack newest version I think "generatorVersion": "3.7.5", and right now I created a route
yo angular-fullstack:controller products and it created the files:
products.controller.js
products.controller.spec.js
products.js
products.scss
and when I tried
yo angular-fullstack:controller product_new_view
inside the folder /client/app/products it created a new folder
/client/app/products/product_new_view
which I think is ok but the question is why the controller definition is not inside a component as in /client/app/products/products.controller.js
angular.module('meanshopApp')
.component('products', {
templateUrl: 'app/products/templates/products.html',
controller: ProductsComponent
})
})();
instead is just
angular.module('meanshopApp')
.controller('ProductNewViewCtrl', function ($scope) {
$scope.message = 'Hello';
});
does that mean that for every new view I need to create a route? cause I read https://docs.angularjs.org/guide/component and there it says
Components as route templates
Components are also useful as route templates (e.g. when using ngRoute). In a component-based application, every view is a component:
Im new to angular by the way

Resources