0

I'm using Laravel 7 with MySQL and Charts.js. I'm not sure how to echo/display the data of two columns ("player_name" and "kills") that's in my MySQL database in the JSON. Usually laravel has a @foreach loop that displays the data like so:

                @php
                  foreach($player_stats as $player) {
                  echo "['".$player->player_name."', ".$player->kills."],";
                  }
                @endphp

but I'm not sure how to use it inside the javascript/JSON. Please help? Here is the error I get and the rest of my code:

Error message:

Facade\Ignition\Exceptions\ViewException
Undefined variable: player_name (View: C:\wamp64\www\GeneralTesting\resources\views\show-players.blade.php)

PlayerController.php:

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Player;

class PlayerController extends Controller
{
    public function playerstats() {
        $player_stats = Player::all();
        return view("show-players", compact("player_stats"));
    }
}

Route file (web.php):

Route::get("players", "PlayerController@playerStats");

View (show-players.blade.php):

<!DOCTYPE html>
<html lang="en">

<head>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>Simple Sidebar - Start Bootstrap Template</title>

    <!-- Bootstrap core CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

    <!-- Custom styles for this template -->
    <link href="../assets/css/simple-sidebar.css" rel="stylesheet">

    <style type="text/css">


        #chart-container {
            width: 100%;
            height: auto;
        }
    </style>

    <!-- CHARTS MIS JS scripts -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js" integrity="sha256-R4pqcOYV8lt7snxMQO/HSbVCFRPMdrhAFMH+vr9giYI=" crossorigin="anonymous"></script>

<!--     <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.0.0-alpha1/js/bootstrap.bundle.min.js" integrity="sha256-U1mGlmAJ9EtQbmI39+qR12ar8kk5Zm2zskTIUmwCS88=" crossorigin="anonymous"></script> -->

</head>

<body>

    <div class="d-flex" id="wrapper">

        <!-- Sidebar -->
        <div class="bg-light border-right" id="sidebar-wrapper">
            <div class="sidebar-heading">Start Bootstrap </div>
            <div class="list-group list-group-flush">
                <a href="#" class="list-group-item list-group-item-action bg-light">Dashboard</a>
                <a href="#" class="list-group-item list-group-item-action bg-light">Shortcuts</a>
                <a href="#" class="list-group-item list-group-item-action bg-light">Overview</a>
                <a href="#" class="list-group-item list-group-item-action bg-light">Events</a>
                <a href="#" class="list-group-item list-group-item-action bg-light">Profile</a>
                <a href="#" class="list-group-item list-group-item-action bg-light">Status</a>
            </div>
        </div>
        <!-- /#sidebar-wrapper -->

        <!-- Page Content -->
        <div id="page-content-wrapper">

            <nav class="navbar navbar-expand-lg navbar-light bg-light border-bottom">
                <button class="btn btn-primary" id="menu-toggle">Toggle Menu</button>

                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>

                <div class="collapse navbar-collapse" id="navbarSupportedContent">
                    <ul class="navbar-nav ml-auto mt-2 mt-lg-0">
                        <li class="nav-item active">
                            <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link" href="#">Link</a>
                        </li>
                        <li class="nav-item dropdown">
                            <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                                Dropdown
                            </a>
                            <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
                                <a class="dropdown-item" href="#">Action</a>
                                <a class="dropdown-item" href="#">Another action</a>
                                <div class="dropdown-divider"></div>
                                <a class="dropdown-item" href="#">Something else here</a>
                            </div>
                        </li>
                    </ul>
                </div>
            </nav>



            <div class="container">
                <div class="row">
                    <div class="col">
                        COL 1

        <!-- CHART.JS HTML ETC -->
        <div id="chart-container">
            <canvas id="graphCanvas"></canvas>
        </div>


<script>
 var ctx = document.getElementById('graphCanvas').getContext('2d');
  var myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: {!! json_encode($player_name) !!},
        datasets: [{
            label: 'player name',
            data: {!! json_encode($kills) !!},
            backgroundColor: ['rgba(255, 99, 132, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(255, 206, 86, 0.2)',
                'rgba(75, 192, 192, 0.2)',
                'rgba(153, 102, 255, 0.2)',
                'rgba(255, 159, 64, 0.2)'
            ],
            borderColor: [
                'rgba(255, 99, 132, 1)',
                'rgba(54, 162, 235, 1)',
                'rgba(255, 206, 86, 1)',
                'rgba(75, 192, 192, 1)',
                'rgba(153, 102, 255, 1)',
                'rgba(255, 159, 64, 1)'
            ],
            borderWidth: 1
        }]
    },
    options: {
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero: true
                }
            }]
        }
    }
});
</script>



        <!--END OF  CHART.JS HTML ETC -->

                    </div>
                    <div class="col-md-auto">
                       COL 2
                    </div>
                    <div class="col col-lg-2">
                        COL 3
                    </div>
                </div>
            </div>


        </div>
        <!-- /#page-content-wrapper -->

    </div>
    <!-- /#wrapper -->


    <!-- BOOSTRAP JS FOR DROP DOWN MENU -->
     <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>

    <!-- Menu Toggle Script -->
    <script>
        $("#menu-toggle").click(function(e) {
            e.preventDefault();
            $("#wrapper").toggleClass("toggled");
        });
    </script>

</body>

</html>
KD_Raj
  • 189
  • 3
  • 16
  • Does this answer your question? [How to Decode Json object in laravel and apply foreach loop on that in laravel](https://stackoverflow.com/questions/29070907/how-to-decode-json-object-in-laravel-and-apply-foreach-loop-on-that-in-laravel) – 4givN Jun 18 '20 at 00:55
  • it's a bit abstract for me. I'm looking at it – KD_Raj Jun 18 '20 at 01:05
  • basically I'm trying to apply a foreach on the JSON `labels: {!! json_encode($player_name) !!}` and `data: {!! json_encode($kills) !!},` – KD_Raj Jun 18 '20 at 01:15
  • Where are you passing $player_name variable to the view? – Vinayak Sarawagi Jun 18 '20 at 01:31
  • yes. it echoes if I do `@php foreach($player_stats as $player) { echo "['".$player->player_name."', ".$player->kills."],"; } @endphp` but I can't figure out how to do this same type of behaviour in the json – KD_Raj Jun 18 '20 at 01:35
  • To traverse through it, you need to handle it in Javascript only, you can only pass a variable from PHP to JS. – Vinayak Sarawagi Jun 18 '20 at 01:41
  • what would be the equivalent in js? it looks like my problem is i'm not clear on how to jump from php to another language in this case js/json. Or how to access mysql data in the js – KD_Raj Jun 18 '20 at 01:43
  • so you want one array containing arrays containing player_name and kills right ? – N69S Jun 18 '20 at 01:50
  • yes @N69S I am makiing progress. For instance I was able to echo the mysql data in the console log using this: `` Now if I could only display the columns I want in the view – KD_Raj Jun 18 '20 at 02:51

3 Answers3

1

Try mapping your result in the format you want first

class PlayerController extends Controller
{
    public function playerstats() {
        $players = Player::all();
        $player_names = $players->pluck('player_name');
        $player_kills = $players->pluck('kills');
        return view("show-players", compact(['player_names', 'players', 'player_kills']));
    }
}

Then simple @json it on the javascript

<script >
var player_kills = @json($player_kills);

var kills = [player_kills];

var player_names = @json($player_names);

var p_names = [player_names];

var ctx = document.getElementById('graphCanvas').getContext('2d');
var myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: p_names[0],
        datasets: [{
            label: 'player name',
            data: kills[0],
            backgroundColor: ['rgba(255, 99, 132, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(255, 206, 86, 0.2)',
                'rgba(75, 192, 192, 0.2)',
                'rgba(153, 102, 255, 0.2)',
                'rgba(255, 159, 64, 0.2)'
            ],
            borderColor: [
                'rgba(255, 99, 132, 1)',
                'rgba(54, 162, 235, 1)',
                'rgba(255, 206, 86, 1)',
                'rgba(75, 192, 192, 1)',
                'rgba(153, 102, 255, 1)',
                'rgba(255, 159, 64, 1)'
            ],
            borderWidth: 1
        }]
    },
    options: {
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero: true
                }
            }]
        }
    }
}); 
</script>
KD_Raj
  • 189
  • 3
  • 16
N69S
  • 16,110
  • 3
  • 22
  • 36
  • It looks like you are on to something but I get this error `ErrorException: array_map(): Expected parameter 2 to be an array, object given` – KD_Raj Jun 18 '20 at 02:00
  • Player::all() returns Collection and not array. You need to use map method to traverse it. https://laravel.com/docs/7.x/collections#method-map – Vinayak Sarawagi Jun 18 '20 at 02:07
  • This can help you to understand difference between ```all()``` and ```toArray()``` - https://stackoverflow.com/questions/43287573/difference-between-all-and-toarray-in-laravel-5 – Abhishek Honrao Jun 18 '20 at 03:54
  • @kevind just add `toArray()` method to the collection. – N69S Jun 18 '20 at 10:55
  • @N69S, I'm not sure where to add toArray() I get a number of unrelated error messages – KD_Raj Jun 18 '20 at 12:20
  • @kevind already edited my answer for the `toArray()` – N69S Jun 18 '20 at 14:54
  • @N69S copied over your code and got `Error Call to a member function map() on array` – KD_Raj Jun 18 '20 at 15:47
  • `Error Call to a member function array_map() on array` – KD_Raj Jun 18 '20 at 15:57
  • @kevind my bad, didnt remove the whole edit. now it should work – N69S Jun 18 '20 at 20:03
  • @N69S I made a small change to your console.log code. But my next question is how to echo a specific column in the view i.e. JSON i.e. not in console.log. Eg like the $player_stats->player_name ? – KD_Raj Jun 18 '20 at 22:25
  • For example in the View file where I have `labels: {!! json_encode($player_name) !!},` and `data: {!! json_encode($kills) !!},` in the view. – KD_Raj Jun 18 '20 at 22:40
  • @kevind you can simply send the `$players` variable to the view, alongside the `$player_stats` variable, to be used in a loop (edited above) – N69S Jun 18 '20 at 23:43
  • @N69S The loop would be ideal but since I could not figure that part out I submitted my own answer (see below). But I believe your solution with the loop would be ideal ( I avoided the loop in my workaround) – KD_Raj Jun 19 '20 at 00:33
  • @kevind got you a simpler version for the controller, this version also keeps the `$players` as a collection. – N69S Jun 19 '20 at 03:35
  • @N69S, `pluck()` seems to work without `toArray()`. See edited code. – KD_Raj Jun 19 '20 at 11:57
  • 1
    @kevind `toArray()` is forced on bny the `@json` in the view. without the `toArray()`, if you do `{!! json_encode() !!}` you will get the object version. but yeah in this case it seems the same but no performance change in the end. a `toArray()` is called in both versions. – N69S Jun 19 '20 at 16:06
0

I avoided the loop but got the chart.js bar chart to work correctly (refactoring needed)

Controller (PlayerController.php):

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Player;

class PlayerController extends Controller
{
    public function playerstats() {
        // $players = Player::all();
        $players = Player::all()->toArray();
        $player_kills = array_map(function($player) {
          return $player['kills'];
        }, $players);
        $player_names = array_map(function($player) {
          return $player['player_name'];
        }, $players);
        // return view("show-players", compact("player_stats"));
        return view("show-players", compact(['player_kills',
                                             'players',
                                             'player_names']));
    }
}

View (show-player.blade.php)

<script >
    var player_kills = @json($player_kills);
// console.log(player_kills); 
var kills = [player_kills];

var player_names = @json($player_names);
// console.log(player_names); 
var p_names = [player_names];

var ctx = document.getElementById('graphCanvas').getContext('2d');
var myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: p_names[0],
        datasets: [{
            label: 'player name',
            data: kills[0],
            backgroundColor: ['rgba(255, 99, 132, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(255, 206, 86, 0.2)',
                'rgba(75, 192, 192, 0.2)',
                'rgba(153, 102, 255, 0.2)',
                'rgba(255, 159, 64, 0.2)'
            ],
            borderColor: [
                'rgba(255, 99, 132, 1)',
                'rgba(54, 162, 235, 1)',
                'rgba(255, 206, 86, 1)',
                'rgba(75, 192, 192, 1)',
                'rgba(153, 102, 255, 1)',
                'rgba(255, 159, 64, 1)'
            ],
            borderWidth: 1
        }]
    },
    options: {
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero: true
                }
            }]
        }
    }
}); 
</script>
KD_Raj
  • 189
  • 3
  • 16
-2

use this in your controller:

dump($variable);
Angel
  • 1