Refresh same livewire component after form wire:submit.prevent - laravel

Please I'd like to refresh same component after form submit. There is an if statement that allows the the form to display in the component. I'd like to refresh the whole component so as not to show the form again after submit.
I already tried emit but I don't think it works for same component.
Livewire component
<?php
namespace App\Http\Livewire;
use App\Lesson;
use App\Question;
use App\QuestionsOption;
use App\TestsResult;
use Livewire\Component;
class LessonTest extends Component
{
public $test_result;
public $lesson;
public $test_exists;
public array $question = [];
//protected $listeners = ['testDone' => 'render'];
public function mount($test_exists, $lesson, $test_result)
{
$this->lesson = $lesson;
$this->test_exists = $test_exists;
$this->test_result = $test_result;
}
public function lessonTest()
{
$lesson = Lesson::where('slug', $this->lesson->slug)->firstOrFail();
$answers = [];
$test_score = 0;
foreach ($this->question as $question_id => $answer_id) {
$question = Question::find($question_id);
$correct = QuestionsOption::where('question_id', $question_id)
->where('id', $answer_id)
->where('correct', 1)->count() > 0;
$answers[] = [
'question_id' => $question_id,
'option_id' => $answer_id,
'correct' => $correct,
];
if ($correct) {
$test_score += $question->score;
}
/*
* Save the answer
* Check if it is correct and then add points
* Save all test result and show the points
*/
}
$test_result = TestsResult::create([
'test_id' => $this->lesson->test->id,
'user_id' => \Auth::id(),
'test_result' => $test_score,
]);
$test_result->answers()->createMany($answers);
$this->reset(['question']);
$this->emit('testDone');
}
public function render()
{
return view('livewire.lesson-test');
}
}
Livewire Blade View
<div>
#if ($test_exists)
<hr />
<h3>Test: {{ $lesson->test->title }}</h3>
#if (!is_null($test_result))
<div class="alert alert-info">Your test score: {{ $test_result->test_result }} /
{{ $lesson->test->questions->count() }}</div>
#else
<form wire:submit.prevent='lessonTest' action="{{ route('lessons.test', [$lesson->slug]) }}"
method="post">
{{ csrf_field() }}
#foreach ($lesson->test->questions as $question)
<b>{{ $loop->iteration }}. {{ $question->question }}</b>
<br />
#foreach ($question->options as $option)
<input type="radio" wire:model='question.{{ $question->id }}'
name="questions[{{ $question->id }}]" value="{{ $option->id }}" />
{{ $option->option_text }}<br />
#endforeach
<br />
#endforeach
<button class="btn btn-success btn-lg refresh" type="submit">Submit</button>
</form>
#endif
<hr />
#endif
</div>

Thank You. I got it solved, I forget that I passed the test result from the controller before, so I had to recall the test_result and also the test_exist inside the lessonTest action.
$this->test_result = TestsResult::where('test_id', $this->lesson->test->id)
->where('user_id', \Auth::id())
->first();
$this->test_exists = true;

Related

Livewire dropdown with change event value getting set back to original after change event

I have a dropdown in a livewire component that I'm using a change event to enable/disable a second input field. The change event is working, and it's sent to the server, and updated in the database, however, after the change event fires, it immediately changes the dropdown selected value back to the original one. I can't figure out why it's doing that.
Here's the code in my blade view:
<div class="row">
<div class="mb-3 col-md-4">
<x-input.group label="Legal Entity" for="legal_entity_type_id" :error="$errors->first('companyDetail.legal_entity_type_id')">
<x-input.select wire:model.defer="companyDetail.legal_entity_type_id" wire:change="entitySelected" id="legal_entity_type_id" for="legal_entity_type_id" label="Legal Entity">
#foreach ($legalEntities as $entity)
<option name="{{ $entity->name }}" id="{{ $entity->id }}" value="{{ $entity->id }}" wire:key="{{ $entity->id }}" #if (isset($companyDetail->legal_entity_type_id) && $companyDetail->legal_entity_type_id === $entity->id) selected #endif>
{{ $entity->name }}
</option>
#endforeach
</x-input.select>
</x-input.group>
</div>
<div class="mb-3 col-md-5">
<x-input.group label="Legal Entity If Other" for="legal_entity_description_if_other" :error="$errors->first('companyDetail.legal_entity_description_if_other')">
<x-input.text wire:model.defer="companyDetail.legal_entity_description_if_other" isDisabled="{{ !$enableOtherLegalEntity }}" id="legal_entity_description_if_other" name="legal_entity_description_if_other" value="{{ $companyDetail->legal_entity_description_if_other ?? '' }}" />
</x-input.group>
</div>
</div>
Here's the component code:
class CompanyDetail extends Component
{
public LocationDetail $companyDetail;
public $legalEntities;
public $smsTypes;
public $enableOtherLegalEntity;
protected $rules = [
'companyDetail.legal_entity_type_id' => 'required|exists:legal_entity_types,id',
'companyDetail.legal_entity_description_if_other' => 'required_if:legal_entity_type_id, ==, 6',
'companyDetail.sms_type_id' => 'required|exists:sms_types,id',
'companyDetail.rent_amount' => 'numeric',
'companyDetail.ein' => 'numeric|max:999999999'
];
public function mount(LocationDetail $companyDetail)
{
$this->companyDetail = $companyDetail;
$this->smsTypes = SmsType::all();
$this->legalEntities = LegalEntityType::all();
$this->enableOtherLegalEntity = ($this->companyDetail['legal_entity_type_id'] == 6);
}
public function render()
{
return view('livewire.locations.company-detail');
}
public function entitySelected()
{
$this->enableOtherLegalEntity = ($this->companyDetail['legal_entity_type_id'] == 6);
}
public function save()
{
$this->validate();
$this->companyDetail->save();
$this->companyDetail->refresh();
$this->dispatchBrowserEvent('closeModal');
}
}

Livewire throwing error when using paginated data

So I am being given this error when trying to paginate my data and send it in to a view through a livewire component.
I am trying to get all posts and display at max 5 posts per page using pagination in laravel.
Livewire version: 2.3.1
Laravel version: 8.13.0
Error:
Livewire\Exceptions\PublicPropertyTypeNotAllowedException
Livewire component's [user-posts] public property [posts] must be of type: [numeric, string, array, null,
or boolean]. Only protected or private properties can be set as other types because JavaScript doesn't
need to access them.
My Component:
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use App\Models\Post;
use Livewire\WithPagination;
class UserPosts extends Component
{
use WithPagination;
public $posts;
public $type;
protected $listeners = ['refreshPosts'];
public function delete($postId)
{
$post = Post::find($postId);
$post->delete();
$this->posts = $this->posts->except($postId);
}
public function render()
{
if($this->type == 'all')
$this->posts = Post::latest()->paginate(5);
else if($this->type == 'user')
$this->posts = Post::where('user_id',Auth::id())->latest()->paginate(5);
return view('livewire.user-posts', ['posts' => $this->posts]);
}
}
My Blade:
<div wire:poll.5s>
#foreach($posts as $post)
<div style="margin-top: 10px">
<div class="post">
<div class="flex justify-between my-2">
<div class="flex">
<h1>{{ $post->title }}</h1>
<p class="mx-3 py-1 text-xs text-gray-500 font-semibold"
style="margin: 17px 0 16px 40px">{{ $post->created_at->diffForHumans() }}</p>
</div>
#if(Auth::id() == $post->user_id)
<i class="fas fa-times text-red-200 hover:text-red-600 cursor-pointer"
wire:click="delete({{$post->id}})"></i>
#endif
</div>
<img src="{{ asset('image/banner.jpg') }}" style="height:200px;"/>
<p class="text-gray-800">{{ $post->text }}</p>
#livewire('user-comments', [
'post_id' => $post->id,
'type' => 'all'
],
key($post->id)
)
</div>
</div>
#endforeach
{{ $posts->links() }}
</div>
$posts should not be declared as a property in the Livewire component class, you passed the posts with the laravel view() helpers as data.
Remove the line
public $posts;
And replace $this->posts by $posts in the render function:
public function render()
{
if($this->type == 'all')
$posts = Post::latest()->paginate(5);
else if($this->type == 'user')
$posts = Post::where('user_id',Auth::id())->latest()->paginate(5);
return view('livewire.user-posts', ['posts' => $posts]);
}
}

Update data in laravel 6

I try to create crud in laravel 6. Create, Read and Delete process is running well. But when Update process, the data in table not change. Could anyone help me to find the problem ? The following my code.
Route
Route::get('/blog', 'BlogController#index');
Route::get('/blog/add','BlogController#add');
Route::post('/blog/store','BlogController#store');
Route::get('/blog/edit/{id}','BlogController#edit');
Route::post('/blog/update','BlogController#update');
Controller
public function index()
{
$blog = DB::table('blog')->get();
return view('blog',['blog' => $blog]);
}
public function edit($id)
{
$blog = DB::table('blog')->where('blog_id', $id)->get();
return view('edit', ['blog'=>$blog]);
}
public function update(Request $request)
{
DB::table('blog')->where('blog_id',$request->blog_id)->update([
'blog_title' => $request->title,
'author' => $request->author]);
return redirect('/blog');
}
View
#foreach ($blog as $n)
<form method="post" action="/blog/update" />
{{ csrf_field() }}
Title <input type="text" name="title" value="{{ $n->title}}">
Author<input type="text" name="author" value="{{ $n->author}}">
<button type="submit" class="btn btn-secondary">Update</button>
</form>
#endforeach
You must provide id in your route
Route::post('/blog/update/{id}','BlogController#update');
In update method add parameter id and then find product against id
public function update(Request $request, $id)
{
DB::table('blog')->where('blog_id',$id)->update([
'blog_title' => $request->title,
'author' => $request->author]);
return redirect('/blog');
}
#foreach ($blog as $n)
<form method="post" action="{{ route('your route name'), ['id' => $$n->id] }}" />
{{ csrf_field() }}
Title <input type="text" name="title" value="{{ $n->title}}">
Author<input type="text" name="author" value="{{ $n->author}}">
<button type="submit" class="btn btn-secondary">Update</button>
</form>
#endforeach
try separating the update into two statements like so
$blog = DB::table('blog')->where('blog_id',$id)->first();
$blog->update([
'blog_title' => $request->title,
'author' => $request->author]);
Also you might want to use models in the future so you can do it like
$blog = Blog::where('blog_id',$id)->first();
Doesn't really shorten your code but it improves the readibility.
Do your update like this:
public function update(Request $request)
{
$post = DB::table('blog')->where('blog_id',$request->blog_id)->first();
$post->blog_title = $request->title;
$post->author = $request->author;
$post->update();
return redirect('/blog');
}

Laravel Maatwebsite excel

I need your help. I don't know how to import the excel file. I mean I don't understand where to put this users.xlsx and how to get its directory
public function import()
{
Excel::import(new UsersImport, 'users.xlsx');
return redirect('/')->with('success', 'All good!');
}
its simple on mattwebsite you need a controller like below :
public function importExcel(Request $request)
{
if ($request->hasFile('import_file')) {
Excel::load($request->file('import_file')->getRealPath(), function ($reader) {
foreach ($reader->toArray() as $key => $row) {
// note that these fields are completely different for you as your database fields and excel fields so replace them with your own database fields
$data['title'] = $row['title'];
$data['description'] = $row['description'];
$data['fax'] = $row['fax'];
$data['adrress1'] = $row['adrress1'];
$data['telephone1'] = $row['telephone1'];
$data['client_type'] = $row['client_type'];
if (!empty($data)) {
DB::table('clients')->insert($data);
}
}
});
}
Session::put('success on import');
return back();
}
and a view like this :
<form
action="{{ URL::to('admin/client/importExcel') }}" class="form-horizontal" method="post"
enctype="multipart/form-data">
{{ csrf_field() }}
<div class="form-group">
<label class="control-label col-lg-2">excel import</label>
<div class="col-lg-10">
<div class="uploader"><input type="file" name="import_file" class="file-styled"><span class="action btn btn-default legitRipple" style="user-select: none;">choose file</span></div>
</div>
</div>
<button class="btn btn-primary">submit</button>
</form>
and finally a route like below :
Route::post('admin/client/importExcel', 'ClientController#importExcel');

Laravel Pagination Appends Not Keeping Search Data

I've been able to implement the pagination and appends() on my form and it does show the proper values in the url on page 2, though it doesn't actually bring the values back into the form/query, it simply resets the actual data being searched for and displays all.
Here is my form code and the appends.
{{ Form::open(array('class' => 'stdform', 'method' => 'post', 'name' => 'all')) }}
<input type="text" name="srch_lname" class="input-large"
value="{{ Input::old('srch_lname', Session::get('srch_lname')) }}" />
<input type="text" name="srch_fname" class="input-large"
value="{{ Input::old('srch_fname', Session::get('srch_fname')) }}" />
.
.
.
<?php echo $employees->appends(array("srch_lname" => Session::get('srch_lname'),
"srch_fname" => Session::get('srch_fname') ))->links(); ?>
And my Controller
public function getIndex() {
$srch_lname = Session::get('srch_lname');
$srch_fname = Session::get('srch_fname');
$employees = vEmployees::co()->restrictions()
->where('lastname', 'LIKE', $srch_lname . '%')
->where('firstname', 'LIKE', $srch_fname . '%')
->paginate(10);
return View::make('employees.index')
->with('employees', $employees)
->with('title', 'Users');
}
public function postIndex() {
if (Input::has('btnSearch')) {
return Redirect::to('/employees')->with('search', 1)
->with('srch_lname', Input::get('srch_lname'))
->with('srch_fname', Input::get('srch_fname'));
else {
return Redirect::to('/employees');
}
}
Full Form
{{ Form::open(array('class' => 'stdform', 'method' => 'post', 'name' => 'all')) }}
<div class="stepContainer">
<div class="formwiz content">
<h4 class="widgettitle">Search for an Employee</h4>
<p>
<label>Lastname</label>
<span class="field">
<input type="text" name="srch_lname" class="input-large"
value="{{ Input::old('srch_lname', Session::get('srch_lname')) }}" />
</span>
</p>
<p>
<label>Firstname</label>
<span class="field">
<input type="text" name="srch_fname" class="input-large"
value="{{ Input::old('srch_fname', Session::get('srch_fname')) }}" />
</span>
</p>
</div>
</div>
<div class="actionBar" style="text-align: right;">
<button class="btn btn-primary" name="btnSearch" value="1">
Search for Employee(s)
</button>
</div>
{{ Form::close() }}
You need to pass your inputs to the view so that Input::old() has values to work with after the redirect from postIndex to getIndex.
in getIndex(), add to View::make()
->with('input', [ 'srch_lname'=> $srch_lname, 'srch_fname' => $srch_fname ]);
It looks like you do not have the pageSearch value in your pagination query string. Try this.
<?php echo $employees->appends(
array("btnSearch" => "1",
"srch_lname" => Session::get('srch_lname'),
"srch_fname" => Session::get('srch_fname') )
)->links(); ?>
I made a small sample but since I don't have your employees I just used the User model and commented out the filtering, just used as a test to pass and get input values.
Note the change to Input:: from Session, in getIndex() and in the form for $employees->appends(). Use Input instead of Session, I did not see anywhere in your code where you save the filter values in session variables.
I also changed the Redirect::to() to pass the parameters in the URL since it is a get method.
I tested and the filter values are passed to getIndex() and the form fields, also the inputs get properly passed by pagination links.
class EmployeeController extends BaseController
{
public
function getIndex()
{
$srch_lname = Input::get('srch_lname');
$srch_fname = Input::get('srch_fname');
$employees = User::query()
//->where('lastname', 'LIKE', $srch_lname . '%')
//->where('firstname', 'LIKE', $srch_fname . '%')
->paginate(10);
// make input available for page's form fields as old input
Session::flash('_old_input', Input::all());
return View::make('employees')
->with('employees', $employees)
->with('title', 'Users');
}
public
function postIndex()
{
if (Input::has('btnSearch'))
{
return Redirect::to('/employees?search=1&srch_lname=' . urlencode(Input::get('srch_lname')) . '&srch_fname=' . urlencode(Input::get('srch_fname')));
//return Redirect::to('/employees')->with('search', 1)
// ->with('srch_lname', Input::get('srch_lname'))
// ->with('srch_fname', Input::get('srch_fname'));
}
else
{
return Redirect::to('/employees');
}
}
}
Form and ->appends():
{{ Form::open(array('class' => 'stdform', 'method' => 'post', 'name' => 'all')) }}
<div class="stepContainer">
<div class="formwiz content">
<h4 class="widgettitle">Search for an Employee</h4>
<p>
<label>Lastname</label>
<span class="field">
<input type="text" name="srch_lname" class="input-large"
value="{{ Input::old('srch_lname', Session::get('srch_lname')) }}" />
</span>
</p>
<p>
<label>Firstname</label>
<span class="field">
<input type="text" name="srch_fname" class="input-large"
value="{{ Input::old('srch_fname', Session::get('srch_fname')) }}" />
</span>
</p>
</div>
</div>
<div class="actionBar" style="text-align: right;">
<button class="btn btn-primary" name="btnSearch" value="1">
Search for Employee(s)
</button>
</div>
{{ Form::close() }}
<?php echo $employees->appends(array("srch_lname" => Input::get('srch_lname'),
"srch_fname" => Input::get('srch_fname') ))->links(); ?>
I got it working! I continued to do some research and running the search through POST was really a major issue in adding that gap between the search itself and holding the data into the GET method of pagination.
I'll run through everything I did below for anyone in the future having the same issue.
I first created a Route that would direct to a new function in my EmployeesController
Route::get('emp_srch', 'EmployeesController#search');
And created the new function in the Controller
public function search() {
$srch_lname = Input::get('srch_lname');
$srch_fname = Input::get('srch_fname');
$employees = vEmployees::co()->restrictions()
->where('lastname', 'LIKE', $srch_lname . '%')
->where('firstname', 'LIKE', $srch_fname . '%')
->orderBy('lastname')
->orderBy('firstname')
->paginate(10);
Session::flash('_old_input', Input::all());
return View::make('employees.index')
->with('employees', $employees)
->with('title', 'Users')
->with('pagetitle', 'Employees')
}
It's essentially the function I had in the getIndex though rearranging the way the search was functioning I believe was the defining factor in actually getting this to work in my case.
I also changed the url on the form, which directed to my new Route. As well as changing the form so it uses the GET Method and no longer POST.
{{ Form::open(array('url' => 'emp_srch', 'class' => 'stdform', 'method' => 'get')) }}
I do want to thank vladsch and whoacowboy for helping push me in the right direction(s).

Resources