Andy
Andy

Reputation: 5404

CakePHP 3.x Flash messages for ajax requests

I have an application written in CakePHP 3.5.13

It makes use of the Flash Component built into Cake. All of this is working when configured in the standard way, e.g.

// src/Controller/SomeController.php
public function foo()
{ 
    $this->Flash->set('Records updated', ['element' => 'success']);
    return $this->redirect(['action' => 'index']);
}

// src/Template/SomeController/index.ctp
<?= $this->Flash->render() ?>

So if I access /some-controller/foo it will set the flash message, reload index.ctp and display it.

However, I want to modify things so that it's all done via ajax calls.

If I create a new template, /src/Template/SomeController/index.ctp and use the following jquery:

$('.foo-test').click(function(e) {
    e.preventDefault();

    $.ajax({
        url: '/some-controller/foo'
    }).done(response) {
       //console.log(response);
       window.location.href = '/some-controller/index'; 
    });
});

When I click on an anchor with the class .foo-test it will make the ajax request.

But reloading the page (window.location.reload) doesn't display the flash message. Why is this, because that's equivalent to the browser reloading /some-controller/index, right?

The only way I can think to modify this is to have foo() return a JSON response. Where I've used console.log(response) I could then access the response data and determine the outcome, then add the flash message, e.g.

 if (response.success !== '') {
     $('#outcome').html(response.success).addClass('alert alert-success');
 }

Which would write the response message to a div with the ID #outcome and add the appropriate classes for styling purposes.

Surely there is a better way than this, as it would involve rewriting every single method where I needed to do this?

Why doesn't executing the controller function followed by reloading the page with jquery work, bearing in mind it can still access the $_SESSION when doing things in this way?

I have looked at plugins but want to know if there's a native Cake way to do this that I'm overlooking? Ajax isn't mentioned in the Flash Component docs.

Upvotes: 1

Views: 1761

Answers (1)

Andy
Andy

Reputation: 5404

Ok, I've figured this out, with help from @ndm in the comments.

The solution is to remove the PHP redirect in SomeController::foo():

public function foo()
{ 
    // There is no template (foo.ctp) associated with this function.
    $this->autoRender = false;

    $this->Flash->set('Records updated', ['element' => 'success']);

    // Remove line below:
    //return $this->redirect(['action' => 'index']);
}

This is because we're doing an equivalent redirect in jquery:

window.location.href = '/some-controller/index'; 

So the ajax request to /some-controller/foo still sets the flash messages. Using the jquery redirect reloads index.ctp which then has the code to render the flash message.

If you're refactoring code to do things in this way, you need to make sure the action equivalent to foo() in this example just sets the flash messages and does not output anything. You can achieve this with $this->autoRender = false and then use $this->Flash->set() as normal to set your messages.

Upvotes: 2

Related Questions