Question

I am using Laravel Framework 4.1.30.

How do you pass a data from one template to another without passing through route or controller?

Specifics: I got a "Main" blade template that is extended by a "Sign-in" blade template. My objective is to put any errors that appears in the the "Sign-in" template and displayed this to a footer section of the "Main" template.

My codes for main template inside the "body" tag are as follows (note some codes exist in between to format my view):

<!-- Serving as Header -->
@include('layout.navigation')

<!-- Serving as left content/status displays -->
@include('layout.frameleft') 

<!-- Serving as right content/entry point -->
@yield('content')

<!-- Serving as Error Notification/footer -->
@if (Session::has('global'))
      {{ Session::get('global') }}
@endif

The blade template calling the Main is coded like so:

@extends('layout.main')

@section('content')

    ... more code here / input fields ...

    {{ $errors->first('email')}}

    ... more code here / input fields ...

@stop

As I understand it (fairly new to Laravel) the content gets to be read first before the session display global.

I was hoping, a simple variable passing between template would be enough (if it exist) to resolve the problem. I wish to pass the error value from the content back to the main template on the footer section part without going back to controller.

I am aware there are work-arounds, like instead of waiting for controller to output the errors to template, I could pass the errors directly to global variable via session (or to layout) from Controller. Currently the following working code is what I have implemented but I'm just wondering what if the data was passed already to the template.

public function postSignin() {

        $validator = Validator::make(Input::all(),
            array(
                    'email'     => 'required|email',
                    'password'  => 'required'
            )
        ); 

        if ($validator->fails()) {

            $errors = $validator->errors();
            $formErrors = 'Errors: ';

            foreach($errors->all() as $error ) {
                $formErrors .= sprintf("%s", $error);
            }

            return Redirect::route('account-sign-in')
                ->withErrors($validator)
                ->withInput()
                ->with('global',$formErrors);

        } else {

        ...more codes here...

Why I'm doing so is that originally my code at the controller is just like..

        if ($validator->fails()) {

           return Redirect::route('account-sign-in')
              ->withErrors($validator)
              ->withInput();

Now it seem so big. I figure if I can relieve the controller with a loop, my program would be more efficient.

Was it helpful?

Solution

From the Laravel documentation (emphasis theirs):

However, notice that we do not have to explicitly bind the error messages to the view in our GET route. This is because Laravel will always check for errors in the session data, and automatically bind them to the view if they are available. So, it is important to note that an $errors variable will always be available in all of your views, on every request, allowing you to conveniently assume the $errors variable is always defined and can be safely used. The $errors variable will be an instance of MessageBag.

Because Laravel's Redirect... withErrors() method does this, you don't need to add the errors to the Session again by hand. Instead of checking for if (Session::has('global')), just do this:

<!-- Serving as Error Notification/footer -->
@foreach ($errors as $error)
    <p>{{ $error }}</p>
@endforeach

This should work even though it is in the layout and not in the actual view, because binding that applies errors inside the template also applies them outside of it.

If there are no errors, Laravel will just skip that block. If there are errors, they will have been automatically bound to the $errors variable and will be rendered as expected.

OTHER TIPS

I was originally writing up an answer that recommended View Composers, but then I re-read the question and I believe what you need to do is abstract out the form validation to a 'form' class:

interface FormInterface {
    public function isValid($input);
    public function errors();
}

The basic idea I got from your question is that you want your controller to look something like this:

public function postSignIn()
{
    if(!$this->_signinForm->isValid(Input::all())) {
        return Redirect::route('account-sign-in')
            ->withErrors($this->_signinForm->errors())
            ->withInput()
        ;
    }

    // Non-error logic branch
}

Your form class will basically contain a reference to the validator object. All the isValid method should do is basically call passes() on the validator, and all the error method will simply return the results of calling errors() on the validator.

I honestly have no idea why you're actually combining all of the error messages into a single variable, I assume its because you want them all displayed in the same place. If that's the case and that's how you want the errors to function, then you can build that in to your form's errors method.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top