Home > Blockchain >  Why does the old() method fail in this Laravel 8 form?
Why does the old() method fail in this Laravel 8 form?

Time:03-27

I am making a blogging application with Laravel 8 and Bootstrap 5.

I run into a problem trying to validate my "Add new article" form: when the form fails validation, the valid fields do not keep their values, despite ne using Blade's old() method.

In the controller, I have:

namespace App\Http\Controllers\Dashboard;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;
use App\Models\ArticleCategory;
use App\Models\Article;
use Illuminate\Http\Request;

class ArticleController extends Controller
{
    
    private $rules = [
        'category_id' => ['required', 'exists:article_categories,id'],
        'title' => ['required', 'string', 'max:255'],
        'short_description' => ['required', 'string', 'max:255'],
        'image' => ['mimes: jpeg, jpg, png, gif', 'max:2048'],
        'content' => ['required', 'string']
    ];

    private $messages = [
        'category_id.required' => 'Please pick a category for the article',
        'title.required' => 'Please provide a title for the article',
        'short_description.required' => 'The article needs a short description',
        'content.required' => 'Please add content'
    ];
    
    public function categories() {
        return ArticleCategory::all();
    }
    
    public function index() {
        $articles = Article::paginate(10);

        return view('dashboard/articles',
            ['articles' => $articles]
        );
    }

    public function create() {
        // Load the view and populate the form with categories
        return view('dashboard/add-article',
            ['categories' => $this->categories()]
        );
    }

    public function save(Request $request) {

        // Validate form (with custom messages)
        $validator = Validator::make($request->all(), $this->rules, $this->messages);

        if ($validator->fails()) {
            return redirect()->back()->withErrors($validator->errors());
        }

        $fields = $validator->validated();

        // Upload article image
        $current_user = Auth::user();

        if (isset($request->image)) {
            $imageName = md5(time()) . $current_user->id . '.' . $request->image->extension();
            $request->image->move(public_path('images/articles'), $imageName);
        }

        // Data to be added
        $form_data = [
            'user_id' => Auth::user()->id,
            'category_id' => $fields['category_id'],
            'title' => $fields['title'],
            'slug' => Str::slug($fields['title'], '-'),
            'short_description' => $fields['short_description'],
            'content' => $fields['content'],
            'image' => $fields['image'],
            'featured' => $fields['featured']
        ];

        // Insert data in the 'articles' table
        $query = Article::create($form_data);

        if ($query) {
            return redirect()->route('dashboard.articles')->with('success', 'Article added');
        } else {
            return redirect()->back()->with('error', 'Adding article failed');
        }

    }
}

The form:

<form method="POST" action="{{ route('dashboard.articles.add') }}">
    @csrf
    <div >
            <label for="title" >{{ __('Title') }}</label>

            <div >
                    <input id="title" type="text" placeholder="Title"  name="title" value="{{ old('title') }}" autocomplete="title" autofocus>

                    @error('title')
                        <span  role="alert">
                            <strong>{{ $message }}</strong>
                        </span>
                    @enderror
            </div>
    </div>

    <div >
            <label for="short_description" >{{ __('Short description') }}</label>

            <div >
                    <input id="short_description" type="text" placeholder="Short description"  name="short_description" value="{{ old('short_description') }}" autocomplete="short_description" autofocus>

                    @error('short_description')
                        <span  role="alert">
                            <strong>{{ $message }}</strong>
                        </span>
                    @enderror
            </div>
    </div>

    <div >
        <label for="category" >{{ __('Category') }}</label>
    
        <div >
    
            <select name="category_id" id="category" >
                <option value="0">Pick a category</option>
                @foreach($categories as $category)
                    <option value="{{ $category->id }}">{{ $category->name }}</option>
                @endforeach
            </select>
                
                @error('category_id')
                    <span  role="alert">
                        <strong>{{ $message }}</strong>
                    </span>
                @enderror
        </div>
    </div>

    <div >
        <div >
                <p >Featured article?</p>
                <input  type="checkbox" name="featured" id="featured">
                <label  for="featured">{{ __('Toggle') }}</label>
        </div>
    </div>

    <div >
        <label for="image" >{{ __('Article image') }}</label>
    
        <div >
            <input type="file" name="image" id="file" >
    
            @error('image')
                <span  role="alert">
                    <strong>{{ $message }}</strong>
                </span>
            @enderror
        </div>
    </div>

    <div >
        <label for="content" >{{ __('Content') }}</label>

        <div >

            <textarea name="content" id="content"  placeholder="Content" cols="30" rows="6">{{ old('content') }}</textarea>

            @error('content')
                <span  role="alert">
                    <strong>{{ $message }}</strong>
                </span>
            @enderror
        </div>
    </div>
    
    <div >
            <div >
                    <button type="submit" >
                            {{ __('Save') }}
                    </button>
            </div>
    </div>
</form>

The routes:

// Article routes
Route::group(['prefix' => 'articles'], function() {
    Route::get('/', [ArticleController::class, 'index'])->name('dashboard.articles');
    Route::get('/new', [ArticleController::class, 'create'])->name('dashboard.articles.new');
    Route::post('/add', [ArticleController::class, 'save'])->name('dashboard.articles.add');
    Route::get('/delete/{id}', [ArticleController::class, 'delete'])->name('dashboard.articles.delete');
}); 

The problem:

I was expecting this syntax for keeping the values of valid fields in an invalid form, should work: value="{{ old('title') }}". But, fo a reason I have been enable to spot, it does not. The form is reset entirely.

What is my mistake?

CodePudding user response:

You're redirecting back to the previous page without telling Laravel to pass the old inputs. Use the method withInput() with the route return.

Change

return redirect()->back()->withErrors($validator->errors()); 

with

 return redirect()->back()->withErrors($validator->errors())->withInput();
  • Related