proengsoft / laravel-jsvalidation

Laravel Javascript Validation
MIT License
1.13k stars 175 forks source link

I suggest adding a check for an error #985

Open spy-reality opened 11 months ago

spy-reality commented 11 months ago

/resources/views/bootstrap.php

errorPlacement: function (error, element) {
    if (element.parent('.input-group').length ||
        element.prop('type') === 'checkbox' || element.prop('type') === 'radio') {
        error.insertAfter(element.parent());
        // else just place the validation message immediately after the input
    } else {
        error.insertAfter(element);
    }
},

replace with

errorPlacement: function(error, element) {
    var existingError = element.next('.error-help-block'); // Checking the existence of an already displayed error
    if (existingError.length) {
        existingError.replaceWith(error); // Replacing an existing error with a new one
    } else {
        if (element.parent('.input-group').length ||
            element.prop('type') === 'checkbox' || element.prop('type') === 'radio') {
            error.insertAfter(element.parent());
        } else {
            error.insertAfter(element);
        }
    }
},

The form validation is done in php and an error is returned which is inserted like this

@error('username')
<span class="help-block error-help-block">{{ $message }}</span>
@enderror

The problem is that error.insertAfter does not replace this error.

bytestream commented 11 months ago

If it's inserting the error multiple times then it would suggest an issue with your jquery-validation configuration. errorPlacement won't be ran if the error element already exists.

spy-reality commented 11 months ago

Is it possible that the problem is that I send the entry through php and not through ajax?

https://github.com/proengsoft/laravel-jsvalidation/assets/8506195/97ec7a94-cee3-40a0-98b0-250044680d42

bytestream commented 11 months ago

What's your full jquery-validation config?

spy-reality commented 11 months ago

router

Route::get('/login', [AuthController::class, 'showLoginForm'])->name('login');
Route::post('/login', [AuthController::class, 'login']);

login.blade.php

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
    <title>Логін | Admin LTE</title>

    <!-- Bootstrap 3.3.4 -->
    <link href="/adminlte/bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
    <!-- FontAwesome 4.3.0 -->
    <!-- <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet"
          type="text/css"/> -->
    <!-- Ionicons 2.0.0 -->
    <link href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css" rel="stylesheet" type="text/css" />
    <!-- Theme style -->
    <link href="/adminlte/dist/css/AdminLTE.min.css" rel="stylesheet" type="text/css" />
    <!-- AdminLTE Skins. Choose a skin from the css/skins 
         folder instead of downloading all of them to reduce the load. -->
    <link href="/adminlte/dist/css/skins/_all-skins.min.css" rel="stylesheet" type="text/css" />
    <!-- iCheck -->
    <link href="/adminlte/plugins/iCheck/flat/blue.css" rel="stylesheet" type="text/css" />
    <!-- Morris chart -->
    <link href="/adminlte/plugins/morris/morris.css" rel="stylesheet" type="text/css" />
    <!-- jvectormap -->
    <link href="/adminlte/plugins/jvectormap/jquery-jvectormap-1.2.2.css" rel="stylesheet" type="text/css" />
    <!-- Date Picker -->
    <link href="/adminlte/plugins/datepicker/datepicker3.css" rel="stylesheet" type="text/css" />
    <!-- Daterange picker -->
    <link href="/adminlte/plugins/daterangepicker/daterangepicker-bs3.css" rel="stylesheet" type="text/css" />
    <!-- bootstrap wysihtml5 - text editor -->
    <link href="/adminlte/plugins/bootstrap-wysihtml5/bootstrap3-wysihtml5.min.css" rel="stylesheet" type="text/css" />
    <!-- DATA TABLES -->
    <link href="/adminlte/plugins/datatables/dataTables.bootstrap.css" rel="stylesheet" type="text/css" />

    <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->

    @vite('resources/css/app.css')
    @vite('resources/js/app.js')
</head>

<body id="body" class="sidebar-mini wysihtml5-supported skin-purple fixed">
    <div class="login-box">
        <div class="login-logo">
            <a href="{{ url('/') }}"><b>Admin</b>LTE</a>
        </div>
        <!-- /.login-logo -->
        <div class="login-box-body">
            <p class="login-box-msg">Увійдіть, щоб почати сеанс.</p>

            <form id="formLogin" method="POST" action="{{ route('login') }}">
                @csrf

                <div class="form-group has-feedback required {{ $errors->has('username') ? ' has-error' : '' }}">
                    <label class="control-label">Логін</label>
                    <input type="text" name="username" class="form-control" placeholder="Логін" value="{{ old('username') }}" required autofocus>
                    @error('username')
                    <span class="help-block error-help-block">{{ $message }}</span>
                    @enderror
                    <span class="glyphicon glyphicon-envelope form-control-feedback"></span>
                </div>

                <div class="form-group has-feedback required {{ $errors->has('password') ? ' has-error' : '' }}">
                    <label class="control-label">Пароль</label>
                    <input type="password" name="password" class="form-control" placeholder="Пароль" required>
                    @error('password')
                    <span class="help-block error-help-block">{{ $message }}</span>
                    @enderror
                    <span class="glyphicon glyphicon-lock form-control-feedback"></span>
                </div>

                <div class="form-group">
                    <div class="checkbox">
                        <label>
                            <input type="checkbox" name="remember" {{ old('remember') ? 'checked' : '' }}> Запам'ятай мене
                        </label>
                    </div>
                </div>

                <div class="form-group">
                    <button type="submit" class="btn btn-primary btn-block btn-flat" name="login-button">Увійти</button>
                </div>
            </form>

        </div>
        <!-- /.login-box-body -->
    </div><!-- /.login-box -->

    <!-- jQuery 2.1.4 -->
    <script src="/adminlte/plugins/jQuery/jQuery-2.1.4.min.js"></script>
    <!-- jQuery UI 1.11.2 -->
    <script src="http://code.jquery.com/ui/1.11.2/jquery-ui.min.js" type="text/javascript"></script>
    <!-- Resolve conflict in jQuery UI tooltip with Bootstrap tooltip -->
    <script>
        $.widget.bridge('uibutton', $.ui.button);
    </script>

    <!-- Sparkline -->
    <script src="/adminlte/plugins/sparkline/jquery.sparkline.min.js" type="text/javascript"></script>
    <!-- jvectormap -->
    <script src="/adminlte/plugins/jvectormap/jquery-jvectormap-1.2.2.min.js" type="text/javascript"></script>
    <script src="/adminlte/plugins/jvectormap/jquery-jvectormap-world-mill-en.js" type="text/javascript"></script>
    <!-- jQuery Knob Chart -->
    <script src="/adminlte/plugins/knob/jquery.knob.js" type="text/javascript"></script>
    <!-- daterangepicker -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.2/moment.min.js" type="text/javascript"></script>
    <script src="/adminlte/plugins/daterangepicker/daterangepicker.js" type="text/javascript"></script>
    <!-- datepicker -->
    <script src="/adminlte/plugins/datepicker/bootstrap-datepicker.js" type="text/javascript"></script>
    <!-- Bootstrap WYSIHTML5 -->
    <script src="/adminlte/plugins/bootstrap-wysihtml5/bootstrap3-wysihtml5.all.min.js" type="text/javascript"></script>
    <!-- Slimscroll -->
    <script src="/adminlte/plugins/slimScroll/jquery.slimscroll.min.js" type="text/javascript"></script>
    <!-- FastClick -->
    <script src='/adminlte/plugins/fastclick/fastclick.min.js'></script>
    <!-- AdminLTE App -->
    <script src="/adminlte/dist/js/app.min.js" type="text/javascript"></script>

    <!-- Laravel Javascript Validation -->
    <script type="text/javascript" src="{{ asset('vendor/jsvalidation/js/jsvalidation.js')}}"></script>

    <!-- Include the jsvalidation generated script -->
    {!! $validator->selector('#formLogin') !!}
</body>

</html>

AuthController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;

use App\Models\User;
use JsValidator;

class AuthController extends Controller
{
    // Method for displaying the input form
    public function showLoginForm()
    {
        $validator = JsValidator::make([
            'username' => 'required',
            'password' => 'required',
        ]);

        return view('auth.login', compact('validator'));
    }

    // Method to handle user login
    public function login(Request $request)
    {
        // Initialize errors array
        $errors = [];

        $validated = $request->validate([
            'username' => 'required',
            'password' => 'required',
        ]);

        // Check the entered user data
        $credentials = $request->only('username', 'password');

        // var_dump(Hash::make($credentials['password']));
        // die();

        // Find the user by username
        $user = User::where('username', $credentials['username'])->first();

        if ($user) {
            // Check if the password matches using bcrypt
            if (Hash::check($credentials['password'], $user->password)) {
                // Password matches, attempt to authenticate the user
                Auth::login($user, $request->has('remember'));
            } else {
                // If password does not match
                $errors['password'] = 'Неправильний Пароль';
            }
        } else {
            // If user not found by username
            $errors['username'] = 'Неправильний Логін';
        }

        // Authentication failed
        return redirect()->back()->withInput($request->only('username', 'remember'))->withErrors($errors);
    }

    // Method for user logout
    public function logout(Request $request)
    {
        Auth::logout();

        $request->session()->invalidate();

        $request->session()->regenerateToken();

        return redirect('/');
    }
}