Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

warpig's avatar
Level 12

Display 1 video from a collection inside a view

I want to be able to pass the location of a resource, it could be 0, 1, 2, 3, store it inside an href and check it against a foreach loop.

 0 => array:8 [▶]
  1 => array:6 [▶]
  2 => array:6 [▶]
  3 => array:6 [▶]

The foreach loop will most likely have 1 value, a dynamic youtube url with the ID as the dynamic content. But I can't wrap my head around the concept, it might be simple for some. I have a Controller with a function and im attempting to fetch this array like this:

    public function show()
    {
        $thps4Videos = Http::get('http://thvid-api.herokuapp.com/videos/game/THPS4')->json();
        dd($thps4Videos);

        return view ('videos.show', compact('thps4Videos'));
    }

So anytime this gets a request I will only get the column for the "id" value, I'd have to associate it with the location from the collection array, and display it on this view, videos.show by associating the position and the value of the column id.

The goal is to display 1 video for each array from the collection in 1 page.

This is one example of 1 array:

  0 => array:8 [▼
    "_id" => "605a43ea667cd39060f435ac"
    "Title" => "THPS4 Rewind: Summer Of 2003 Unreleased (Edited by Maxfli)"
    "Game" => "THPS4"
    "ID" => "Qxd7D1KN1No"
    "Thumbnail" => "https://i.ytimg.com/vi_webp/Qxd7D1KN1No/maxresdefault.webp"
    "newduration" => "00:22:53"
    "category" => "gameplay"
    "updatedAt" => "2021-04-12T17:45:27.167Z"
  ]

The column that can bring me to the video is ID, so the dynamic URL would have to be something like this:

https://www.youtube.com/watch?v={{ $thps4Videos['ID'] }}
´´´
0 likes
30 replies
neilstee's avatar

@warpig sorry but I think I'm lost what is the real question here. Based on your current setup, can you explain in simple terms the problem and what do you need?

warpig's avatar
Level 12

Ok, so from this list of videos that I get from this API, I want to be able to view just 1 video. Very similar to when you make a list of posts and you pass the ID or the slug of the post, and you use this value (either the Id or the slug) inside an href and you pass the variable, then when you're on the show.blade.php you can view that single post.

neilstee's avatar

@warpig and that would be the first video on the list?

Can you try this:

public function show()
{
	$thps4Videos = Http::get('http://thvid-api.herokuapp.com/videos/game/THPS4')->json();

	$thps4Video =  $thps4Videos[0]['ID'];

	return view ('videos.show', compact('thps4Video'));
}

and in your blade:

https://www.youtube.com/watch?v={{ $thps4Video['ID'] }}

or you need a checking if the first array doesn't contain ID?

warpig's avatar
Level 12

I probably should @neilstee

This line will iterate through all from that get request?

$thps4Video = $thps4Videos[0]['ID'];

What value should then get passed in the href, I probably should have mentioned this, because I am already displaying information about the video inside a foreach, and its coming from a different component, Livewire.

Then I think all I would have to do is to change the variable, for example this is that component:

<?php

namespace App\Http\Livewire;

use Livewire\Component;
use Illuminate\Support\Facades\Http;

class Thps4 extends Component
{
    public $thps4Results = [];

    public function loadTHPS4()
    {
        $response = Http::get('http://thvid-api.herokuapp.com/videos/game/THPS4/1/21')->json();
        $this->thps4Results = collect($response);
    }

    public function render()
    {
        return view('livewire.thps4');
    }
}

Thanks, I will try

neilstee's avatar

@warpig sorry $thps4Video = $thps4Videos[0]['ID']; should be $thps4Video = $thps4Videos[0];

And in your blade you can do this:

https://www.youtube.com/watch?v={{ $thps4Results->first()['ID'] }}
warpig's avatar
Level 12

I get this:

Call to a member function first() on string

Is it because I have to pass a variable first on the a tag? How else would it know which video I want to select from the collection? This is my foreach:

    @foreach($thps4Video as $thps4)
        <script>
            var player = videojs('vid1', { 
                "techOrder": ["youtube"], 
                "sources": [{ "type": "video/youtube", 
                "src": "https://www.youtube.com/watch?v={{ $thps4->first()['ID'] }}"}], 
                "fluid": true,
                "autoplay": true
            });
            player.ready(function() {
                setTimeout(function() {
                    player.autoplay('muted');
                    player.volume(0.5);
                    player.fluid('true')
                }, 2000);
            });
        </script>
    @endforeach
neilstee's avatar

@warpig I thought you only want to show the first video? so you don't need foreach in this case, just do:

<script>
            var player = videojs('vid1', { 
                "techOrder": ["youtube"], 
                "sources": [{ "type": "video/youtube", 
                "src": "https://www.youtube.com/watch?v={{ $thps4Results->first()['ID'] }}"}], 
                "fluid": true,
                "autoplay": true
            });
            player.ready(function() {
                setTimeout(function() {
                    player.autoplay('muted');
                    player.volume(0.5);
                    player.fluid('true')
                }, 2000);
            });
        </script>
warpig's avatar
Level 12

Sorry for that, yes I would like to view any video in this page whenever a user clicks on a button, it should see this variable and then be able to watch that.

This is the result of that:

Call to a member function first() on array 
neilstee's avatar

@warpig

Ok, so from this list of videos that I get from this API, I want to be able to view just 1 video. Very similar to when you make a list of posts and you pass the ID or the slug of the post, and you use this value (either the Id or the slug) inside an href and you pass the variable, then when you're on the show.blade.php you can view that single post.

Okay, I think I know what you wanted:

public function render()
{
	// you get all the list here
	$thps4Videos = Http::get('http://thvid-api.herokuapp.com/videos/game/THPS4')->json();

	return view ('videos.index', compact('thps4Videos'));
}

public function show($id)
{
	$thps4Videos = Http::get('http://thvid-api.herokuapp.com/videos/game/THPS4')->json();

	$thps4Video = $thps4Videos[$id]; // which is an index

	return view ('videos.show', compact('thps4Video'));
}

then in your show blade:

{{ $thps4Video['ID'] }}
{{ $thps4Video['Title'] }}
etc...
neilstee's avatar

@warpig and in your index blade you list something like this:

@foreach($videos as $key => $video)
<a href="/video/{{ $key }}">Show</a>
@endforeach
neilstee's avatar

I hope we are on the same page now @warpig . I think this is a simple loop issue but it's very hard when we both have a different view on the issue 😅

1 like
warpig's avatar
Level 12

Yea that seems more like it, but I have one question the $id is it that like a reference to the actual column on the collection from the API or should it come from the index? I don't know what to put in index()... Im not storing them anywhere, they are coming from the API.

neilstee's avatar

@warpig you can use ID if you want to. Do you see any issues if you use the index instead of ID?

neilstee's avatar

@warpig sorry but index should be render() since this is Livewire and render doesn't need an id. I edited my answer.

The show() method only has an $id which is a key index on the loop in your blade

warpig's avatar
Level 12

On that livewire component I already have this: <a class="relative bottom-4" href="play/{{$thps4['ID']}}"> ok..

Do you see any issues if you use the index instead of ID?

Not sure I follow, the index method instead of the ID column?

warpig's avatar
Level 12

@neilstee Can I show you what I already have in the Livewire? Having difficulties understanding how to reformat what's already in there...

warpig's avatar
Level 12
<?php

namespace App\Http\Livewire;

use Livewire\Component;
use Illuminate\Support\Facades\Http;

class Thps4 extends Component
{
    public $thps4Results = [];

    public function loadTHPS4()
    {
        $response = Http::get('http://thvid-api.herokuapp.com/videos/game/THPS4/1/21')->json();
        $this->thps4Results = collect($response);
    }

    public function render()
    {
        return view('livewire.thps4');
    }
}

This is the view:

        @forelse ($thps4Results as $thps4)
            <div wire:key="results-{{ $thps4['_id'] }}">
                <img
                    src="{{ $thps4['Thumbnail'] }}">
                    <div>
                        <a href="play/{{$thps4['ID']}}">
                            <svg>
                            </svg>
                        </a>

                        <p>
                            {{ $thps4['Title'] }}
                        </p>
                    </div>
            </div>
        @empty
            @foreach (range(1,6) as $thumbnail)
                <div>
                    <p>loading</p>
                </div>
            @endforeach
        @endforelse
warpig's avatar
Level 12

The only thing I have regarding that is this: Route::get('/play', [PlayVideosController::class, 'show'])->name('videos.show'); how should I work with this?

warpig's avatar
Level 12

Videos show is where I have to pass the variable of $thps4 you've already seen it, it's this part:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link href="//vjs.zencdn.net/7.10.2/video-js.min.css" rel="stylesheet">
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
    <script src="{{ asset('js/app.js') }}" defer></script>
    <title>Document</title>
    <style>
    .video-js .vjs-big-play-button {
        display: none;
    }
    .vjs-waiting .vjs-loading-spinner {
        display: none;
    }
    </style>
</head>
<body class="bg-black">

    <div class="pt-20 h-full w-screen">
        <video
            id="vid1"
            class="video-js"
            controls
            autoplay="true"
            preload="auto"
        >
      </video>

        <div
            x-data="{close: true}"
            x-show="close"
            class="text-center"
        >
            <p class="text-sm text-gray-500">
              Mute is enabled by default, sorry for the inconveniences
            </p>
            <p 
                x-on:click="close = false"
                class="text-green-500 text-sm cursor-pointer"
            >
                close
            </p>
        </div> {{-- inconveniences message --}}

    </div>
    
    <!-- videojs -->
    <script src="//vjs.zencdn.net/7.10.2/video.min.js"></script>
    <script src="{{ asset ('/js/Youtube.min.js') }}"></script>
    
        <script>
            var player = videojs('vid1', { 
                "techOrder": ["youtube"], 
                "sources": [{ "type": "video/youtube", 
                "src": "https://www.youtube.com/watch?v={{ $thps4Video->first()['ID'] }}"}], 
                "fluid": true,
                "autoplay": true
            });
            player.ready(function() {
                setTimeout(function() {
                    player.autoplay('muted');
                    player.volume(0.5);
                    player.fluid('true')
                }, 2000);
            });
        </script>

</body>
</html>
neilstee's avatar
neilstee
Best Answer
Level 34

@warpig but my point here is, just change $thps4['ID'] to $key instead.

        @forelse ($thps4Results as $key => $thps4)
            <div wire:key="results-{{ $thps4['_id'] }}">
                <img
                    src="{{ $thps4['Thumbnail'] }}">
                    <div>
                        <a href="play/{{ $key }}">
                            <svg>
                            </svg>
                        </a>

                        <p>
                            {{ $thps4['Title'] }}
                        </p>
                    </div>
            </div>
        @empty
            @foreach (range(1,6) as $thumbnail)
                <div>
                    <p>loading</p>
                </div>
            @endforeach
        @endforelse

so in your /play/{$id} you can show the video like this:

public function show($id)
{
	$thps4Videos = Http::get('http://thvid-api.herokuapp.com/videos/game/THPS4/1/21')->json();

	$thps4Video = $thps4Videos[$id]; // which is an index

	return view ('videos.show', compact('thps4Video'));
}

and actually, I just notice that http://thvid-api.herokuapp.com/videos/game/THPS4/1/21 is modifiable using an index and how many records, so you can even get better performance using $key like this:

public function show($id)
{
	$id++;
	$thps4Videos = Http::get('http://thvid-api.herokuapp.com/videos/game/THPS4/$id/1')->json();

	$thps4Video = $thps4Videos[0]; // get the first one 

	return view ('videos.show', compact('thps4Video'));
}

so you don't need to load ALL

neilstee's avatar

@warpig and in your videos.show blade you only do this:

<script>
            var player = videojs('vid1', { 
                "techOrder": ["youtube"], 
                "sources": [{ "type": "video/youtube", 
                "src": "https://www.youtube.com/watch?v={{ $thps4Video['ID'] }}"}], 
                "fluid": true,
                "autoplay": true
            });
            player.ready(function() {
                setTimeout(function() {
                    player.autoplay('muted');
                    player.volume(0.5);
                    player.fluid('true')
                }, 2000);
            });
        </script>

1 like
neilstee's avatar

I even tried it on my local and everything is perfectly working. 😅 much faster than fetching ALL the results. use the index and get only 1 item when you show it on the play route.

1 like
warpig's avatar
Level 12

Oh that's awesome, check this, so now my URL's are pointing to an array, and it matches! https://imgur.com/62leXW0 :-)

Did you also get to watch a video? Maybe you couldn't do that since you probably don't have the plug-in but I do get a 404 when I click on the href, thanks for guiding me I appreciate all and any help I can get :-)

neilstee's avatar

@warpig glad it works and you got better performance too on that new implementation!

Don't forget to mark an answer "Best Reply" if that solves your issue so others can find it helpful as well 😉

1 like
warpig's avatar
Level 12

Yea, a little tough since it was more of a progression ! But I will try my best.

Please or to participate in this conversation.