chern123's avatar

Processing AJAX requests from Vue.js

I was going to use the PHP $_POST variable, but figured there must be a better way of processing the data using Laravel. I tried using Requests, but that didn't seem to work...

Here is my main.js file (temporary took out the 'item' argument and put in a dummy string for the POST request argument):

    new Vue({
        el: "#home",
    
        data:
        {
            v1_user:[],
            v2_user:[],
        },
    
        ready : function()
        {
            this.fetchV1IntermediaryUsers();
            this.fetchV2IntermediaryUsers();
    
        },
    
        methods:
        {
            fetchV1IntermediaryUsers: function()
            {
                this.$http.get('/api/v1_users', function(v1users)
                {
                    this.$set('v1_user',v1users);
                });
            },
    
            fetchV2IntermediaryUsers: function()
            {
                this.$http.get('/api/v2_users', function(v2users)
                {
                    this.$set('v2_user',v2users);
                });
            },
    
       onClick: function (item)
{
    this.$http.post('/api/reset_waitlist_v2', item, function (data){
    this.email = data.email;
})
}

Here is the routes excerpt with the non-working code:

post('api/reset_waitlist_v2',function(Request $request)
{
    $email = Request::all();
   return Response::json(array('email' => $email),200);
});

What would be the best way to process the data and use it? Is my attempt at using the Request feature even moderately close?

EDIT:

The view file:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
        <meta name="description" content="">
        <meta name="author" content="">
        <meta name="csrf-token" content="{{ csrf_token() }}" />
        <link rel="icon" href="../../favicon.ico">
    
        <title>Navbar Template for Bootstrap</title>
    
        <!-- Bootstrap core CSS -->
        <link media="all" type="text/css" rel="stylesheet" href="{{ URL::asset('css/bootstrap.min.css') }}">
        <!-- Custom styles for this template -->
        {!! Html::style('css/navbar.css') !!}
    </head>
    
    <body id = "home">
    <div class="container">
        <!-- Static navbar -->
        <nav class="navbar navbar-default">
            <div class="container-fluid">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                        <span class="sr-only">Toggle navigation</span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                    <a class="navbar-brand" href="#">User Password Operations</a>
                </div>
                <div id="navbar" class="navbar-collapse collapse">
                    <ul class="nav navbar-nav">
                        <li class="inactive"><a href="#">Reset New User</a></li>
                        <li class="inactive"><a href="#">Pending Users</a></li>
                    </ul>
                </div><!--/.nav-collapse -->
            </div><!--/.container-fluid -->
        </nav>
    
        <!-- Main component for a primary marketing message or call to action -->
        <div class="jumbotron">
            <h1>Pending 1.0 Users</h1>
            <p>A list of 1.0 users that have a change!me password as a result of this tool, and are awaiting password change.</p>
        </div>
    
        <table class="table table-bordered" id = "user">
            <tr>
                <td>
                    <b>Name</b>
                </td>
                <td>
                    <b>Email</b>
                </td>
                <td>
                    <b>Select</b>
                </td>
            </tr>
            <div>
                <tr v-repeat = "usr: v1_user">
                    <td>
                        @{{ usr.first_name }}
                    </td>
                    <td>
                        @{{ usr.email_address }}
                    </td>
                    <td>
                        <button type="button" class="btn btn-success" v-on="click: onClick(usr.email_address)">Revert Password To Original</button>
                    </td>
                </tr>
            </div>
        </table>
       <div class="jumbotron">
             <h1>Pending 2.0 Users</h1>
             <p>A list of 2.0 users that have a change!me password as a result of this tool, and are awaiting password change.</p>
         </div>
         <table class="table table-bordered">
             <tr>
                 <td>
                     <b>Name</b>
                 </td>
                 <td>
                     <b>Email</b>
                 </td>
                 <td>
                     <b>Select</b>
                 </td>
             </tr>
             <tr v-repeat = "usr: v2_user">
                 <td>
                     @{{ usr.first_name }}
                 </td>
                 <td>
                     @{{ usr.email_address }}
                 </td>
                 <td>
                     <button type="button" class="btn btn-success" v-on="click: onClick(usr.email_address)">Revert Password To Original</button>
                 </td>
             </tr>
         </table>
    </div> <!-- /container -->
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <script>
        $.ajaxSetup({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            }
        });
    </script>
    <!-- Vue.js file REP  -->
    <script src="/js/vue.js"></script>
    <script src="/js/vue-resource.min.js"></script>
    <!-- Main Vue file-->
    <script src="/js/main.js"></script>
    </body>
    </html>

The HTML of the error page that Laravel returns when inspecting the console via firebug: http://pastebin.com/kKxuziwt

0 likes
13 replies
handy_man's avatar

If you get data from your request you can then save it to a variable in vue like so

 onClick: function (item)
{
    this.$http.post('/api/reset_waitlist_v2', item, function (data){
    this.email = data.email;
})
}

you can send the data like this (I usually encode them as json)

post('api/reset_waitlist_v2',function(Request $request)
{
    $email = Request::all();
   return json_encode(['email' => $email])
});
travoltron's avatar

See above:

I also like to use the built in Response class so I can also add HTTP response codes:

post('api/reset_waitlist_v2',function(Request $request)
{
    $email = Request::all();
   return Response::json(array('email' => $email),200);
});
chern123's avatar

Thanks a ton for the response! I've been working at it and managed to get a bit closer - now running into TokenMismatchException...

Any ideas? So close!

topvillas's avatar

Two ways to handle the token mismatch. Put the hidden form field on the page as usual then grab the value and send it as a header with vue-resource. Or disable the CSRF middleware

vitorarjol's avatar
Level 10

@mdobrenko To handle the exception, you can do the following:

#Put this in the <head> element
{{-- This is the token Laravel requires for non-GET requests --}}
    <meta id="_token" value="{{ csrf_token() }}"> 

If you are using the Vue http lib, use this code to include the token:

Vue.http.headers.common['X-CSRF-TOKEN'] = document.querySelector('#token').getAttribute('value');

If you are using jQuery, use this code:

<script>
        $.ajaxSetup({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            }
        });
</script>
vdhjonas's avatar

I'm having a relevant problem: https://github.com/jonasvanderhaegen/jonasvanderhaegen.be/blob/master/resources/views/pages/misc/realtime-app.blade.php#L311

below as you can see i'm using self.$http.put('/items/'+task.id, {done:!task.done}); self.$http.delete('/items/'+task.id , task );

put it keeps saying it doesn't find it with a 404 while the route resource is there. I don't get it. And it's not coming after any wildcard route.

The weird thing is: on my local server this works fine, on my productions server it doesn't. except for post for adding tasks, that works too. I ftp'd the whole laravel project like 5 times.

vdhjonas's avatar

@vitorarjol I tried that too yes, even with Route::put('test','TodoAppController@update'); it doesn't wants to find it while on a local server it will.

vdhjonas's avatar

@vitorarjol nope, i'll save that for last. So strange.

Am I supposed to add _method : ''PUT" to the data and turn self.$http.put into post then?

vdhjonas's avatar

@vitorarjol well, that seems to be it. If I add _method : PUT or DELETE to the data and change both to "this.$http.post" it works.

ctf0's avatar

@vitorarjol maybe this should be

Vue.http.headers.common['X-CSRF-TOKEN'] = document.querySelector('#_token').getAttribute('value');

& for jquery

<meta name="csrf-token" content="{{ csrf_token() }}">
leanwebstart's avatar

This is how it should be defined to get this meta tag...

Vue.http.headers.common['X-CSRF-TOKEN'] = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
1 like

Please or to participate in this conversation.