Livewire - updated hook without render of complex data - laravel

I'm using Livewire for data table with a complex database query with pagination. In table are also checkboxes and after check/uncheck is quite annoying to wait for render method with fetching all necessary data witch are required only for first component load.
I know I can use defer flag for checkboxes but I need also do some action when is any checkbox checked/unchecked so I cannot use that flag. So my question is if I can use updated hook method for checkbox without loading data in render.
Here is my example code:
class LivewireComponent extends Component
{
public $arrayOfCheckboxes = [];
public function render(SomeService $service)
{
$data = $service->fetchComplexData->paginate();
return view('livewire.some-component', ['data' => $data]);
}
public function updatedArrayOfCheckboxes($value)
{
// if value is true/false then do some action
// do I really need to call render and fetch complex data again?
}
}
// livewire.some-component.blade.php
<div>
<table>
#foreach($data as $row)
<input type="checkbox" wire:model="arrayOfCheckboxes" value="{{ $row->someValue }}">
#endforeach
</table>
</div>

Related

Livewire Select2 Dynamic not updating public view

I am using a select2 component with wire:ignore and i want to update the select2 value dynamically after clicking a button. I set up this functionality with events and events work fine, so does the variable gets initialized as well. I am failing to update this public view of this select2.
my blade
<select class="select2-example form-control" id="subjects" wire:model.lazy="subjects" name="subjects">
</select>
#push('scripts')
<script>
$('#subjects').select2({
maximumSelectionLength: 1,
minimumInputLength:2,
tags: false,
placeholder: 'Enter Subject(s)',
.... // this all works great
});
$('#subjects').on('change', function (e) {
let data = $(this).val();
#this.set('subjects', data);
});
// my event listener and it is working as well
Livewire.on('editSubject', subject => {
console.log(subject);
#this.set('subjects', subject);
$('#subjects').val(subject);
$('#subjects').trigger('change'); //the public view doesn't get updated
})
</script>
#endpush
I so far tried with browser dispatch event as well. Nothing works. What would be the workaround for this? Any help is greatly appreciated.
in blade
<div class="col d-flex display-inline-block">
<label for="contact_devices">{{ __('Select Device') }}</label>
<select id="contact_devices" wire:model="selectedDevice" class="form-control contact_devices_multiple" multiple="multiple" data-placeholder="{{ __('Select') }}">
#foreach($devices as $device)
<option value="{{ $device->id }}">{{ $device->alias }}</option>
#endforeach
</select>
</div>
<script>
window.loadContactDeviceSelect2 = () => {
$('.contact_devices_multiple').select2({
// any other option
}).on('change',function () {
livewire.emitTo('tenant.contact-component','devicesSelect',$(this).val());
});
}
loadContactDeviceSelect2();
window.livewire.on('loadContactDeviceSelect2',()=>{
loadContactDeviceSelect2();
});
</script>
in component
public $selectedDevice;
protected $listeners = [
'devicesSelect'
];
public function devicesSelect($data)
{
dd($data);
$this->selectedDevice = $data;
}
public function hydrate()
{
$this->emit('loadContactDeviceSelect2');
}
Note: If some face the problem of real time validaiton while implementing the above mentioned solution as i have commented in the accepted answer above.
My Comments:
hey, I have implemented your solution its working great but there is
one problem, here is the scenario, I submit empty form and all the
validations gets triggered, when i start filling the form the error
starts to disappear but as soon as i change the select2 the validation
part $this-update($key, $value) function does not work. Can you please
tell me why real time validation is not working ? and how to fix it
please. thankyou – Wcan
Solution:
Use syncInput() function instead of assigning the value to country property. updated lifecycle hook will be trigerred automatically.
public function setCountry($countryValue)
{
// $this->country = $countryValue;
$this->syncInput('country', $countryValue);
}

Laravel Calling Multiple Controllers from Form Submit

I want to submit a form, and once that submit button is pressed, I run a bit of code.
During this 'bit of code', part of its job will be to create a student, and also create a lunch order. (information pulled from the form).
From what I've been reading, I should be aiming to use CRUD, which would mean I should have a Student Controller and a LunchOrderController.
I want to call the #store method in each controller.
If I was doing it the 'bad' way, the form would have [action="/students" method=POST]. And in that route, it would then call /lunchorder/ POST, and then return to a page (redirect('students')).
However, as above, I don't want to call a controller from a controller. Therefore, the initial [action="/students" method=POST] should be something else instead, and this new entity will then call the StudentController, then call the LunchOrderController, then redirect('students').
But, I don't know what this new entity is, or should be, or how to link to it.
It is just a new route to a new controller which is ok to call other controllers from?
Or is there some other place I should be sending the form data to (maybe models?), to them call the controller? Or am I way off base and need to take some steps back?
I'm fairly new to Laravel but am wanting to use best practice as much as possible. All my reading of other posts don't seem to explain it enough to get my head around how its meant to work.
Edit: Some code to give an idea of what I'm getting at.
Student_edit.blade.php
<form action="/student" method="POST">
{{ csrf_field() }}
<label>First Name</label><input name="firstname" value="">
<label>Last Name</label><input name="lastname" value="">
<label>Lunch Order</label>
<select name="lunch_value" id="">
<option value="1" >Meat Pie</option>
<option value="2" >Sandwich</option>
<option value="3" >Salad</option>
<option value="4" >Pizza</option>
</select>
<input type="submit" value="Submit" class="btn btn-primary btn-lg">
</form>
web.php
Route::resource('/students', 'StudentController');
Route::resource('/lunchorder', 'LunchOrderController');
Studentcontroller
public function store(Request $request)
{
Student::create(request(['firstname', 'lastname']));
LunchOrderController::store($request, $student_id); //<- This isn't the correct syntax
return redirect('/students');
}
LunchOrderController
public function store(Request $request, $student_id)
{
LunchOrder::create(array_merge(request(['lunch_value']), ['student_id' => $student_id]));
return null;
}
Personally I would create a 'Logic' Directory as: app/Logic. Some people prefer Repositories etc, but this is my preference.
For your specific requirement I'd create the following file:
app/Logic/StudentLogic.php
StudentLogic
<?php
namespace App\Logic\StudentLogic;
use App\Student;
use App\LunchOrder;
class StudentLogic
{
public function handleStudentLunch(Request $request): bool
{
$student = Student::create(request(['firstname', 'lastname']));
if(is_null($student)) {
return false;
}
LunchOrder::create(array_merge(request(['lunch_value']), ['student_id' => $student->id]));
return true;
}
}
StudentController
public function store(Request $request)
{
$logic = new StudentLogic();
$valid = $logic->handleStudentLunch($request);
if($valid) {
return redirect('/students');
}
abort(404, 'Student Not Found');
}
ASSUMPTIONS
Student is stored under App/Student & LunchOrder is stored under App\LunchOrder
You will also need to use App\Logic\StudentLogic in StudentController
The reason I'd split this out into a Logic file is because I do not like 'heavy' controllers. Also, I'm not entirely sure what you're trying to acomplish here, but creating a student on the same request you create a LunchOrder seems like you're asking for trouble

How to send the values of checked items in a dynamic list from a database displayed in a view to controller?

How to send the values of checked items in a dynamic list from a database displayed in a view to controller ?
A concrete solution depends on your data, but if you are talking about a list of checkboxes, you can give them a common name in array notation:
<form type="post" action="...">
#foreach($elements as $elem)
<input type="checkbox" name="my_input[{{ $elem->id }}]" value="1">
#endforeach
</form>
On the server-side, you can then query the data like this:
use Illuminate\Http\Request;
class MyController
{
public function postData(Request $request)
{
$myInput = (array) $request->get('my_input', []);
// ... remaining logic
}
}
The line $myInput = (array) $request->get('my_input', []); will read the POST variable my_input as array and, if no such post variable is given, an empty array will be returned. In other words, $myInput will always be an array, where the key is $elem->id and the value '1' as defined by value="1".

Preventing resubmission of form data Laravel 5.5

I am working on Laravel 5.5 framework.
I have a form home page like this:
<form action = "/result" method = "post">
<input type = "hidden" name = "_token" value = "<?php echo csrf_token() ?>">
<table>
<tr>
<td>Name or Nickname</td>
<td><input type = "text" name = "name_nickname" autofocus /></td>
</tr>
<tr>
<input type = "submit" value = "LuckyNumber" />
</td>
</tr>
</table>
The controller looks like this:
class SixGetController extends Controller
{
public function luckyNumber(Request $request){
$nameNickname = $request->input('name_nickname');
$luckyNumber = rand (1,10);
DB::table('visitor')->insert(
['name_nickname' => $nameNickname, 'luckyNumber' => $luckyNumber]);
return view('result', ['nameNickname' => $nameNickname, 'luckyNumber' =>
$luckyNumber]);
}
The result page looks like this:
<p><?php echo $nameNickname; ?> </p>
<p>Your lucky number is <?=$result?> .</p>
If the user presses the reload F5 button the scrip will reroll the random number generator and resubmit the data with the rerolled number. I've read about the PGR pattern which i dont know how to use and something about manipulating history which i dont understand either. Can somebody point out what kind of code do i put somewhere to prevent the reroll and the resubmission. Thanks.
For laravel implementation, you can use Session Flash Data.
Sometimes you may wish to store items in the session only for the next
request. You may do so using the flash method. Data stored in the
session using this method will only be available during the subsequent
HTTP request, and then will be deleted. Flash data is primarily useful
for short-lived status messages:
In this case, when someone make a post request, you should store the useful data to session, and redirect them to other route. The other route can then retrieve the useful data to display to the view, and user no longer resubmit the form when refresh the page.
public function luckyNumber(Request $request) {
...
$request->session()->flash('nameNickname', $nameNickname);
$request->session()->flash('luckyNumber', $luckyNumber);
return redirect()->action('SixGetController#resultView');
}
public function resultView(Request $request) {
$nameNickname = $request->session()->get('nameNickname');
$luckyNumber = $request->session()->get('luckyNumber');
return view('result', ['nameNickname' => $nameNickname, 'luckyNumber' => $luckyNumber]);
}

Display db data in edit page

I am working with a registered_member_data_edit page?
My controller function is
function edit_profile()
{
$data['title']= 'Edit Profile';
$member_id = $this->session->userdata('member_id');
$this->load->model('user_model','',TRUE);
$data['row'] = $this->user_model->edit_user($member_id)->result();
$this->load->view('edit_profile.php', $this->data);
}
My model function is
public function edit_user($member_id)
{
$this->db->select('fullname','country','district','address','nominee_name','nominee_relation','mobile_no','password','bank_acc_no','bank_acc_name','bank_name','branch_name');
return $this->db->get_where('user', array('member_id'=> $member_id));
}
My view page is like
<p><label>User Name</label>
<input type="text" class="input-short" value="" /></p>
What should I put in the value to show the db data in edit page?
public function edit_user($member_id)
{
$this->db->select('fullname','country','district','address','nominee_name','nominee_relation','mobile_no','password','bank_acc_no','bank_acc_name','bank_name','branch_name');
return $this->db->get_where('user', array('member_id'=> $member_id));
}
this will return the object, which you have in $data['row'] and that variable you are sending to view file.
So in view file, you can access the all data of the object using $row.
So from here you have 2 options
Even that function returning only 1 row, you have to access using foreach($row->result() as $_data) and after that you can access each and every column as $_data->fullname like that.
You can convert that object to array using $row = $row->result_array() and you can access the database column using $row[0]['fullname'] like that.
Best luck.

Resources