I am experimenting with Laravel Livewire and I came across a situation where the previous errors are displayed even though the form is successfully submitted.
Before hit Save
After hitting Save
Html segment of name in blade file customer-new.blade.php.
<div class="form-group">
<div class="border rounded-0 px-1">
<label class="mb-0" for="name">Name</label>
<input wire:model="name" type="text" class="form-control form-control-sm " id="customer-name" aria-describedby="customer-nameHelp">
</div>
#error('name') <span class="err-message">{{ $message }}</span> #enderror
</div>
and the Save button code:
<button
wire:click="store"
wire:loading.attr="disabled"
wire:target="store"
type="submit"
class="btn btn-sm btn-light">Save
</button>
store method of CustomerNew.php:
public function store()
{
$this->validate([
'name' => 'required|max:80',
'street' => 'required|max:100',
'city' => 'required|max:40',
'dueAmount' => 'numeric|min:0'
]);
Customer::create([
'name' => $this->name,
'street' => $this->street,
'city' => $this->city,
'due_amount' => $this->dueAmount,
]);
session()->flash('message', 'Customer was saved');
$this->clear();
}
and the clear() method is like:
public function clear() {
$this - > name = '';
$this - > street = '';
$this - > city = '';
$this - > dueAmount = 0;
}
According to docs https://laravel-livewire.com/docs/input-validation,
You need to reset the validations whenever you want
Direct Error Message Manipulation The validate() and validateOnly()
method should handle most cases, but sometimes you may want direct
control over Livewire's internal ErrorBag.
Livewire provides a handful of methods for you to directly manipulate
the ErrorBag.
From anywhere inside a Livewire component class, you can call the
following methods:
$this->addError('email', 'The email field is invalid.');
// Quickly add a validation message to the error bag.
$this->resetErrorBag();
$this->resetValidation();
// These two methods do the same thing. The clear the error bag.
// If you only want to clear errors for one key, you can use:
$this->resetValidation('email');
$this->resetErrorBag('email');
$errors = $this->getErrorBag();
// This will give you full access to the error bag,
// allowing you to do things like this:
$errors->add('some-key', 'Some message');
HINT
I am using the reset methods on hydrate function like following
...
public function hydrate()
{
$this->resetErrorBag();
$this->resetValidation();
}
...
You should reset the public properties by using the livewire's reset method. Delete your $this->clear() method definition and replace it with the following:
$this->reset('name', 'street', 'city', 'dueAmount');
add id's to the error message div
#error('name') <span class="err-message" id="name-error">{{ $message }}</span> #enderror
#error('street') <span class="err-message" id="street-error">{{ $message }}</span> #enderror
#error('city') <span class="err-message" id="city-error">{{ $message }}</span> #enderror
#error('due_amount') <span class="err-message" id="due_amount-error">{{ $message }}</span> #enderror
$this->resetErrorBag();
Just add this in your clear() method. This will reset the error bag after each save.
It is better to send $name to the resetValidation and resetErrorBug. In this way you reset validation for the updating fields only. Here is my example:
public function updated($name, $value)
{
$this->resetValidation($name);
$this->resetErrorBag($name);
}
Related
in new to laravel and Im trying to set up an edit blade using resource controller . ( using laravel 5.7) but it is throwing an error like this
Missing required parameters for [Route: home.hotels.update] [URI: home/hotels/{hotel}]. (View: C:\xamp\....\.....\edit.blade.php)
Please note:
when i hover over edit button it is correctly pointing to the id's and
when i tries to echo a fieldname inside my "edit function"in controller it returns the correct page but "blank" . can some one tell me wher this error comming from and if possible how to fix this
code in my index blade ( part relating to the edit)
#foreach($hotels as $c)
<tr>
<td>{{$c->hotelid}}</td>
<td>{{$c->hotelname}}</td>
<td>{{$c->city}}</td>
<td>{{$c->location}}</td>
<td>{{$c->singleroom}}</td>
<td>{{$c->doubleroom}}</td>
<td>{{$c->deluxroom}}</td>
<td>{{$c->deluxdouble}}</td>
<td>{{$c->superiorsuit}}</td>
<td><a href="{{route('home.hotels.edit',$c->id)}}"class="btn btn-info" >Update </a>
my edit blade
im passing the entries like this
<form method="post" action="{{route('home.hotels.update',$hotels->id)}}">
#csrf
{{ method_field('PUT') }}
<div class="form-group">
<div class="row">
<label class="col-md-6">Hotel ID</label>
<div class="col-md-6"><input type="text" name="hotelid" class="form-control" value="{{$hotels->hotelid}}"> </div>
</div>
......... rest of the input fields follows........
controller functions
public function index()
{
$arr['hotels']=hotels::all();
return view('admin.hotels.index')->with($arr);
}
my update function also has the same code as store ------
public function store(Request $request, hotels $hotels)
{
$hotels->hotelid=$request->hotelid;
$hotels->hotelname=$request->hotelname;
...........other fields..................
$hotels->save();
return redirect('home/hotels');
}
public function edit(hotels $hotels )
{
$arr['hotels'] = $hotels;
return view('admin.hotels.edit')->with($arr);
}
and my routes
Route::get('/home', 'HomeController#index')->name('home');
Route::resource('home/users', 'Admin\UsersController',['as'=>'home']);
Route::resource('home/hotels', 'Admin\HotelsController',['as'=>'home']);
I am using a template based form in angular. I also use bootstrap (v4) and I wish to show some validation messages when the form was submitted.
This is my form:
<form [ngClass]="{'was-validated': wasValidated}">
<div class="form-group">
<label for="name">Name</label>
<input type="text" id="name" name="name" class="form-control" [(ngModel)]="category.name" #name="ngModel" required maxlength="100"/>
<div *ngIf="name.invalid" class="invalid-feedback">
<div *ngIf="name.errors.required">
Name is required.
</div>
</div>
</div>
<button type="submit" class="btn btn-success" (click)="save()">Save</button>
</form>
My component looks as follows:
category: Category;
wasValidated: boolean = false;
ngOnInit() {
this.reset();
}
save() {
this.wasValidated = true;
this.categoriesService.createCategory(this.category).subscribe(
() => {
this.notificationService.add(notifications.category_saved, {name: this.category.name});
this.reset();
},
() => this.notificationService.add(notifications.save_category_failed)
);
}
reset() {
this.wasValidated = false;
this.category = {} as Category;
}
This works, but I have a feeling it's overly complex and more like a workaround rather than the right way. What is the best way to accomplish this?
Note: the class was-validated must be present on the form element in order to show the div with class invalid-feedback. I'm using this: https://getbootstrap.com/docs/4.0/components/forms/#validation
Note 2: I have currently no mechanism yet to prevent form submission on error. I'd like to know a good solution for that as well!
With the answer from #Chellappan V I was able to construct the solution I wanted.
I have applied to following changes:
First added #form="ngForm" to the form tag in the template. Secondly I changed the ngClass expression to reference the submitted state of the form, rather than referring to a boolean which was set to true manually when form was submitted. Last but not least I pass the form in the submit method on the save button.
<form novalidate #form="ngForm" [ngClass]="{'was-validated': form.submitted}">
<!-- form controls -->
<button type="submit" class="btn btn-success" (click)="submit(form)">Save</button>
</form>
In the component I injected the template variable in the component with #ViewChild.
#ViewChild("form")
private form: NgForm;
The submit method now takes a form parameter of type NgForm which is used to check if the form was valid before sending a request to the backend:
submit(form: NgForm) {
if (form.valid) {
this.categoriesService.createCategory(this.category).subscribe(
() => {
this.notificationService.add(notifications.category_saved, {name: this.category.name});
this.reset();
},
() => this.notificationService.add(notifications.save_category_failed)
);
} else {
this.notificationService.add(notifications.validation_errors);
}
}
Finally the reset method resets the form and the model so it can be re-entered to submit a next instance:
reset() {
this.form.resetForm();
this.category = {} as NewCategoryDto;
}
I have a button that contains a link to another page, and pass some variables from the twig template to the controller action of that page :
<button class="btn btn-warning btn-xs" title="modifier l'article">
<i class="fa fa-pencil-square-o"></i>
</button>
The variables pass to the action successfully but I get an error :
No route found for "GET /content/articles/changeArt/3/test3/%3Ci%3E%3Cu%20style=%22background-color:%20rgb%28255,%20255,%200%29;%22%3Esdfghyujhgrertjr%22%5Ekrjthbkrkjgjgrhgiebgfjkebvkebvkezbkzbkdzbdkzbckdszb%20sdnckdzb%20nc,de%3C/u%3E%3C/i%3E/11/04/2017" (from "http://127.0.0.1/PFE_CNAM/web/content/articles")
(the variable 'content' its of type BLOB, and I start geting this error when i changed its type, because before when it was of type text,this action was working pretty good).
Here is the action code :
/**
* #Route("/content/articles/changeArt/{id}/{title}/{content}/{date}",defaults={"id": 0,"title": 0,"content": 0,"date": 0},name="changeArticle")
* #Template()
*/
public function changeArticleAction($id,$title,$content,$date)
{
$session = new Session();
$session->start();
$search = $session->get('user');
$gestAcces = $session->get('acces');
$gestEtat = $session->get('etatUser');
$gestCont = $session->get('contenu');
$repMsg = $session->get('repMsg');
$gestRec = $session->get('Reclam');
$gestMess = $session->get('gestMess');
$gestMp = $session->get('gestMp');
return $this->render('CNAMCMSBundle:Default:changeArticle.html.twig', array('search' => $search,
'contenu' => $gestCont,
'gestAcces' => $gestAcces,
'gestEtat' => $gestEtat,
'repMsg' => $repMsg,
'gestRec' => $gestRec,
'gestMess' => $gestMess,
'gestMp' => $gestMp,
'date'=>$date,
'id'=>$id,
'title'=>$title,
'content'=>$content,
));
}
Look at your route definition /content/articles/changeArt/{id}/{title}/{content}/{date} you can see this route expected exactly 4 params. Then, look at the generated path /content/articles/changeArt/3/test3/%3Ci%3E%3Cu%20style=%22background-color:%20rgb%28255,%20255,%200%29;%22%3Esdfghyujhgrertjr%22%5Ekrjthbkrkjgjgrhgiebgfjkebvkebvkezbkzbkdzbdkzbckdszb%20sdnckdzb%20nc,de%3C/u%3E%3C/i%3E/11/04/2017, it has alot of params separated by / because your params contains slashes.
When matching the URI with route path, it look like:
id: 3
title: test3
content: %3Ci%3E%3Cu%20style=%22background-color:%20rgb%28255,%20255,%200%29;%22%3Esdfghyujhgrertjr%22%5Ekrjthbkrkjgjgrhgiebgfjkebvkebvkezbkzbkdzbdkzbckdszb%20sdnckdzb%20nc,de%3C
date: u%3E%3C
i%3E // how about these extra params?
11 //
04 //
2017 //
I don't known which Symfony version you're using, it should throw exeption if your params contains /. You can solve your problem by encode your params before generate the url.
{{ path('changeArticle', {
id: id,
title: titre|url_encode,
content: corps|url_encode,
date: pub|date('d/m/Y')|url_encode
}) }}
Is 'date':pub|date('d/m/Y') a Typo?
Try this:
<button class="btn btn-warning btn-xs" title="modifier l'article">
<a
href="{{ path('changeArticle',{
'id' : id,
'title' : titre,
'content' : corps,
'date' : date|date('d/m/Y')
}) }}"
style="color: #ffffee;text-decoration: none;"><i class="fa fa-pencil-square-o"></i>
</a>
</button>
I am trying to use the last version of vuejs with Laravel 5.3 ! The idea I am trying to fulfill is make a component foreach user. So that I have all users listed and foreach one there is a button "edit" , when I click this button I should see the form to update this user.
So this is how I defined the component :
<script>
new Vue({
el: '.view-wrap',
components: {
user-view: {
template: '#user-view',
props: ['user']
}
},
data: {
users: <?php echo json_encode($users); ?>,
},
methods: {
showForm: function(number){
$('div.update-user-'+number).css({'display':'block'});
},
getClassName: function (index) {
return "update-user-"+index;
},
getUpdateUrl: function(id){
return '/users/update/'+id;
},
}
});
This is the template for the "user-view" which take a class name "updateClass" which contains the id of every user (for show/hide purposes), an "updateUrl" which is the url to update the user to bind it with each form action and finally the object user :
<template id="user-view">
<div>
<div class="updateclass">
<form class="form-horizontal" method="PUT" action="updateUrl">
{{ csrf_field() }}
<ul>
<li>
<label for="name"> Name </label>
<input type="text" name="name" :value="user.name">
</li>
<li>
{!! Form::submit('Save', ['class' => 'button-green smaller right']) !!}
</li>
</ul>
{!! Form::close() !!}
</div>
and This is finally how I call the template :
<user-view v-for="user in users" :updateclass="getClassName(user.id)" :user="user" :updateUrl="getUpdateUrl(user.id)"></user-view>
The issue then : it seems that for example [class="updateclass"] doesn't change the value of updateclass with the result of getClassName(user.id) as defined in template call that is binded to. When I try it with [:class="updateclass"] in the template I get : Property or method "updateclass" is not defined on the instance ...
and the same thing applies to all other binded attributes.
The syntax you are using to assign a class dynamically is wrong. from the getClassName method you have to return a object having className like this : {"className: true} , like following
getClassName: function (index) {
var tmp = {}
var className = 'update-user-'+index
tmp[className] = true
return tmp
}
Than you can assign it like following as is in documentation:
<div :class="updateclass"></div>
In controller i have this code. When i want to show company variable on view it gives the error.
This is my controller.
public function login(Request $request){
$email = $request->input('email');
$password = $request->input('password');
$validation = array(
'email' =>'required',
'password' => 'required');
//dd($email);
$validator = Validator::make($request->all(), $validation);
if ($validator->fails()) {
$messages = $validator->messages();
return redirect('login_with_assismo')
->withErrors($validator)
->withInput(Input::except('password'));
} else {
$admin = DB::table('admin')
->where('email',$email)
->where('password', $password)
->where('is_admin', 1)
->first();
if (!empty($admin)) {
$company = DB::table('company_details')
->where('id', $admin->company_id)
->pluck('company_name');
if (!empty($company)) {
return redirect('company_details')->with('company', $company);
}
}
}
}
and this is my view
<input type="text" name="company_name" class="form-control" placeholder="Company name" value = "{{ company }}">
This is the error when i execute this code:
Use of undefined constant company_name - assumed 'company_name' (View: /opt/lampp/htdocs/assismo/resources/views/company_details.blade.php)
The undefined constant error means that you probably tried something like
<div><!-- or other html -->
{{ company_name}}
</div><!-- ... -->
Even though it should be
<div><!-- or other html -->
{{ $company_name}}
</div><!-- ... -->
Howveer, it does not seem you return a company name variable at all so probably it should be
<div><!-- or other html -->
{{ $company }}
</div><!-- ... -->
Additional remarks:
Your code is highly insecure. You should never ever use this in a productive enviroment. You dont crypt the password or anything. It actually seems like your passwords are stored plain.
You should also consider to write your own requests (php artisan:make request) and move validation somewhere else.
I also don't see a reason to use DB Facade here instead of the actual Object you are interested in.