When trying to implement https://laravel-livewire.com/docs/2.x/input-validation - Real-time Validation I noticed a problem. Let's assume that we have 3 inputs with real time validation, if I type into first one some value and click tab to go to next input, again i enter the value and go to 3 input, the second and/or third input will glitch because there are 3 request(in case you use https://laravel-livewire.com/docs/2.x/properties#lazy-updating) or even more request if you don't use it. And because of this the value from second and/or third input disappear until all request hit the server. This can be notices with normal internet connection, but with slow internet it's even more obvious.
Steps to reproduce:
Create a livewire component with this content
namespace App\Http\Livewire;
use Livewire\Component;
class ShowPosts extends Component
{
protected $rules = [
'field1' => 'required',
'field2' => 'required',
'field3' => 'required',
];
public $field1;
public $field2;
public $field3;
public function updated($propertyName)
{
$this->validateOnly($propertyName, $this->rules);
}
public function render()
{
return view('livewire.show-posts');
}
}
And this view
<div>
<form wire:submit.prevent="submit">
<div class="form-group mb-3 col-12">
<input class="form-control" type="text" wire:model="field1">
</div>
<div class="form-group mb-3 col-12">
<input class="form-control" type="text" wire:model="field2">
</div>
<div class="form-group mb-3 col-12">
<input class="form-control" type="text" wire:model="field3">
</div>
</form>
</div>
Include it in a blade view with #livewire('show-posts')
In chrome dev tools go to network->online dropdown->select slow 3g connection
Try to enter value for each input and go to next with tab, you will notice that value from previous input disappear or change to the last value that was before modification
What can be done to avoid this disappearing/changing of the input value?
Related
I started working on my first Laravel 6 web app about 2 months ago.
I've been stuck for far too long on this & I'm looking for some tips on what angle from should I look at this problem:
Problem
There's a form in my blade view that has a textarea for user input, 3 switches/checkboxes, a button & a disabled textarea field for the output (just a placeholder for the output at the moment).
This is how the form looks like
The user can paste a list of domains in the textarea input field & depends on which switches/checkboxes are checked, the request (which is now an array thanks to preg_split in the controller) must go through all checked switches/checkboxes logic. I look at these switches like they are filters.
Question
Basically I'm in a never-ending search for any tips on how should I approach defining those switches. I've looked into form request validation, but that doesn't seem to be needed in solving this problem (I know I will use it later to finish up & not leave any loose ends in user inputs fields).
Now, I have a class(ListsCleaner.php) method(filters) that is called in the controller to respond to the request from the view & I think I'm moving the right way, I just don't know how to start writing each switch logic(switch1, switch2, switch3) in there:
class ListsCleaner
{
protected $domains;
function __construct($domains)
{
$this->domains = $domains;
}
public function filters()
{
// Should I write all 3 switches/checkboxes logic here?
}
}
My controller.php
public function filter(Request $request)
{
$domains = preg_split('/\\s/', $request->input('domains'));
dd ($domains);
return new ListsCleaner($domains);
}
dd ($domains);
array:5 [▼
0 => "website1.com"
1 => ""
2 => "website2.com"
3 => ""
4 => "website3.com"
]
My blade.php view
<form class="col s12 center-align" method="get" enctype="multipart/form-data" action="{{ route('filters') }}">
{{csrf_field()}}
<div class="row">
<!-- Switches -->
<div class="switch col 4 valign-wrapper">
<label>
<input checked type="checkbox" name="Switch1" value="true">
<span class="lever"></span>
gTLDs
</label>
</div>
<div class="switch col 4 valign-wrapper">
<label>
<input checked type="checkbox" name="Switch2" value="true">
<span class="lever"></span>
Competitors
</label>
</div>
<div class="switch col 4 valign-wrapper">
<label>
<input checked="checked" type="checkbox" name="Switch3" value="true">
<span class="lever"></span>
Blogspam Sites
</label>
</div>
</div>
<div class="row">
<div class="col s6 input-field">
<textarea name="domains" id="batch_requests" class="materialize-textarea" rows="5" oninput="changedValue()"></textarea>
<label for="batch_requests">Enter URLs separated by space or line break.</label>
</div>
<div class="col s6 input-field">
<textarea disabled name="domains_cleaned" class="materialize-textarea" rows="5" oninput="changedValue()"></textarea>
</div>
</div>
<div class="row">
<div class="col s6 left-align">
<button type="submit" class="btn btn-large waves-effect waves-light white-text">Clean Websites</button>
</div>
</div>
</form>
And lastly, my full ListsCleaner class
namespace App\Lists;
class ListsCleaner
{
protected $domains;
function __construct($domains)
{
$this->domains = $domains;
}
public function filters()
{
// Should I write all 3 switches/checkboxes logic here?
}
}
If I were you, I'd create three classes in \App\Models\Filters, and named them accordingly (class Filter1, class Filter2). Then on each class I'd have a filter($list) method that contains the logic.
On the controller, I'd have a property:
$filters = [
'filter1' => App\Models\Filters\Filter1,
'filter2' => App\Models\Filters\Filter2,
'filter3' => App\Models\Filters\Filter3,
];
Then finally on the controller action you could loop through those and check which ones were selected by user:
foreach($this->filters as $filterName => $class) {
if($request->has($filterName)) {
$list = (new $class)->filter($list);
}
}
That would allow you to run all the three (or more) filters while having their logic in a separate place, which is good for code structure.
As a bonus, you can make Filter1, Filter2 and Filter3 extend a base class App\Models\Filters\AbstractFilter, which would hold common data/methods these filters share.
Here is my routes
Route::get('add-members/{id}','MemberController#create');
Route::post('save-member/{id}','MemberController#store');
This is my code to show the create form
public function create($id)
{
$team=Team::find($id);
$users = User::doesntHave('teams')->whereHas('roles', function($role) {
$role->where('name', 'member');
})->get();
return view('members.create',compact('users','team'));
}
An this is my code to store it
public function store(Request $request,$id)
{
$team=Team::find($id);
dd($request->id);
$team->users()->attach($request->id);
return redirect('home');
}
and this is my blade file
#extends('layouts.app')
#section('content')
<form action="{{url('save-member',$team->id)}}" method="post" accept-charset="utf-8">
#csrf
<div class="form-group row">
<label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Select Member/s') }}</label>
<div class="col-md-6">
#foreach($users as $key => $user)
<input type="checkbox" name="id[]" value="{{$user->id}}">{{$user->email}}<br>
#endforeach
#error('member_id')
<span class="invalid-feedback" role="alert"><strong><font
color="red">{{ $message }}</font></strong></span>
#enderror
</div>
</div>
<button type="submit" class="btn btn-primary">Save</button>
</form>
#endsection
Now when i select none of the user and just click save button it will save the the user id as 1. After i am doing dd($request->id) it will show me the output 1. But in my form there is no users left or my form is empty.So where from 1 is coming. you can see this picture for clearify.
Please help me to solve this problems
You should be more specific with what data you are requesting from the Request:
$request->id; // could be an input named 'id' or a route parameter named 'id'
$request->input('id'); // is an input
$request->route('id'); // is a route parameter
You are running into a situation where you have a route parameter named id and potentially an input named id. Using the dynamic property of the Request, $request->id, will return the input id if it is there, if not it falls back to returning a route parameter named id.
Here is an article from the past that shows the issue with not being specific about what you are trying to get from the Request object:
asklagbox - blog - watch out for request
I'm working on Laravel project and I want to send my input values from the FORM from one page (the inscription page) to a pdf page (which I want the user to be able to download). I couldn't find a way to send them from that page to the other
input:all
using the $request in the controller
<div class="fieldgroup">
<input type="text" style="color:0B0C51" onclick="submitform2()" name="cin" id="cin"
placeholder="N°CIN" maxlength="8" class="required"></i><br>
</div>
<div class="fieldgroup">
<input type="text" style="color:0B0C51" v-model="prenom" name="prenom" id="prenom"
placeholder="Prenom" class="required"><br>
</div>
<div class="fieldgroup">
<input type="text" style="color:0B0C51" v-model="nom" onclick="submitform2()" name="nom"
id="nom" placeholder="Nom" class="required"><br>
</div>
<div class="fieldgroup">
<input type="mail" style="color:0B0C51" name="email" id="email" placeholder="Email"
class="required" />
</div>
ViewController :
class ViewController extends Controller
{
public function generatePDF(Request $request){
$request=this.
$data="form";
$pdf= PDF::loadView('pdf',compact('data'));
return $pdf->download('Terms.pdf');
}
}
web.php:
Route::get('/pdf','ViewController#generatePDF');
inscriController:
public function store(Request $request)
{
$cin = $request->input('cin');
$data = array(['cin'=>$cin ]);
DB::table('form')->insert($data);
return redirect('/pdf')->withInput();
This returns an empty form page without the input values
It may be easier to load the pdf right in the store method of inscriController. As it is, you are redirecting and passing no data into the pdf generator / view. You set $request as the controller ($this), which has none of the form data, and then you pass a single word 'form' as your data-set into the PDF generator. I don't think this will work the way you wish - I assume the pdf view is looking for specific variables (not 'form'), and thus it is failing because those vars are missing. IE you'd want to pull those vars like $name = $request->get('name') and pass whatever pdf.blade.php view needs from your $request var.
If you don't want to do it all in the store function, perhaps pass it to a method in the same inscriController? This way you can easily push the actual request object into that method and pull the fields you need for the PDF view.
use $input = $request->all(); for getting the data and in same function instead of redirect u can just return view for your /pdf route.
like return view('yourpath.pdf', compact('input'));
I'm trying to update my database using a form on my
edit.blade.php page as shown below. The edit part works correctly as the fields are filled in in the form as expected, however when i try to save, an error message of
Symfony \ Component \ HttpKernel \ Exception \ MethodNotAllowedHttpException
No message
is displayed. I have tried so many ways on how to fix it and I'm not sure where I'm going wrong. Hopefully it's something simple to fix?
edit.blade.php
#extends('layouts.app')
<!-- Styles -->
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
#section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<form method="post" action="{{ action('PostsController#update', $id) }}">
{{ csrf_field() }}
<input type="hidden" name="_method" value="PATCH" />
<h1>Edit Item</h1>
<div class="form-group">
<label for="item">Item:</label>
<input type="text" id="item" name="item" value="{{$post->item}}" class="form-control" required>
</div>
<div class="form-group">
<label for="weight">Weight (g):</label>
<input type="number" id="weight" value="{{$post->weight}}" name="weight" class="form-control">
</div>
<div class="form-group">
<label for="noofservings">No of Servings:</label>
<input type="number" id="noofservings" value="{{$post->noofservings}}" name="noofservings" class="form-control">
</div>
<div class="form-group">
<label for="calories">Calories (kcal):</label>
<input type="number" id="calories" name="calories" value="{{$post->calories}}" class="form-control">
</div>
<div class="form-group">
<label for="fat">Fat (g):</label>
<input type="number" id="fat" name="fat" value="{{$post->fat}}" class="form-control">
</div>
<button type="submit" class="btn btn-primary">Save</button>
</form>
</div>
</div>
</div>
#endsection
PostsController.php
<?php
public function update(Request $request, $id)
{
$this->validate('$request', [
'item' => 'required'
]);
$post = Post::find($id);
$post->item = $request->input('item');
$post->weight = $request->input('weight');
$post->noofservings = $request->input('noofservings');
$post->calories = $request->input('calories');
$post->fat = $request->input('fat');
$post->save();
return redirect('/foodlog');
}
web.php
<?php
Route::get('edit/{id}', 'PostsController#edit');
Route::put('/edit', 'PostsController#update');
Post.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $fillable = [
'id',
'user_id',
'item',
'weight',
'noofservings',
'calories',
'fat',
'created_at'
];
}
My website is a food log application and this function is so that they can edit their log.
Any help is greatly appreciated!
Based on Michael Czechowski I edited my answer to make this answer better, The main problem is inside your routes:
Route::put('/edit/{id}', 'PostsController#update');
You have to add the id inside your route parameters either. Your update() function needs two parameters, first the form parameters from the formular and second the $id of the edited log entry.
The second problem is , the form method field is 'patch' and your route method is 'put'.
The difference between 'patch' and 'put' is:
put: gets the data and update the row and makes a new row in the database from the data that you want to update.
patch: just updates the row and it does not make a new row.
so if you want to just update the old row change the route method to patch.
or if you really want to put the data, just change the put method field in your form.
simply by : {{method_field('PUT')}}
Remember, the form's and the route's methods must be same. If the form's method is put, the route method must be put; and vice-versa.
The main problem is inside your routes:
Route::put('/edit/{id}', 'PostsController#update');
You have to add the id inside your route parameters either. Your update() function needs two parameters, first the form parameters from the formular and second the $id of the edited log entry.
The second one is inside your HTML template:
<input type="hidden" name="_method" value="PUT" />
To hit the right route you have to add the corresponding method to your route Route::put('/edit/{id}', 'PostsController#update');.
A possible last problem
<form method="post" action="{{ action('PostsController#update', $post->id) }}">
I am not sure how your template works, but $id is possible not set inside your template. Maybe try to specify the ID depending on your post. Just to make it sure the ID comes from the shown post.
Further suggestions
Best practice is to use the symfony built-in FormBuilder. This would make it easier to target those special requests like PUT, PATCH, OPTIONS, DELETE etc.
I need to get a value of input to use below, how to do that?
I tried to like this but error says
Undefined variable: name
<div class="col-md-10 col-md-offset-1">
<input id="name" type="text" name="name" />
</div>
<div class="col-md-10 col-md-offset-1">
#php
$nameValue=$_GET['name'];
#endphp
<input id="name2" type="text" name="name2" value="{{$nameValue}}" />
</div>
$nameValue=Request::input('name')
From the blade template you can access the request parameters with the Request facade, you can also print it directly:
{{Request::input('name')}}
In latest versions you can also use:
{{request()->input('name')}}
You have to be aware that your input-values (here "name") ist only available after submitting the form.
If you want to access the form-values before submitting you should take a look at VueJS or any other frontend-framework (React, Angular). Or simply use jQuery.
Therefor you have to use JavaScript if you want to use the input-value before submitting.
Like the others said in the comments, you can access your form-values within your controller and then pass it to your view.
For example (from the documentation):
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class UserController extends Controller
{
public function formSubmit(Request $request)
{
$name = $request->input('name');
return view('form', ['name' => $name])
}
}
Now you can use the value within your view:
<input id="name2" type="text" name="name2" value="{{$name}}">
Another possibility would be to "by-pass" your controller and return your view directly from your routes.php:
Route::get('/form-submit', function(){
return view('form');
});
But I'm not sure if this is working and you could access $_GET/$_PSOT directly without using Laravels Request.
You can get inputs array from Request class:
Request::all()['your_input']
Also you can check if that input you want is exists not:
#isset(Request::all()['your_input'])
{{-- your input existed --}}
#else
{{-- your input does not existed --}}
#endisset