avoid form data getting clear on form submission - php

I am using a html form to get user data using laravel php. On form submit I am executing an api which in Web.php is defined as
Route::post('/register_user', 'UserRegistrationController#registerUser');
which executes,
public function registerUser(Request $request){
$apiResult = $this->executeApi($request->input('mobile_no'));
if($apiResult === "Success"){
return view('further_view');
}else{
toastr()->error('Registration Failed. Please check mobile number.');
return back();
}
}
html code
<div class="form-group{{ $errors->has('mobile_no') ? ' has-error' : '' }}">
<label for="mobile_no">Mobile No</label>
<input type="text" name="mobile_no" class="form-control" id="mobile_no" value="{{ old('mobile_no') }}" placeholder="Enter Mobile No" required>
<small class="text-danger">{{ $errors->first('mobile_no') }}</small>
</div>
My issue here is , whenever my $apiResult === "Success" condition goes false, i get toast message on screen but my page get refreshed and all the data user has typed gets cleared from the input box.
Hence my question is how can I show the toast messages without form being cleared or how would I prevent the input box getting cleared on such conditions.
I am using this Toast library
https://github.com/yoeunes/toastr

I would suggest that you use a session to store the data. For example:
session()->put('forms.mobile_no', $request->get('mobile_no'));
Your HTML:
<input value="{{ $mobile_no }}" type="text" name="mobile_no" class="form-control" id="mobile_no" placeholder="Enter Mobile No" required>

Try to return the error message back with this after the toastr call:
return redirect->back()->withInput();

Related

Laravel - Please how can I make a form field editable by a user when it has no value inside, but read-only when it has value on it

I need a help on a project I am working on using Laravel.
I am working on user profile page.
During user registration on a page, a user can choose to provide username or skip it.
I have no problem with that.
But I want on the user profile page, if the user wants to edit their details.
I want the user to be able to edit and add his/her username in the profile user name for field, if only they doesn't have username already.
But if the user has a username already, then, they can't change/edit their username.
If they have username already, then on the user profile page, they username field should be read-only while displaying their username to them without being able to edit/change the username again from their end.
This is my form username field code sample.
A help will really be appreciated.
Thank you in advance.
<div class="form-group">
<label for="username">#lang('Username')</label>
<input type="text"
class="form-control input-solid"
id="username"
placeholder="(#lang('Enter username'))"
name="username"
value="{{ $edit ? $user->username : '' }}">
Try using Laravel blade if statement directive to conditionally render the input field like this:
<div class="form-group">
<label for="username">#lang('Username')</label>
#if($user->username ?? false)
<input type="text"
class="form-control input-solid"
id="username"
placeholder="(#lang('Enter username'))"
name="noname"
value="{{ $user->username }}" disabled>
#else
<input type="text"
class="form-control input-solid"
id="username"
placeholder="(#lang('Enter username'))"
name="username"
value="{{ $edit ? $user->username : '' }}">
#endif
</div>
I'm using disabled here because apart from making the field read-only it also prevents the field from being submitted. Use readonly="readonly" if you still want the read-only field to be submitted. Also, I changed the name of the read-only field so that even if it is edited by a hacker on the client and submitted, your server PHP script simply ignores it without errors (I'm assuming you don't want it submitted). If you still want to submit it, keep the correct name.
I'll also suggest that on your server side controller, you conditionally validate the username field for extra protection. E.g.
function update(Request $request, User $user)
{
if($user->username ?? false) {
// ignore username field, validate other user input fields and update profile
} else {
// validate username field with other fields and update profile
}
}
CAUTION
Any one with html knowledge can edit your html on a client browser and submit it. Chances are that a hacker will attempt this after highjacking another user session. Use Laravel csrf protection always to prevent this.
For allowing the users who don't have username just for the UI:
document.getElementById("editUserName").addEventListener("click", enableUserNameEditing);
function enableUserNameEditing(){
document.getElementById("username").disabled = false;
}
<div class="form-group">
<label for="username">username</label>
<input type="text"
class="form-control input-solid"
id="username"
placeholder="user name"
name="username"
value="john doe"
disabled
>
<button id='editUserName'>edit</button>
</div>
You should add validation server sided if user has already username don't update.
on the edit buttons and the JS you can add checks
$show_edit = empty($user->username) ? true : false;
now you can use this $show_edit variable to control the permissions for user to see show username field should behave:
<input type="text"
class="form-control input-solid"
id="username"
placeholder="(#lang('Enter username'))"
name="username"
value="{{ $edit ? $user->username : '' }}"
{{ $show_edit === false ? "disabled" : "" }}>
#if($show_edit)
<button id='editUserName'>edit</button>
#endif

Validator Does Not Show Errors At Blade

I have a Controller method like this:
use Validator;
public function insert(Request $request)
{
$data = Validator::make(request()->all(),[
'title' => 'required',
'name' => 'required|alpha_num',
'activation' => 'nullable',
'cachable' => 'nullable'
])->validated();
$wallet = new Wallet();
$wallet->title = $data['title'];
$wallet->name = $data['name'];
if (!empty($data['activation'])) {
$wallet->is_active = 1;
} else {
$wallet->is_active = 0;
}
if (!empty($data['cachable'])) {
$wallet->is_cachable = 1;
} else {
$wallet->is_cachable = 0;
}
$wallet->save();
return redirect(url('admin/wallets/index'));
}
And then I tried showing errors like this:
#error("name")
<div class="alert alert-danger">{{$message}}</div>
#enderror
But the problem is, it does not print any error when I fill the form incorrectly.
So how to fix this and show errors properly?
Here is the form itself, however it submits data to the DB correctly:
<form action="{{ route('insertWallet') }}" method="POST" enctype="multipart/form-data">
#csrf
<label for="title" class="control-label">Title</label>
<br>
<input type="text" id="title-shop" name="title" class="form-control" value="" autofocus>
#error("title")
<div class="alert alert-danger">{{$message}}</div>
#enderror
<label for="title" class="control-label">Name</label>
<br>
<input type="text" id="title-shop" name="name" class="form-control" value="" autofocus>
#error("name")
<div class="alert alert-danger">{{$message}}</div>
#enderror
<input class="form-check-input" type="checkbox" name="cachable" value="cashable" id="cacheStatus">
<label class="form-check-label" for="cacheStatus">
With Cash
</label>
<input class="form-check-input" type="checkbox" name="activaton" value="active" id="activationStatus">
<label class="form-check-label" for="activationStatus">
Be Active
</label>
<button class="btn btn-success">Submit</button>
</form>
check the official documentation here
add the following code
if($data->fails()){
return redirect(url('admin/wallets/index'))->withErrors($data)->withInput();
}
And after that save your data in your database
You are not returning any errors, you are just redirecting back to the view without any data.
Your fix would be to have your validator as this:
$data = Validator::validate(request()->all(),[
'title' => 'required',
'name' => 'required|alpha_num',
'activation' => 'nullable',
'cachable' => 'nullable'
]);
See that I have changed Validator::make to Validator::validate. As the documentation states:
If the validation rules pass, your code will keep executing normally; however, if validation fails, an exception will be thrown and the proper error response will automatically be sent back to the user.
If validation fails during a traditional HTTP request, a redirect response to the previous URL will be generated. If the incoming request is an XHR request, a JSON response containing the validation error messages will be returned.
So, if your validation passes, it will save all the validated data into $data, as you did with ->validated() (but you don't have to write it here), and if it fails, it will automatically throw an Exception, in this case ValidationException, so Laravel will automatically handle it and redirect back with to the same URL and with the errors. So it now should work...
This is the Validator::validate source code and this is the validate source code for the validator validate method.

Autofill the title of website via link in a form

<form method="POST" action="{{ route('storeCompany') }}">
#csrf
<label>{{ __('Website URL') }}</label>
<input type="text" name="url" value="{{ old('url') }}" placeholder="{{ __('http://example.com') }}" class="form-control" required="required">
<label>{{ __('Website Title') }}</label>
<input type="text" name="name" value="{{ old('name') }}" placeholder="{{ __('Example Ltd') }}" class="form-control" required="required">
<input type="submit" name="sbNewReviewItem" class="btn btn-block btn-primary" value="{{ __('Submit New Company') }}">
</form>
I want the "Website Title" field to be auto-filled when the user types the "Website URL" also "Website Title" must be editable if the user want to. How can I do this? Please help :(
Example: When the user enters https://stackoverflow.com/ URL in the "Website URL" field "Website Title" filed must auto-filled as Stack Overflow - Where Developers Learn, Share, & Build Careers
You have a change event on the url-field element which does a fetch request to an api website that returns the html contents of that website, and then it uses regex to extract the html title and then it adds it to the name field.
Also while the fetching is executing we show a Fetching text to let the user know what's going on. And the form submit event has been stopped with the preventDefault() function. Here you can do what ever you want after the user submits the form.
Instead of using https://api.codetabs.com/v1/proxy/?quest= which will limit your requests and show you a Too many requests error, you should use your own code that fetches the website contents and then return the response. To optimize this you can return just the website title, to save on bandwidth and cpu cycles.
The reason you need an api to fetch the website content is because of CORS. You can't just use fetch resources from any website you want. You can only do this from the current website or from websites that have allowed you to do so.
document.addEventListener('submit', event => {
event.preventDefault()
})
document.addEventListener('change', async (event) => {
if (event.target.classList.contains('url-field')) {
await changeUrl(event.target.closest('form').elements)
}
})
async function changeUrl (fields) {
try {
if (!fields.url.value) return
fields.output.removeAttribute('hidden')
const response = await fetch('https://api.codetabs.com/v1/proxy/?quest=' + encodeURI(fields.url.value))
const html = await response.text()
const match = /<title[\s\S]*?>([\s\S]*?)<\/title>/gi.exec(html)
if (!match || !match[1]) throw new Error('No title found')
fields.name.value = match[1].trim()
fields.output.setAttribute('hidden', '')
} catch (error) {
console.error(error)
}
}
<form method="POST" action="">
<p>
<label>Website URL</label>
<input type="url" name="url" value="" placeholder="http://example.com" class="form-control url-field" required>
<output name="output" hidden>Fetching</output>
</p>
<p>
<label>Website Title</label>
<input type="text" name="name" value="" placeholder="Example Ltd" class="form-control">
</p>
<input type="submit" name="sbNewReviewItem" class="btn btn-block btn-primary" value="Submit New Company">
</form>
Because you're example look like Laravel.
I found it appropriate to write an answer in PHP.
example.blade.php
<title>{{ $title ?? 'Default title' }}</title>
<form method="POST" action="{{ route('storeCompany') }}">
#csrf
<label>{{ __('Website URL') }}</label>
<input type="text" name="url" value="{{ $url ?? old('url') }}" placeholder="{{ __('http://example.com') }}" class="form-control" required="required">
<label>{{ __('Website Title') }} <small>(Leave blank to retrieve from URL)</small></label>
<input type="text" name="name" value="{{ $title ?? old('name') }}" placeholder="{{ __('Example Ltd') }}" class="form-control">
<input type="submit" name="sbNewReviewItem" class="btn btn-block btn-primary" value="{{ __('Submit New Company') }}">
</form>
CompanyController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
class CompanyController extends Controller
{
public function index(){
return view('example');
}
public function storeCompany(Request $request){
$title = $request->name;
if (empty($title) && filter_var($request->url, FILTER_VALIDATE_URL)){
$response = HTTP::get($request->url);
if ($response->ok()){
preg_match('/<title>(.*)<\/title>/i', $response->body(), $matches);
$title = $matches[1] ?? null;
}
}
$data = [
'url' => $request->url,
'title' => $title
];
return view('example', $data);
}
}
As soon as user has entered the data.
Get the value using $("#text_field").val();
Have an ajax call and get the value using the below function, pass the url to t
require 'simple_html_dom.php';
function dataParser($url){
$html = new simple_html_dom();
$html->load_file($url);
$title = $html->find('title',0)->innertext;
return $title;
}
// something like $_GET['user_url'];
echo $title = dataParser('https://stackoverflow.com');
this code will output the title, set it to the div where you want to show the title, something like this
var ajaxCallResponse = ""//store the response here
$("#title_div").val(ajaxCallResponse);
Here is how to:
Read the website url.
Send an ajax request to codetabs api to get full html.
Get the title from the html.
Do whatever you need with the title.
function gettitle(website) {
if(website.trim() == ''){
return false;
}
var url = 'https://api.codetabs.com/v1/proxy/?quest=' + website;
$.ajax({
url: url,
success: function(responseHtml) {
var newTitle = $(responseHtml).filter('title').text();
document.getElementById('title').innerHTML = 'Title: ' + newTitle
},
error: function() {
document.getElementById('title').innerHTML = newTitle = 'Sorry that page doesn\'t';
}
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input placeholder='Website' oninput='gettitle(this.value)' type='url' id='url'>
<div id='title'></div>

Laravel 5 form does not redirect with old input

I'm validating laravel forms and old input does not preserve after validation fail.
I'm using laravel 5.8 form request validation and html input fields are filled with default values :
public function store(ProyectoRequest $request){
$input = $request->validated();
DB::transaction(function () use($input) {
$proyecto = new Proyecto();
$proyecto->fill($input);
$proyecto->save();
});
return redirect(route('proyectos.index'));
}
<div class="form-group">
<label for="nombre">Nombre</label>
<input type="text" class="form-control input-lg" value="{{$proyecto_nombre}}" name="nombre">
</div>
When the form is validated the page reloads with the default values. I expect that input fields values are preserved. That is what I have understood from the documentation.
I am looking for the docs and there is not written if this is the normal behaviour or not.
Anyway you can do yourself with this code:
<div class="form-group">
<label for="nombre">Nombre</label>
<input type="text" class="form-control input-lg" value="{{ old('proyecto_nombre', $proyecto_nombre) }}" name="nombre">
</div>
In laravel the old function retrieves input fields.

How to get old value of a field using vue inside blade.php

I am having a registration form that uses vue inside Laravel blade file. I'm using a validator for invalid inputs of user and I want to get the old value of the field but now I can't make it work since some of the fields are using vue. Here's my code:
regist.blade.php
<div class="regist_input">
<input type="email" name="email" v-model="email" v-bind:placeholder="placeholder_email" v-bind:class="{ error: emailError }">
<p class="error_text" v-bind:class="{ active: emailError2 }">Invalid email.</p>
#if($errors->has('email'))
<p class="alert-error">
{{ $errors->first('email') }}
</p>
#endif
</div>
<dd>
<div class="regist_input">
<input class="input_company" type="text" name="company" value="{{ old('company') }}" placeholder="company"> //this one works
</div>
</dd>
controller
if($validator->fails()) {
return redirect()->back()->withInput()->withErrors($validator->errors());
}
I can display its old value if out side the field, which means that my php function that validates is working.
I tried using v-bind:value="{{ old('email') }}" or :value="{{ old('email') }}" but is not working.For this one, how can I display the old value in the input field that has a vue component?
You could pass the blade email data to vue using data attributes.
First should add an id to an HTML element with data attribute on it. Then use blade to parse your data and set the data attribute to email data.
<div id="email-data" data-email="{{ old('email') }}"></div>
TO BE EXACT (OP)
<input type="email" value="{{ old('email') }}" name="email" v-model="email" id="email-data" data-email="{{ old('email') }}" v-bind:placeholder="placeholder_email"
v-bind:class="{ error: emailError }">
Then in the created / mounted hook in vue extract the data and set to the email state.
created() {
const el = document.getElementById('email-data')
const email = el.dataset.email
this.email = email
}
v-bind:value="{{ old('email') }}" or :value="{{ old('email') }} don't work because you are using v-model="email"
When you use v-model, it means that there should be an "email" property in the "data" attribute of a Vue component, and any value set to that "email" property will be what is displayed as the value of the input field.
See this Pen I created to illustrate both scenarios.
So, you'll need to remove the v-model if you want to use the v-bind:value. And now that I'm writing this, I don't think you need the v-bind:value and can just simply use value (just as you're doing with the company input.

Categories