# Shop: detail section

tracks

# Get selected record

  • We will use the wire:click attribute on the Show Tracks icon to pass the id of the selected record to the showTracks method in the component
  • The showTracks method will retrieve the record from the database and store it in a new public property $selectedRecord
  • Add the wire:click attribute to the Show Tracks icon


 




<div class="w-6 cursor-pointer hover:text-red-900">
    <x-phosphor-music-notes-light
        wire:click="showTracks({{ $record->id }})"
        class="outline-0"
        data-tippy-content="Show tracks"/>
</div>
Copied!
1
2
3
4
5
6
  • Instead of only the id we want to store the complete record in the public property $selectedRecord
  • The long way is to query the database for the record with the id and store the result in the public property $selectedRecord
  • But there is a better way: we can use Laravel's Route Model Binding (opens new window) to get the complete record with only the id as a parameter in the method showTracks
  • Line 1: type-hint the parameter $record with the model Record => replace showTracks($record) with showTracks(Record $record)
  • Line 4: dump the property $selectedRecord as an array to the page (add ->toArray())
 


 


public function showTracks(Record $record)
{
    $this->selectedRecord = $record;
    dump($this->selectedRecord->toArray());
}
Copied!
1
2
3
4
5

# Add a modal to the view

  • Now we have the complete record in the public property $selectedRecord, we can use it to pop up a modal
  • Let's start with only the artist, the title of the album and the cover image
  • Paste the following code just before the last closing </div> tag
  • When the page first loads, the property $selectedRecord is empty and to avoid errors, we need to catch this in the model
    • Line 6: if $selectedRecord->title doesn't exist, show the string Title
    • Line 7: if $selectedRecord->artist doesn't exist, show the string Artist
    • Line 10: if $selectedRecord->cover['url] doesn't exist, show a dummy cover image
    • Line 12: if $selectedRecord has no tracks, hide the table
      (We push the tracks later in the array, so for now it doesn't exist)





 
 


 

 
















 



{{-- Detail section --}}
<div class="fixed z-40 inset-0 p-8 grid h-screen place-items-center backdrop-blur-sm backdrop-grayscale-[.7] bg-slate-100/70">
    <div class="bg-white p-4 border border-gray-300 max-w-2xl">
        <div class="flex justify-between space-x-4 pb-2 border-b border-gray-300">
            <h3 class="font-medium">
                {{ $selectedRecord->title ?? 'Title' }}<br/>
                <span class="font-light">{{ $selectedRecord->artist ?? 'Artist' }}</span>
            </h3>
            <img class="w-20 h-20"
                 src="{{ $selectedRecord->cover['url'] ?? asset('storage/covers/no-cover.png') }}" alt="">
        </div>
        @isset($selectedRecord->tracks)
            <table class="w-full text-left align-top">
                <thead>
                <tr>
                    <th class="px-4 py-2">#</th>
                    <th class="px-4 py-2">Track</th>
                    <th class="px-4 py-2">Length</th>
                </tr>
                </thead>
                <tbody>
                <tr class="border-t border-gray-100">
                    <td class="px-4 py-2">........</td>
                    <td class="px-4 py-2">........</td>
                    <td class="px-4 py-2">........</td>
                </tr>
                </tbody>
            </table>
        @endisset
    </div>
</div>
Copied!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# Show and hide the modal with Alpine

  • Luckily for us, Alpine and Livewire work together very well (both frameworks are from the same author)
  • With @entangle we can sync a public property from the Livewire component with an Alpine variable
    • When a property in Livewire changes, the Alpine variable changes too
    • When the Alpine variable changes, the Livewire property changes too
  • This is the technique we're going to use to show and hide the modal
  • Line 2: add a public property $showModal and set it default to false
    (We can use the value of this variable with @entangle('showModal') in Alpine)
  • Line 14: after loading the selected record, set the property $showModal to true








 




 






class Shop extends Component
{
    use WithPagination;

    // public properties
    public $perPage = 6;
    public $loading = 'Please wait...';
    public $selectedRecord;
    public $showModal = false;

    public function showTracks(Record $record)
    {
        $this->selectedRecord = $record;
        $this->showModal = true;
        // dump($this->selectedRecord->toArray());
    }
    
    ...
}
Copied!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# Get all tracks for the selected record

  • Line 4: the URL which contains the mb_id of the selected record
  • Line 5: $response fetches the URL with the Laravel HTTP client (include use Http;) and convert the result to JSON data
    ($response contains all the data from the API, like we can see in the first screenshot of this chapter)
  • Line 6:
    • push a new key tracks to the selected record $this->selectedRecord['tracks']
    • select only the tracks-array in the response ($response['media'][0]['tracks']) and add them to the tracks key
  • Line 7: (temporary) dump and die the selected record, with the tracks, to the page



 
 
 
 



public function showTracks(Record $record)
{
    $this->selectedRecord = $record;
    $url = "https://musicbrainz.org/ws/2/release/{$record->mb_id}?inc=recordings&fmt=json";
    $response = Http::get($url)->json();
    $this->selectedRecord['tracks'] = $response['media'][0]['tracks'];
    dd($this->selectedRecord->toArray());
    $this->showModal = true;
}
Copied!
1
2
3
4
5
6
7
8
9

Tracks from API response

# Show tracks in the modal

  • Line 11 - 17: loop over the tracks and show the title and duration (you don't need a wire:key here, because it's a static list)
  • Line 13 - 55: show the position, the title and the duration (length) of each track










 

 
 
 

 




@isset($selectedRecord->tracks)
<table class="w-full text-left align-top">
    <thead>
    <tr>
        <th class="px-4 py-2">#</th>
        <th class="px-4 py-2">Track</th>
        <th class="px-4 py-2">Length</th>
    </tr>
    </thead>
    <tbody>
    @foreach($selectedRecord['tracks'] as $track)
        <tr class="border-t border-gray-100">
            <td class="px-4 py-2">{{ $track['position'] }}</td>
            <td class="px-4 py-2">{{ $track['title'] }}</td>
            <td class="px-4 py-2">{{ $track['length'] }}</td>
        </tr>
    @endforeach
    </tbody>
</table>
@endisset
Copied!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

dd

  • Don't forget to comment the dump in Livewire/Shop.php!

# Reformat the track length with Carbon

  • The track length is in milliseconds, so we need to convert it to mm:ss
  • You can make a custom function for it that handles the transformation, but we prefer to use the Carbon (opens new window) package for this
    • Carbon is an easy to use PHP extension for date/time manipulation and formatting
    • Carbon is by default installed in in every Laravel project
  • The Carbon method we need is createFromTimestampMs($milliseconds)->format('i:s') (opens new window)
    • createFromTimestampMs creates a Carbon object from a timestamp in $milliseconds
    • format formats the Carbon object to a string
  • Line 6: wrap the length of the song in a Carbon object
  • IMPORTANT
    • Because there is no Blade helper for Carbon, we need to use the full namespace for the class Carbon\Carbon::createFromTimestampMs($milliseconds)->format('i:s')
    • Another option is to use the use statement at the top of the file: @php use Carbon\Carbon; @endphp and then use Carbon::createFromTimestampMs($milliseconds)->format('i:s') in the view





 




<tbody>
@foreach($selectedRecord['tracks'] as $track)
    <tr class="border-t border-gray-100">
        <td class="px-4 py-2">{{ $track['position'] }}</td>
        <td class="px-4 py-2">{{ $track['title'] }}</td>
        <td class="px-4 py-2">{{ \Carbon\Carbon::createFromTimestampMs($track['length'])->format('i:s') }}</td>
    </tr>
@endforeach
</tbody>
Copied!
1
2
3
4
5
6
7
8
9
Last Updated: 11/9/2022, 12:46:12 PM