I have problem with nesting component when changing the children parent is refresh and its ok, but when I add same product in CartItem by using barcode the quantity dose not change in child component
this my parent Component including a table
parent.blade.php >>>
<table class="table mb-0">
<thead>
<tr>
<th scope="col">product</th>
<th>price</th>
<th>quantity</th>
</tr>
</thead>
<tbody>
#foreach ($cartItems as $item)
<tr>
<td>{{$item['name']}}</td>
<td>{{Cart::session(auth()->id())->get($item['id'])->getPriceSum()}}</td>
<td>
<livewire:child :item="$item" wire:key="$item['id']"/>
</td>
</tr>
#endforeach
</tbody>
</table>
and this id parent.php
class Parent extends Component
{
public $service = null;
public $cartItems = [];
protected $listeners = ['cartUpdated' => 'onCartUpdate'];
public function mount()
{
$this->cartItems = \Cart::session(auth()->id())->getContent()->toArray();
}
public function onCartUpdate()
{
$this->mount();
}
public function render()
{
$this->mount();
return view('livewire.parent');
}
}
the child component in <td> just have an input with livewire:model
<div>
<input type="number" wire:model="quantity" wire:change="updateCart"><span class="col-9"></span>
</div>
My Child.php
class Child extends Component
{
public $item;
public $quantity;
public function mount($item)
{
$this->item = $item;
$this->quantity = $item['quantity'];
}
public function updateCart()
{
\Cart::session(auth()->id())->update($this->item['id'], [
'quantity' => array(
'relative' => false,
'value' => $this->quantity,
),
]);
$this->emit('cartUpdated');
}
public function render()
{
return view('livewire.child');
}
}
I think this return to mount() method in child. can I updating quantity every time?
There is a way you can make child components reactive. Just use now() or random number as a key, as follows:
<livewire:child :item="$item" key="{{now()}}"/>
This my question in GitHub
It's also good to see this tricky way that helped me.
Instead of calling the onCartUpdate method. Try using $refresh in your $listeners:
protected $listeners = ['cartUpdated' => '$refresh'];
You're not utilizing data-bindings properly. You don't need to add wire:change, since you already have wire:model -- you can simply listen for changes to that property.
Even better, just use one property $item and access the quantity from that.
<div>
<input type="number" wire:model="item.quantity" /> <span class="col-9"></span>
</div>
Then use the "magic" method updatedItemQuantity() to listen for updates to the quantity attribute on the $item property.
class Child extends Component
{
public $item;
protected $rules = [
'item.quantity' => 'required|numeric|min:0',
];
public function mount($item)
{
$this->item = $item;
}
public function updatedItemQuantity($quantity)
{
\Cart::session(auth()->id())->update($this->item['id'], [
'quantity' => array(
'relative' => false,
'value' => $quantity,
),
]);
$this->emit('cartUpdated');
}
public function render()
{
return view('livewire.child');
}
}
Now in your parent, you can simply use the "magic" event $refresh,
class Parent extends Component
{
public $service = null;
public $cartItems = [];
protected $listeners = ['cartUpdated' => '$refresh'];
public function mount()
{
$this->cartItems = \Cart::session(auth()->id())->getContent()->toArray();
}
public function render()
{
return view('livewire.parent');
}
}
Related
I am using first time laravel livewire in my project. I am trying to create one simple filter option and this filter will trigger from a dropdown. My problem is when a dropdown value change its completely hide my component view.
I am not sure where i am making a mistake in this but i want to know the best way to resolve this.
my code is this Livewire component
<?php
namespace App\Http\Livewire\Frontend\Boat;
use App\Models\Product;
use Livewire\Component;
class Listing extends Component
{
public $filter_option;
// public $message;
public $product;
public function mount()
{
$this->product = Product::where([
'type_id' => 1,
'status' => 1,
])->orderBy('name', 'asc')->get();
}
public function filter_speed()
{
$this->product = Product::where([
'type_id' => 1,
'status' => 1,
])->orderBy('name', 'asc')->get();
}
public function render()
{
return view('livewire.frontend.boat.listing');
}
}
My blade is
<select wire:model="filter_option" class="form-control" wire:change='filter'>
<option value="#">Filter</option>
<option value="speed">Speed</option>
</select>
//or
<button wire:click='filter_speed'>Filter by speed</button> <!-- Simple button click -->
In my opinion in your case its not necessary to use Query on mount().
But If in case of Filter u can use this method:
<?php
// Livewire
namespace App\Http\Livewire\Frontend\Boat;
use App\Models\Product;
use App\View\Components\comment;
use Livewire\Component;
class Listing extends Component
{
public $filter_option;
// public $message;
// public $product;
public $orderBy = 'id';
public $orderType = 'desc';
public function filter_speed()
{
$this->orderBy = 'speed';
// $this->emit('filter_speed');
}
public function render()
{
$product = Product::where([
'type_id' => 1,
'status' => 1,
])
->orderBy($this->orderBy, $this->orderType)
->get();
return view('livewire.frontend.boat.listing', compact('product'));
}
}
<button wire:click.prevent='filter_speed'>Filter by speed</button>
Instant of making many Query make one with custom variable
In view file is displayed players for each team in match.
here is code in view:
#foreach($match->homeTeam->players as $player)
<tr>
<th scope="row">{{$player->id}}</th>
<td class = "col-md-6" name = "fact[player]" value = "{{$player->id}}">{{$player->name}} {{$player->surname}}</td>
<td align="center" class= "col-md-2"><input class="form-check-input" type="checkbox" id="gridCheck"></td>
<td class = "col-md-2"><input id="minutes" type="integer" class="form-control" name="fact[minutes]"></td>
<td class = "col-md-2"><input id="goals" type="integer" class="form-control" name="fact[goals]"></td>
</tr>
#endforeach
So i need to store them in Match_facts table.
How to insert all in one query?
Match model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\Team;
class Match extends Model
{
protected $fillable = ['round', 'league_id', 'home_team_id', 'away_team_id', 'match_date'];
public function leagues() {
return $this->belongsTo('App\League');
}
public function homeTeam() {
return $this->belongsTo('App\Team', 'home_team_id');
}
public function awayTeam() {
return $this->belongsTo('App\Team', 'away_team_id');
}
}
Player model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Player extends Model
{
public function team() {
return $this->belongsTo('App\Team');
}
}
In view addResult i have displayed Match(home_team and away_team)
and players of each team.
So i want to store match facts in table (match_facts) for each player of the team
Schema::create('match_facts', function (Blueprint $table) {
$table->id();
$table->uuid('match_id');
$table->uuid('player_id');
$table->integer('minutes')->nullable();
$table->integer('goals')->nullable();
$table->timestamps();
});
Founded solution:
$home_team_players=$match->homeTeam->players;
$away_team_players=$match->awayTeam->players;
$match_players = $home_team_players->merge($away_team_players);
foreach ( $match_players as $k => $p ) {
$data[] = [
'match_id' => $match->id,
'player_id' => $p->id,
'minutes' => $request['minutes'][$k],
'goals' => $request['goals'][$k]
];
}
Match_fact::insert( $data );
return view('admin.matches.index')->with('success','ADDED SUCCESSFULLY .');
I have a boolean field when I try to update from false to true for a single or multiple records it works but when trying to update it back to false it works for the first record only and can not repeat to update multiple records at the same time without refreshing the page 1- my vue component that handles the request is like this:
<template>
<div v-for="(channel, index) in items" :key="channel.id">
<a href="" #click.prevent="toggleVisibility(channel)">
<i v-if="channel.active" class="fas fa-stop default-stop" data-toggle="tooltip" title="Stop Channel">
</i>
<i v-else class="fas fa-play" data-toggle="tooltip" title="Start Channel"></i>
</a>
</div>
</template>
export default {
name: "Channels",
props: ['allChannels'],
data() {
return {
items: this.allChannels
}
},
methods: {
toggleVisibility(channel) {
axios[channel.active ? 'delete' : 'post'](`/visible-channels/${channel.name}`);
}
}
}
and my routes:
Route::post('/visible-channels/{channel}', 'ChannelsController#activate');
Route::delete('/visible-channels/{channel}', 'ChannelsController#deactivate');
my controller:
public function activate(Channel $channel, Request $request)
{
if ($request->method() == 'POST') {
$channel->update(['active' => true]);
}
return back();
}
public function deactivate(Channel $channel, Request $request)
{
if ($request->method() == 'DELETE') {
$channel->update(['active' => false]);
}
}
The model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Cache;
class Channel extends Model
{
protected $guarded = [];
protected $casts = [
'active' => 'boolean',
];
protected static function boot()
{
parent::boot();
static::updating(function () {
return Cache::forget('activeChannels');
});
}
public function getRouteKeyName()
{
return 'name';
}
}
Since laravel stores boolean as 1 and 0 in database, You should probably set active property to boolean in your model
That's because laravel treat false as string so when you set active to false it compares it as 'false' == true which is true so it stores 1 in database.
class Channel extends Model
{
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'active' => 'boolean',
];
}
I figured it out just change in the boot function to wait until the update finish
static::updated(function () {
return Cache::forget('activeChannels');
});
I have a problem with some of my routes in Laravel. this my code in web.php file:
Route::group(['namespace' => 'Admin', 'middleware' => ['auth:web']], function () {
Route::get('/admin/audio/create/{audio?}', 'AdminAudioController#create')->name('admin.audioCreate');
Route::get('/admin/article/create/{article?}', 'AdminArticleController#create')->name('admin.articleCreate');
}
and this my link in blade
<i class="fa fa-edit"></i>
<i class="fa fa-edit"></i>
and this are my Controllers:
AdminAudioController
<?php
namespace App\Http\Controllers\Admin;
use App\Article;
use App\Http\Requests\ArticleRequest;
class AdminArticleController extends AdminController
{
public function index()
{
$articleList = Article::where('removed', false)->latest()->paginate(10);
return view('admin.article.archive', compact('articleList'));
}
public function create(Article $article = null)
{
return view('admin.article.create', compact('article'));
}
}
AdminArticleController
<?php
namespace App\Http\Controllers\Admin;
use App\Article;
use App\Http\Requests\ArticleRequest;
class AdminArticleController extends AdminController
{
public function index()
{
$articleList = Article::where('removed', false)->latest()->paginate(10);
return view('admin.article.archive', compact('articleList'));
}
public function create(Article $article = null)
{
return view('admin.article.create', compact('article'));
}
}
but my second link with name "admin.articleCreate" doesn't work and get "404 not found" what should I do?
and this is my article model
class Article extends Model
{
protected $primaryKey = 'articleId';
use Sluggable;
protected $fillable = [
'title',
'subTitle1', 'subTitle2',
'image',
'description',
'body',
'enable',
];
protected $casts = [
'image' => 'array'
];
/**
* Return the sluggable configuration array for this model.
*
* #return array
*/
public function sluggable(): array
{
return [
'slug' => [
'source' => 'title'
]
];
}
public function getRouteKeyName()
{
return 'slug';
}
}
When you call the method create(Article $article = null) on your controller, Laravel uses Model Binding to resolve your model and the model binding uses the method you have added to your model
public function getRouteKeyName()
{
return 'slug'; // by default it will be $primaryKey which is 'id'
}
In short, Laravel will try to use slug to find your model while your giving him articleId
So to fix it you have few options
Using the slug in the URL (the one I would recommend)
// blade.php
<i class="fa fa-edit"></i>
Using the primary articleId in the URL
// blade.php
<i class="fa fa-edit"></i>
// Article.php.php
public function getRouteKeyName()
{
return 'articleId';
}
Using a query
// blade.php
<i class="fa fa-edit"></i>
//Controller.php
public function create($article = null)
{
$article = Article::where('YOUR_FIELD', $article)->firstOrFail();
return view('admin.article.create', compact('article'));
}
you have code
return view('admin.article.create', compact('$article'));
but need
return view('admin.article.create', compact('article'));
I can see you have mentioned $article in side compact.
Can you please check once, I think the create method should look like this:
public function create(Article $article = null)
{
return view('admin.article.create', compact('article'));
}
I'm new in Laravel and stuck with a noob problem. I have 3 tables, users, items, item_images. When i post a item i save the images to item_images with the item_id and the other input data to the items table. now, how to get the first of x images for the item in my foreach loop?
This is my view
#foreach ($items as $item)
<div class="item">
<div class="item-image">
<img src="/uploads/{{ $item->image }}"/>
</div>
{{ $item->title }}
{{ $item->type }}
{{ $item->label }}
</div>
#endforeach
This is the ItemImages Controller
<? class ItemImages extends Eloquent {
protected $fillable = array(
'item_id',
'image'
);
protected $table = 'item_images';
public function item() {
return $this->belongsTo('Item');
}
}
The Item Controller
<? class Item extends Eloquent {
protected $fillable = array(
'user_id',
'type',
'title',
'label'
);
protected $table = 'items';
public function item() {
return $this->hasMany('ItemImages');
}
}
And the home controller
<?php class HomeController extends BaseController {
public function home() {
$items = Item::all();
$images = ItemImages::all();
$users = User::orderByRaw("RAND()")->take(2)->get();
return View::make('home', array(
'items' => $items,
'users' => $users,
'images' => $images
));
}
}
thanks in advance.
Looks like you have not defined relationships. I believe doing that will make the answer much simpler than the following:
<img src="/uploads/{{
$images->filter(function($image) use( $item ) {
return $image->item_id == $item->id;
})->values()->image
}}"/>