Kimmer

at These Days

Experience

13,210

0 Best Reply Awards

  • Member Since 2 Years Ago
  • 119 Lessons Completed
  • 0 Favorites

16th August, 2018

Kimmer left a reply on Policies Always Results In "This Action Is Unauthorized" • 1 month ago

I read somewhere that one should not pass the items ID to the client for security reasons. That's why I started using this Hash ID component. I wouldn't know how to do this "Spot::byHashid($hashid)" but that's outside of the scope of this thread, I'll look it up. Thanks for the suggestion.

Eventually I removed the method name from $this->authorize() because it is not needed in my case.

Thanks again for your time and sharing your knowledge. Didn't progress much today but I learned something new again ;-)

Kimmer left a reply on Policies Always Results In "This Action Is Unauthorized" • 1 month ago

Thanks for your time @crnkovic.

While waiting for a reply I figured out that the options should be an instance of the model, not an ID number. As you point out in your comment.

I updated the controller to this and now it works.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Spot;
use Vinkla\Hashids\Facades\Hashids;

use App\Policies\SpotPolicy;

class spotController extends Controller
{
    public function delete($spot)
    {
        $id = Hashids::connection('spots')->decode($spot)[0];
        
        $this->authorize('delete', Spot::find($id));

        return 'Spot gets deleted';
    }

}

Is this solution acceptable you think?

Kimmer left a reply on Policies Always Results In "This Action Is Unauthorized" • 1 month ago

I had to update my previous comment because I'm back to square one.

With the transformed hashid I'm still getting ""This action is unauthorized".

Even when I try enter the spot's id directly as a parameter for authorize() like this...

$this->authorize('delete', 1);
```
Shouldn't that parameter be an ID number? Apparently not?

Kimmer left a reply on Policies Always Results In "This Action Is Unauthorized" • 1 month ago

Ah, that's why I din't do this...


public function delete(Spot $spot)

but

public function delete($spot)

I forgot to turn the hashed ID to the item's real ID in the controller before calling the authorisation. This controller makes it work.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Spot;
use Vinkla\Hashids\Facades\Hashids;

use App\Policies\SpotPolicy;

class spotController extends Controller
{
    public function delete($spot)
    {

        $id = Hashids::connection('spots')->decode($spot)[0];

        $this->authorize('delete', $id);

        return 'Spot gets deleted';
    }

}

Thanks a lot!

Kimmer left a reply on Policies Always Results In "This Action Is Unauthorized" • 1 month ago

I just don't understand why the URL with the hashed ID doesn't even reach the delete() method in the spotController.

Kimmer left a reply on Policies Always Results In "This Action Is Unauthorized" • 1 month ago

I found what's causing the error. I was sending the item ID as a hashed id because I'm using Laravel component called "Hashids" from Vinkla. so the URL I was sending looked like

https://[domain]/spots/api/Zmr6kGzDE0xN9YeWgAXgApdvlBVyQPo5wj3nb2J4/delete

Surpassing the Hashid's component and sending...

https://[domain]/spots/api/1/delete

...makes my code reach the "delete" method in "SpotPolicy".

So the code works. I just need to make it work with hashed ids.

Kimmer left a reply on Policies Always Results In "This Action Is Unauthorized" • 1 month ago

Thanks for your support @crnkovic.

I'm sorry but I don't know what you mean. What is a "route key in your model"?

This is the Spot model

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Spot extends Model
{

    protected $fillable = [
        'map_id',
        'place_id',
        'user_id',
        'info'
    ];

    protected $hidden = [
        'id',
    ];

    public function user() {
        return $this->belongsTo('App\User');
    }

    public function map() {
        return $this->belongsTo('App\Map');
    }
    
    public function place() {
        return $this->belongsTo('App\Place');
    }

}

Kimmer left a reply on Policies Always Results In "This Action Is Unauthorized" • 1 month ago

Thans @Cruorzy ! Corrected that.

@crnkovic : for some reason this returns "Sorry, the page you are looking for could not be found."

I have this in my routes/web.php

Route::get('spots/api/{spot}/delete', '[email protected]');

And I'm passing

https://[domain]/spots/api/[id]/delete

If I do what you suggest the "delete" method in spotController doesn't even get reached (dd()) is not triggered)

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Spot;

use App\Policies\SpotPolicy;

class spotController extends Controller
{
    public function delete(Spot $spot)
    {
        dd('Stop here');
        $this->authorize('delete', $spot);

        return 'Spot gets deleted';
    }

}
,,,

Kimmer started a new conversation Policies Always Results In "This Action Is Unauthorized" • 1 month ago

I followed the tutorial video, read the docs and searched the web. My code should work... yeah well... it doesn't and it's driving me mad.

I'm trying g to create a simple policy in Laravel.

In the controller

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Spot;

use App\Policies\SpotPolicy;

class spotController extends Controller
{
   public function delete($spot)
   {
       $this->authorize('delete', $spot);

       return 'Spot gets deleted';
   }

}

In the Policy file (app\Policies\SpotPolicy.php)

<?php

namespace App\Policies;

use App\User;
use App\Spot
use Illuminate\Auth\Access\HandlesAuthorization;

class SpotPolicy
{
    use HandlesAuthorization;

    public function delete(User $user, Spot $spot) 
    {
        dd('Stop here');
        
        return true;

    }
}

In the AuthServiceProvider

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    
    protected $policies = [
        'App\Model' => 'App\Policies\ModelPolicy',
        'App\Spot' => 'App\Policies\SpotPolicy'
    ];

    public function boot()
    {
        $this->registerPolicies();
    }
}

This always returns "Symfony \ Component \ HttpKernel \ Exception \ AccessDeniedHttpException This action is unauthorized.". The "delete" method in the SpotPolicy class is never reached.

Anyone... please?

Thanks

28th July, 2018

Kimmer left a reply on Vue.js & Google Maps Api - Button @click In Infowindow • 1 month ago

I seems vm.$mount() was the solution to my issue. https://vuejs.org/v2/api/#vm-mount

I added this to my app.js file

var infoWindowButton = Vue.extend({
  template: '<button type="button" @click="infoWindowButtonClicked()">This is a button</button></div>',
  methods : {
    infoWindowButtonClicked : function() {
      Event.fire('infoWindowButtonClicked'); 
    }
  }
})
Event.fire('infoWindowButton', new infoWindowButton().$mount()); 

And updated the above component to:

<template>
    <div class="map-container" ref="map"></div>
</template>

<script>
    export default {
        data: function () {
            return {
                map: null,
                infoWindow: {},
                infoWindowButton: '', // NEW
            }
        },
        created() {
            Event.listen('MapsApiLoaded', function(value){
                this.createMap();
            }.bind(this));
             // NEW
            Event.listen('infoWindowButton', function(component){
                this.infoWindowButton = component;
            }.bind(this));
            // NEW
            Event.listen('infoWindowButtonClicked', function(){
                this.openDialog();
            }.bind(this));
        },
        methods: {
            // create map
            createMap: function () {
                const element = this.$refs.map;
                const options = {
                    zoom: 7,
                    center: new google.maps.LatLng(9.625482,-84.029368)
                }
                this.map = new google.maps.Map(element, options);
                this.addMarker();
            },
            // Add marker
            addMarker: function(latLng) {
                this.marker = new google.maps.Marker({
                    position: new google.maps.LatLng(9.990378,-85.252195),
                    draggable:true,
                    map: this.map
                });
                this.marker.setMap(this.map);
                this.addInfoWindow();
            },
            // Add infowindow
            addInfoWindow: function () {
                this.infoWindow = new google.maps.InfoWindow({
                    size: new google.maps.Size(150, 50)
                });
                // VARIABLE UPDATED
                // var contentString = '<button type="button" @click="openDialog()">This is a button</button>';
                var contentString = this.infoWindowButton.$el;

                this.infoWindow.setContent(contentString);
                this.infoWindow.open(this.map, this.marker);
            },
            // Method to be reached by click event on button in InfoWindow
            openDialog: function () {
                console.log('openDialog');
            }
        },
    };
</script>

Note the env "infoWindowButton" data variable, the two event listeners in "created()" and the updated "contentString" variable.

Not related to this issue but to make my solution complete, events are handled by a small event wrapper which is also in my app.js

window.Event = new class {

  constructor() {
    this.vue = new Vue();
  }

  fire(event, data = null, action) {
    this.vue.$emit(event, data, action);
  }

  listen(event, callback) {
    this.vue.$on(event, callback)
  }

}

27th July, 2018

Kimmer started a new conversation Vue.js & Google Maps Api - Button @click In Infowindow • 1 month ago

I've been stuck on this for a while, found some other people asking this question but could not find an answer. I hope someone here is able and willing to help me out.

In a vue.js component I have a button in Google Maps API Infowindows. Like this

<template>
    <div class="map-container" ref="map"></div>
</template>

<script>
    export default {
        data: function () {
            return {
                map: null,
                infoWindow: {},
            }
        },
        created() {
            Event.listen('MapsApiLoaded', function(value){
                this.createMap();
            }.bind(this));
        },
        methods: {
            createMap: function () {
                const element = this.$refs.map;
                const options = {
                    zoom: 7,
                    center: new google.maps.LatLng(9.625482,-84.029368)
                }
                this.map = new google.maps.Map(element, options);
                this.addMarker();
            },
            addMarker: function(latLng) {
                this.marker = new google.maps.Marker({
                    position: new google.maps.LatLng(9.990378,-85.252195),
                    draggable:true,
                    map: this.map
                });
                this.marker.setMap(this.map);
                this.addInfoWindow();
            },
            addInfoWindow: function () {
                this.infoWindow = new google.maps.InfoWindow({
                    size: new google.maps.Size(150, 50)
                });
                var contentString = '<button type="button" @click="openDialog()">This is a button</button>';
                this.infoWindow.setContent(contentString);
                this.infoWindow.open(this.map, this.marker);
            },
            openDialog: function () {
                console.log('openDialog');
            }
        },
    };
</script>

I'm trying to reach the "openDialog" method but the @click event does not work.

How can I trigger the "openDialog" method by clicking the button in the Infowindow?

Thanks a lot in advance.

1st April, 2018

Kimmer started a new conversation Get Ranking Based On Voting Scores • 5 months ago

I have a list of tracks on which can be voted. To order the list in vue.js on the front-end I need a unique ranking value for every tack based on the voting score.

This code works perfectly except it does not use the "Tracks" model.

$subquery = "( 
    SELECT      tracks.id,
            IFNULL(Sum(votes.vote), 0) AS score
    FROM        tracks 
    LEFT JOIN   votes 
    ON      tracks.id = votes.track_id
    WHERE       tracks.listing_id = $id
    GROUP BY    tracks.id
    ORDER BY    score DESC, 
    tracks.created_at DESC 
) totals";
    
DB::statement(DB::raw('set @r=0'));

$tracks = DB::table(DB::raw($subquery))
->select(
'*', 
'score', 
DB::raw('@r:[email protected]+1 as rank'), 
DB::raw('@l:=score'))
->get();

return $tracks;

}

Is there a way to do this without a raw SQL (sub)query?

I tried this but it doesn't seem to work.

DB::statement(DB::raw('set @r=0'));

$tracks = Track::select(
    'tracks.*', 
    DB::raw('IFNULL(SUM(votes.vote), 0) AS score'), 
    DB::raw('@r:[email protected]+1 as rank')
    )
->leftJoin('votes', 'tracks.id', '=', 'votes.track_id')
->where('tracks.listing_id', $id)
->groupBy('tracks.id')
->orderBy('rank')
->get();
        
return $tracks;

Thanks!

26th March, 2018

Kimmer started a new conversation SSR With Vue And Vuetify • 5 months ago

I’m trying to figure out how to do SSR with Laravel and I managed to get the results from this tutorial working in MAMP on my Mac (by installing php-v8js).

Now I’m trying to incorporate Vuetify but I’m running into a wall.

I created a component “resources/assets/js/components/Layout/Toolbar.vue” in which I added basic Vuetify toolbar markup

Then I added this line in “resources/assets/js/app.js”

Vue.component('toolbar', require('./components/Layout/Toolbar.vue’));

And created the following markup in “resources/assets/js/components/App.vue”.

<template>
  <div id="app">
    <toolbar></toolbar>
  </div>
</template>

Now when I check the page source in Chrome I can see the the server is sending over the toolbar markup like this

<v-toolbar>
// toolbar markup
</v-toolbar>

It’s clear that Vuetify doesn’t have any effect in this markup. I tried incorporating Vuetify by adding the lines below to the the .js files (one by one) created while doing the tutorial but I can’t get it to work.

import Vuetify from 'vuetify'
Vue.use(Vuetify)

Anyone know how to get SSR running with Vuetify?

Thanks!

6th March, 2018

Kimmer left a reply on Eloquent - Calculate Two Field Values And Order According To Result. • 6 months ago

Thanks so very much! Did a quick test and your solution with the the leftJoin seems to work very nicely @matthew_inamdar .

5th March, 2018

Kimmer started a new conversation Eloquent - Calculate Two Field Values And Order According To Result. • 6 months ago

I am building a query calling a collection of track to build up a track list. There’s a bunch of relationships that go with this.

  • A track has a song (one to one)
  • A track has votes (one to many)
  • A song has artists (many to many)

I can call all this with

Track::where('tracks.listing_id', $id)
    ->with('song', 'song.artists', 'votes')
    ->get();

I want to order the track by the amount of votes they have. Seems fairly simple BUT a vote can be positive (up vote) or negative (down vote). The votes records have a “vote” field in which the value can be “1” or “-1”. This means I can’t just count the number of records in the votes table for one given track.

So, how can I calculate the up and down votes to get an actual votes count and order my query results on that? Is it even possible

I played around with withCount() which allows me to count only the up-votes or down-votes but I could really use some help here. Maybe what I’m after isn’t even possible.

26th November, 2017

Kimmer started a new conversation Inserting Multiple Records With Al Kinds Of Related Models • 9 months ago

This is rather complicated. I’ll try a explain as clearly as possible.

######Models: I have 3 models Track, Song and Artist. A track has one song, a song can belong to many tracks, a song can have many artists and an artist can belong to many songs. (see relationships below at "Models relationships")

######Database tables: The Database tables are tracks, songs, artists and artist_song (pivot). (see the fields below at "Database tables and fields")

######Scenario: Via an API call to the Spotify API data is returned. The returned JSON contains data from three songs which have one or more artists. (see JSON return below at "Returned API data")

######What I want to do: For every song in the JSON…

  • create a record in the tracks table with the ID of the song
  • create a record in the songs table with the song info (“name” to “title” field)
  • create a record for every artist in the artists table
  • attache the artists to the correct songs via the pivot table.

With as few queries as possible

######What I can do: I am able create all records but with queries in loops which could result in too many DB queries.

I can write the 3 songs in one query (see last code block) but I don’t know how to proceed with writing the tracks and artist for these songs.

######Models relationships

// Track
public function song() {
    return $this->belongsTo('App\Models\Song');
}

// Song
public function tracks() {
    return $this->hasMany('App\Models\Track');
} 
public function Artists() {
        return $this->belongsToMany('App\Models\Artist');
}

// Artist
public function Songs() {
    return $this->belongsToMany('App\Models\Song');
}

######Database tables and fields (minimised to only the fields I need for this question)

tracks
    - id
    - song_id

songs
    - id
    - title

artists
    - id
    - name

artist_song
    - song_id
    - artist_id

######Returned API data (example, minified to only the data I need for this question)

{
  “songs”: [
    {
      "artists": [
        {
          "name": "Dreadzone"
        }
      ],
      "name": "Digital Mastermind",
    },
    {
      "artists": [
        {
          "name": "Damian Marley"
        },
        {
          "name": "Stephen Marley"
        },
        {
          "name": "Rovleta Fraser",
        }
      ],
      "name": "Hey Girl",
    },
    {
      "artists": [
        {
          "name": "The Wailers"
        },
        {
          "name": "Alpha Blondy"
        }
      ],
      "name": "Jerusalem",
    }
  ]
}

######Inserting the 3 songs in one query

$songs = collect();

foreach ($spotifyTracksData->songs as $song) {
    $songs->push(['title' => $song->name]);
}

$return = Song::insert($songs->toArray());

12th November, 2017

Kimmer left a reply on Eloquent Many To Many Query Searching Values From Both Tables. All Values Should Be Present. • 10 months ago

This seems to work.

It seems to search for a song in the database which

  • Has an identical title
  • Has the same artists
  • Has the same amount of artists
public static function songExistsByTitleArtists($track) {

    // Create array from artists IDs of a track coming in from a /tracks call to the Spotify API.
    // $artists = ['0jHCJWgwdcqysvbKWjXSI6', '41ekW4MXG59xJMXR8dX1OG'];
    $artists = collect($track->artists)->pluck('id');

    $query = song::query();

    //  Loop over the IDs in the $artists array and create a whereHas() statement for every ID
    foreach ($artists as $artist) {
        $query->whereHas('artists', function ($q) use($artist) {
            $q->where('spotify_id', $artist);
        });
    }

    // Compose the query
    $existingSong = $query
                    ->where('title', $track->name) // Compare incoming track title with song title in DB
                    ->has('artists', count($artists)) // Compare if the amount of artist in existing track is the same as the amount of IDs in the $artists array
                    ->first();

    return $existingSong;

}

Kimmer left a reply on Eloquent Many To Many Query Searching Values From Both Tables. All Values Should Be Present. • 10 months ago

I've been occupied with other things for a couple of days but I've been searching for a solution on this problem again for several hours. Anyone willing to help me crack this, please?

7th November, 2017

Kimmer left a reply on Eloquent Many To Many Query Searching Values From Both Tables. All Values Should Be Present. • 10 months ago

Ah but removing ->toArray() gives the same result, apparently

$ids = collect($track->artists)->pluck('id');
```

Kimmer left a reply on Eloquent Many To Many Query Searching Values From Both Tables. All Values Should Be Present. • 10 months ago

This does return an array of the artists->id in the JSON @Cronix

$ids = collect($track->artists)->pluck('id')->toArray();

Here's an example:

["0jHCJWgwdcqysvbKWjXSI6","41ekW4MXG59xJMXR8dX1OG"]

Kimmer left a reply on Eloquent Many To Many Query Searching Values From Both Tables. All Values Should Be Present. • 10 months ago

$track is the JSON return I get from Spotify after an API call. This is the minified version of the JSON return. This return holds the data I'm using to find the existing song in the database. I need to know if that song already exists.

{
  "artists" : [ {
    "id" : “Artist1”
  }, {
    "id" : “Artist2”
  } ],
  "name" : “Cool Song“,
}

No there is no artist_id in the songs table. There’s a pivot table. songs and artists have a many to many relationship. These are my migrations. I removed the columns that have no use for the issue in this threat.

Schema::create('songs', function (Blueprint $table) {
    $table->string('title');
});
// all references to artists are in the Pivot table ‘artist_song’

Schema::create('artists', function (Blueprint $table) {
    $table->string('spotify_id', 30);
});
// all references to songs are in the Pivot table ‘artist_song’

// Pivot table
Schema::create('artist_song', function (Blueprint $table) {
    $table->integer('song_id')->unsigned()->index();
    $table->integer('artist_id')->unsigned()->index();
    $table->primary(['song_id', 'artist_id']);
});

So I’m searching for spotify_id in the artists table.

I’m fairly new to all of this. I don’t really know why collect() is needed. My code is in a class I made which is in a folder “library” that I created. Maybe I need a certain namespace or a ‘use’?

Kimmer left a reply on Eloquent Many To Many Query Searching Values From Both Tables. All Values Should Be Present. • 10 months ago

Thanks for your reply @robrogers3. Yes the table is “artists”

Sadly I can’t get it working.

Without editing your code returns:

Call to a member function pluck() on array

After some searching I managed to have this code return an array of ids from the incoming API return and solve the above error.

$ids = collect($track->artists)->pluck('id')->toArray();

Your code with the first line replaced with the edited version returned this error.

Call to a member function toArray() on array

I removed the ->toArray() from line three which left me with this error

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'artist_id' in 'where clause' (SQL: select exists(select * from `songs` where `spotify_id` in (select `spotify_id` from `artists` where `artist_id` in (0jHCJWgwdcqysvbKWjXSI6, 41ekW4MXG59xJMXR8dX1OG)) and `title` = Jerusalem) as `exists`)

'artist_id' does not exist in the artists table so I changed the code to this

$ids = collect($track->artists)->pluck('id')->toArray();
return Song::whereIn('spotify_id', function ($query) use ($ids) {
    $query->select('spotify_id')->from('artists')->whereIn('spotify_id', $ids);
})->where('title', $track->name)->exists();

This returns no error but, sadly, does not find the existing song.

6th November, 2017

Kimmer started a new conversation Eloquent Many To Many Query Searching Values From Both Tables. All Values Should Be Present. • 10 months ago

I have a table with called “songs” which contains songs that have a “title”.

I also have a table called “artists” which contains artists that have a “spotify_id”.

A song can have many artist and an artist can blog to many songs so I have a pivot table “artist_song” which connects the “songs” and “artists” tables

In my models I have...

class Song extends Model
{
    public function Artists() {
            return $this->belongsToMany('App\Models\Artist')->withTimestamps();
    }
}

class Artist extends Model
{
    public function Songs() {
            return $this->belongsToMany('App\Models\Song');
        }
}

Via an API call this response comes in (extremely minified to only contain elements needed for this issue)

{
  "artists" : [ {
    "id" : “Artist1”
  }, {
    "id" : “Artist2”
  } ],
  "name" : “Cool Song“,
}

So far so good. Now I want to check if the song exists in the database by it’s title and all artists for this song.

The result can only be positive if the title and all artists are identical. Based on the example, should the song "Cool Song" exist in the database with “Artist1” and “Artist2” and the API call returns “Cool Song“ with only “Artist1”, the result of the query should be negative because not identical.

The amount of artists will be variable depending on the song. Most songs only have one artist but some songs can have a lot of artists.

What would the Eloquent query look like? A very helpful colleague quickly typed something like this on a notepad.

$artists = $track->artists;

$existingSong = Song::with('Artists', function($query) use ($artists) {
            
    foreach($artists as $artist) {
        $query .= $query->where('spotify_id', $artist->id);
    }
    return $query;

})->get()->where('title', $track->name);

return $existingSong;

But this results in this error:

ErrorException in Str.php line 72:
mb_strpos() expects parameter 1 to be string, object given

Thanks!

22nd October, 2017

Kimmer left a reply on Installing Laravel Outside Of The Httpdocs Folder • 10 months ago

The .htaccess files was missing in the public folder. Adding it fixed the test link. Logging is still doesn't work but I think I'm getting close.

This thread has gone way out of topic so if I have another question I will start a new topic.

Thanks for your help!

Kimmer left a reply on Installing Laravel Outside Of The Httpdocs Folder • 10 months ago

I tried that but it doesn't make a difference. Work on my local dev version but not on the server. I also tried removing the leading slash from the routes but also no difference.

I don't think it's the blade template. It seems my routes file just doesn't do anything on the server.

Kimmer left a reply on Installing Laravel Outside Of The Httpdocs Folder • 10 months ago

Strange, the testlink I created also does not work. Made a simple a tag like this

<a href="{{ url('/test') }}">test</a>

and this in my routes/web.php file.

Route::get('/test', function () {
    return view('welcome');
});

Works locally but not on my server.

Kimmer left a reply on Installing Laravel Outside Of The Httpdocs Folder • 10 months ago

Yes I have, but it is different then my development version now. I think I'll manage to solve that. At the moment changes are minimal so I'm focussing on getting everything to work on my production server first. This is mainly what I'm struggling with.

Your tip with url() did the trick. I just had to work out how to use that with Laravel Mix and versioning. My app is loading the CSS and JS files as it should. This is what the stylesheet link tag looks like.

<link rel="stylesheet" href="{{ url(mix('css/app.css')) }}">

However, my routes don't seem to work. Getting 404s. The url is fine. At the moment my app only has one link available for guests, a login via Socialite and Spotify. I'm going to create a testlink to a simple page and see if that works.

Kimmer left a reply on Installing Laravel Outside Of The Httpdocs Folder • 10 months ago

Thanks @Daveismyname . I'm sorry but I should have mentioned I'm using Laravel Mix with versioning. This is what my stylesheet link tag looks like in my blade layout.


<link rel="stylesheet" href="{{ mix('css/app.css') }}">

Kimmer left a reply on Installing Laravel Outside Of The Httpdocs Folder • 10 months ago

Thanks!

With the help the the articles linked here and this one https://laravel-news.com/subfolder-install I managed to install my app in a subfolder.

It seems to work apart from the CSS and JS. The source and href paths start with a "/" so the js and css file are not found. I've been looking around on where to fix that but the only file where I can find the paths with a starting "/" is public/mix-manifest.json. Changing it there does not make a difference.

Any idea what I need to do to get the JS and CSS working?

Kimmer left a reply on Installing Laravel Outside Of The Httpdocs Folder • 10 months ago

Thanks for your reply @Yamen but I don't really understand your answer.

Are you saying I should install my Laravel app outside of the httpdocs folder?

Kimmer started a new conversation Installing Laravel Outside Of The Httpdocs Folder • 10 months ago

Hi there,

I’ve been researching how to install my first Laravel project on my Ubuntu 16.04 (plesk17) VPS. I’m reading that I should install Laravel in a folder outside of the httpdocs and move the public folder inside httpdocs. For security reasons.

Is this correct?

If this is correct I have a follow up question: I am also learning how to use GIT to pull updates to my production site. I can make it deploy to a folder outside of httpdocs but how do I keep the public folder up to date when when pulling updates when it is no longer in the same folder as the rest of my Laravel files?

Thanks!

23rd August, 2017

Kimmer left a reply on Setting Class From Generated List Item Based On Data Coming From Other Component • 1 year ago

Thanks a lot @danmatthews . That seems to work nicely.

20th August, 2017

Kimmer started a new conversation Setting Class From Generated List Item Based On Data Coming From Other Component • 1 year ago

Hi there,

I’ve been trying to figure out how to set a class from a loop generated list item based on information coming from an other vue component. This must be easy for most but any way I look at it I get stuck.

I’ve got some simplified code to Illustrate. GetUserDevices.vue is used to get your available devices from the Spotify API and I’m trying to set the class of the list item containing the active device. information about which device is active comes from an other vue component (GetUserPlayback.vue)

GetUserDevices.vue

Gets the list of available devices.

<template>

    <ul>
        <li v-for="item in items" key="item.id" v-bind:class="activeClass">
            {{ item.name }} - {{ item.id }}
        </li>
    </ul>

</template>

<script>

    export default {
        mounted() {
            this.getUsersDevices();

            Event.listen('getActiveDevice', function(deviceId){
                    console.log(deviceId); // Print out the active device ID coming from GetUserPlayback.vue
            }.bind(this));
        },
        data () {
            return {
                items: [],
                activeClass: '',
            }
        },
        methods: {
            getUsersDevices: function() {

                axios.get('player/api/getUsersDevices')
                .then(function (response) {

                        this.items = response.data.devices;

                }.bind(this))
            }
        }
    }
</script>

GetUserPlayback.vue

This code gets data which holds info about the active device. It takes the active device ID and sends it over to the other vue component with an event. GetUserDevices.vue is listening to that event and prints out the active divide ID in the Console.

<template>

</template>

<script>
    export default {
        mounted() {
            this.getUserPlayback();
        },
        methods: {
            getUserPlayback: function() {

                axios.get('player/api/getUserPlayback')
                .then(function (response) {
                    Event.fire('getActiveDevice', response.data.device.id); 
                }.bind(this))

            }
        }
    }
</script>

This all works fine but now I need to set the class name to the list item holding the device which ID corresponds with the ID coming in from the “getActiveDevice” event. How?

Thanks!

19th April, 2017

Kimmer left a reply on Vue.js Component Within Component (passing Data Obtained With Ajax To Child Component) • 1 year ago

Thanks @moyvera . You know what? I did that tutorial before and I completely forgot about it. I did it and the other one about Events (https://laracasts.com/series/learn-vue-2-step-by-step/episodes/12) about 5 times today. Eventually the fog cleared up and it all works now.

I used an event dispatcher as in the tutorial you suggested.

It solved the main issue this thread is about and I’m able to call the fetch() method from every component now.

I’m just going to share my code so maybe someone else doesn’t have to search for days, like I did.

This is in my view file. I’ll be needing the hashid later so I’m grabbing it from the PHP and adding it as a attribute to be used as a prop in Store.vue.

<store hashid="{{ $list->hashid }}"></store>
<list></list>

The Store.vue component is used to fetch the data (and store it so to speak) from the database via an Ajax call.

Store.vue

<template>
</template>

<script>
    export default {
        props: ['hashid'],
        created() {

            /*
                - Listen for the loadList event to happen.
                - When this event comes in the fetch() method is called which will collect the list data via an Ajax call
             */
            this.fetch(); // Fetch the data on page load
            Event.listen('loadList', () => this.fetch()); // listen. $on(event, callback)

        },
        methods: {
            fetch: function () {

                $.getJSON('api/'+this.hashid, function(data) {

                    /*
                        - Firing the StoreData event
                        - Is being listened to in List.vue. It takes the list data in the second argument
                     */
                    Event.fire('storeData', data); // fire, $emit(event, data)

                }.bind(this));

            }
        }
    }
</script>

List.vue has only a button (for now) that will call the fetch() function in Store.vue with an event called “loadList”. This components also listens for the "storeData" event to come in withe the data.

List.vue ‘’’ <a href="#" class="btn btn-primary" aria-label="Left Align" @click="action()"> Reload list

export default {
    created() {
        /*
            Listen for the StoreData event to happen.
            This event will bring in the list data.
         */
        Event.listen('storeData', function(listData){
            console.log('Store Data: ', listData) // Jeej it works!
        });
    },
    methods: {
        /**
         * On button click
         */
        action: function() {
            /*
                Fires the loadList event
                Is being listened to in Store.vue.
             */
            Event.fire('loadList'); // fire, $emit(event, data)
        },
    }
}
```

In app.js template I’m loading the two components and it has the wrapper mentioned in the tutorial to change “$emit” to “fire” and “$on” to “listen”. That’s why I’m using “fire” and “listen” in my code instead of “$emit” and “$on”. It just makes the code a bit more understandable.

app.js

Vue.component('store', require('./components/List/Store.vue'));
Vue.component('list', require('./components/List/List.vue'));

window.Event = new class {

    constructor() {
        this.vue = new Vue();
    }

    fire(event, data = null) {
        this.vue.$emit(event, data);
    }

    listen(event, callback) {
        this.vue.$on(event, callback)
    }

}

18th April, 2017

Kimmer left a reply on Vue.js Component Within Component (passing Data Obtained With Ajax To Child Component) • 1 year ago

Do you mean consolidating all components within file @MaverickChan ?

I guess that's an option but I fear I'm going to end up with a huge file that might be a pain to update.

Kimmer started a new conversation Vue.js Component Within Component (passing Data Obtained With Ajax To Child Component) • 1 year ago

This a follow up question on this one: https://laracasts.com/discuss/channels/vue/vuejs-component-within-component-getting-data-from-child-component

I can pass the “title” variable to from the Store.vue component to List.vue when the value is set like this.

Store.vue

<template>
    <div>
        <list v-bind:title="title"></list>
    </div>
</template>

<script>
    Vue.component('list', require('../../components/List/List.vue'));

    export default {

        props: ['hash_id'],

        created() {
            this.fetch(this.hash_id);
        },
        data () {
            return {
                title: ''
            };
        },
        methods: {
            fetch: function (list) {
                this.title = 'My Title';
            },
        }
    }
</script>

Then I can use the “title” variable value in List.vue, in the template or in the script (for example to output it in the console) like this.

List.vue

<template>
    <h1>{{ title }}</h1>
</template>

<script>
    export default {
        props: ['title'],
        created() {
            console.log('title: ' +this.title);
        }
    }
</script>

However, when I obtain the value for the “title” variable with an Ajax call the value outputted in the console stays empty.

Store.vue (with Ajax)

<template>
    <div>
        <list v-bind:title="title"></list>
    </div>
</template>

<script>
    Vue.component('list', require('../../components/List/List.vue'));

    export default {

        props: ['hash_id'],

        created() {
            this.fetch(this.hash_id);
        },
        data () {
            return {
                title: ''
            };
        },
        methods: {
            fetch: function (list) {
                // this.title = 'My Title';
                $.getJSON('api/'+list, function(data) {
                    this.title = data.title;
                }.bind(this));
            },
        }
    }
</script>

I assume this must have something to do with Ajax being asynchronous and it is possible to solve this by using a setTimeout function but is this the right way to do this?

List.vue (with setTimeout)

<template>
    <h1>{{ title }}</h1>
</template>

<script>
    export default {
        props: ['title'],
        created() {
            console.log('title: ' +this.title);
            setTimeout(function(){
                    console.log('title: ' +this.title);
            }.bind(this),200);
        }
    }
</script>

I’ve been at this since last weekend and I feel I’m almost there. If I can get this solved I just need to know how to call the “fetch” method from the child component and I’ll be on my way. Don’t worry, I’ll start a new thread for that.

Thanks!

Kimmer left a reply on Vue.js Component Within Component (getting Data From Child Component) • 1 year ago

I’m sorry but I have a follow up question. If I try and access the title variable value inside the script of List.vue now this is possible (I’m outputting the value in the console here).

<template>
    <h1>{{ title }}</h1>
</template>

<script>
    export default {
        props: ['title'],
        created() {
            console.log('title: ' +this.title);
        }
    }
</script>

However, when I obtain the title via a Ajax script in Store.vue the title variable value outputted in the console is empty. Strangely, it is visible in the

tag in my template.

<template>
    <div>
        <list v-bind:title="title"></list>
    </div>
</template>

<script>

    Vue.component('list', require('../../components/List/List.vue'));

    export default {

        props: ['hash_id'],

        created() {
            this.fetch(this.hash_id);
        },
        data () {
            return {
                title: ''
            };
        },
        methods: {
            fetch: function (list) {
                // this.title = 'My Title';
                $.getJSON('api/'+list, function(data) {
                    this.title = data.title;
                }.bind(this));
            },
        }
    }
</script>

I'm using a title as an example here. In reality I need to pass over variables to be used in methods in the child component.

Now I remember I tried this solution at the start of past weekend (that’s how long I’ve been on this) and started looking for other solutions because of this value not being there.

Kimmer left a reply on Vue.js Component Within Component (getting Data From Child Component) • 1 year ago

Alright, I think I understand. I’m adding some working code for other people that might need help.

In my blade template I’m calling ’store’ like this.

<store></store>

Then in my main app.js I require the Store.vue component. So Store.vue becomes the parent component

Vue.component('store', require('./components/List/Store.vue'));

This is Store.vue which fetches the title (“My Title”) which is bound to the “title” attribute in the tag in the template. This is also where I require List.vue.

<template>
    <div>
        <h1>{{ title }}</h1>
        <list v-bind:title="title"></list>
    </div>
</template>

<script>
    Vue.component('list', require('../../components/List/List.vue'));

    export default {
        created() {
            this.fetch();
        },
        data () {
            return {
                title: ''
            };
        },
        methods: {
            fetch: function () {
                this.title = 'My Title'
            },
        }
    }
</script>

Finally, List.vue which gets “title” from the attribute (in Store.vue) as a prop.

<template>
    <h1>{{ title }}</h1>
</template>

<script>
    export default {
        props: ['title']
    }
</script>

Thanks again @topvillas ! Obviously my goal is a bit more complex than this example code but I think I might juts be able to pull it off now. Thanks also for the Vuex tip but, honestly, I hardly understand what it does at the moment. ;-)

Kimmer left a reply on Vue.js Component Within Component (getting Data From Child Component) • 1 year ago

Hej, thanks for your reply @topvillas . Do you mean making Store.vue the parent component and pass down the data to List.vue (which becomes the child) component using props?

Kimmer started a new conversation Vue.js Component Within Component (getting Data From Child Component) • 1 year ago

And I’m trying to extract data from a child vue components within the parent component.

I’m using Laravel 5.4, btw.

I’ve broken down my code. What I basically want to do here is get the ‘title’ from the child component (Store.vue) and show it the parent component (List.vue).

List.vue

<template>
    <div>
        <h1>{{ title }}</h1>
        <store></store>
    </div>
</template>

<script>

    import store from '../../components/List/Store.vue';

    export default {
        components: {
            'store': store
        },
        created() {
            this.title = store.title;
        },
        data () {
            return {
                title: 'List Tilte'
            };
        }
    }
</script>

Store.vue

<template>
</template>

<script>
    export default {
        created() {
            this.fetch();
            // alert('Store.vue is loaded');
        },
        data () {
            return {
                title: ''
            };
        },
        methods: {
            fetch: function () {
                this.title = 'my Title'
            },
        }
    }
</script>

Later I want to get the title (and all other needed data) from an Ajax call in Store.vue.

I guess this must be simple for some of you but I’ve a bit of a newbie and I’ve been at this for a long time now. I really hope someone is willing to help me out here.

Thanks!

16th April, 2017

Kimmer started a new conversation PreventDefault() Prevents From Getting The Value From A Text Field On A Drop Event • 1 year ago

Hi there,

I’m trying to make it possible to drag tracks from Spotify an drop them on to a dropzone in my app. I did it in jQuery before but I’m rebuilding my app in Laravel with Vue.

The drop happens on a text field which works fine. However for some reason I need to grab the value of the field with a bit of a timeout.

Now i’d like to prevent the default action a browser takes when something is dropped on a page just in case someone drops an image file or an mp3 on the dropzone.

preventDefault() in my drop function seems to also prevent the field value coming though.

This is my code. Without “e.preventDefault();” in the “drop” function, I’m getting a value from the field after a Spotify track is dropped on it. With “e.preventDefault();” the browses stops doing it’s default drop actions but the field value is empty every time.

<template id="dropzone">
    <div>
        <div class="dropzone-area" >
            <input type="text" id="url_input" class="dropinput" v-model="value" @drop="drop">
        </div>
    </div>
</template>

<script>
    export default {

        data() {
            return {
                value: ''
            }
        },

        methods: {
            drop: function(e) {

                e.preventDefault();
                
                setTimeout(function(){
                    console.log(this.value);
                }.bind(this),1);

            }
        }
    }
</script>

I’m hoping someone could nudge me in the right direction.

Thanks!

1st March, 2017

Kimmer left a reply on Trying To Get Vue-Strap To Work In Laravel 5.4 • 1 year ago

Solved it.

return {
      activeTab: ' '
}

Should be

return {
      activeTab: 0
}

For anyone trying to do the same here's the full working code for using the Vue-strap 2 tabs in Laravel 5.4:

In app.js

Vue.component('tabscontainer', require('./components/Tabs.vue'));

const app = new Vue({
    el: '#app'
});

In the Blade template

<tabscontainer></tabscontainer>

In my Tabs.vue

<template>
<tabs v-model="activeTab" nav-style="tabs" justified>
  <tab header="zero">
    Zero
  </tab>
  <tab header="one">
    One
  </tab>
  <tab header="two" disabled>
    Two
  </tab>
  <tab-group header="group1">
    <tab header="three">
      Three
    </tab>
    <tab header="four" disabled>
      Four
    </tab>
  </tab-group>
  <tab-group header="group2">
    <tab header="five">
      Five
    </tab>
  </tab-group>
</tabs>
</template>

<script>
var tab = require('vue-strap/src/Tab');
var tabs = require('vue-strap/src/Tabs');
var tabGroup = require('vue-strap/src/TabGroup');

export default {
  mounted() {
    console.log('Component mounted.')
  },
  data: function () {
    return {
      activeTab: 0
    }
  },
  components: {
    tab,
    tabs,
    tabGroup
  }
}
</script>

26th February, 2017

Kimmer left a reply on Trying To Get Vue-Strap To Work In Laravel 5.4 • 1 year ago

I have commented out line 29 in node_modules/vue-strap/src/Tabs.vue.

This got rid of the warning and everything seems to still work but I'm anything but sure that was the right thing to do.

I filed it as an issue on the Vue-strap for Vue 2 Github page: https://github.com/wffranco/vue-strap/issues/54

19th February, 2017

Kimmer left a reply on Trying To Get Vue-Strap To Work In Laravel 5.4 • 1 year ago

I got the tabs to work but there’s one more warning.

Apparently I made a mistake in the template in the Vue component. It seem the parent needs to be there. Like this

<template>
<tabs v-model="activeTab" nav-style="tabs" justified>
  <tab header="zero">
    ...
  </tab>
  <tab header="one">
    ...
  </tab>
  <tab header="two" disabled>
    ...
  </tab>
  <tab-group header="group1">
    <tab header="three">
      ...
    </tab>
    <tab header="four" disabled>
      ...
    </tab>
  </tab-group>
  <tab-group header="group2">
    <tab header="five">
      ...
    </tab>
  </tab-group>
</tabs>
</template>

So I did this in the Blade template

<tabcontainer></tabcontainer>

And changed the reference in the app.js file to reflect this 'tabcontainer'

Vue.component('tabcontainer', require('./components/Tabs.vue’));

The tabs seem to work now but there’s still this warning and I really, really don’t like red coloured text in the Console.

[Vue warn]: Invalid prop: type check failed for prop "value". Expected Number, got String. (found in component at [path to the node_modules folder on my Mac]/node_modules/vue-strap/src/Tabs.vue)

Kimmer started a new conversation Trying To Get Vue-Strap To Work In Laravel 5.4 • 1 year ago

First of all I installed the Vue-strap version for Vue 2: https://github.com/wffranco/vue-strap.

I’m trying to get the Tabs to work https://wffranco.github.io/vue-strap/#tabs

I have this in my app.js file

Vue.component('tabs', require('./components/Tabs.vue'));

const app = new Vue({
    el: '#app'
});

This in my Blade template

<tabs v-model="activeTab" nav-style="tabs" justified></tabs>

And this in my Tabs.vue file

<template>
<div>
  <tab header="zero">
    ...
  </tab>
  <tab header="one">
    ...
  </tab>
  <tab header="two" disabled>
    ...
  </tab>
  <tab-group header="group1">
    <tab header="three">
      ...
    </tab>
    <tab header="four" disabled>
      ...
    </tab>
  </tab-group>
  <tab-group header="group2">
    <tab header="five">
      ...
    </tab>
  </tab-group>
</div>
</template>

<script>
var tab = require('vue-strap/src/Tab');
var tabs = require('vue-strap/src/Tabs');
var tabGroup = require('vue-strap/src/TabGroup');

export default {
  mounted() {
    console.log('Component mounted.')
  },
  data: function () {
    return {
      activeTab: ''
    }
  },
  components: {
    'tab': tab,
    'tabs': tabs,
    'tabGroup': tabGroup
  }
}
</script>

I’m getting this warning twice:

[Vue warn]: Property or method "activeTab" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option. (found in root instance)

And this error:

Uncaught Error: tab depend on tabs.

Could someone nudge me in the right direction please. I’ve been at this all morning, read everything I could find but found not solution (yet)

Thanks!

Kimmer left a reply on Pass A Variable From Blade To Vue Component • 1 year ago

I was able to edit my post today so I cleaned it up a bit and removed some of my comments that referred to the mess I made.

12th February, 2017

Kimmer left a reply on Pass A Variable From Blade To Vue Component • 1 year ago

I found it: removing the colon in front of the "hashid" attribute in the Blade template made it work. Together with declaring hashid as a prop on your vue component (comment above this one) as zachleigh suggested (thanks for that).

So I changed:

<subscribe :hashid="{{ $list->hashid }}"></subscribe>

to

<subscribe hashid="{{ $list->hashid }}"></subscribe>

Kimmer left a reply on Pass A Variable From Blade To Vue Component • 1 year ago

I did this but it doesn’t solve the issue. Still getting the same warning.

export default {
        props: ['hashid'],
        data: function () {
            return {
                buttonClass: 'btn-primary',
                text: 'Subscribe',
                disabledState: false,
                title: 'Subscribe to this list',
                iconClass: 'glyphicon-paperclip'
            }
        },
    …

Note: I had to remove the declaration in the data function because I was getting this warning:

[Vue warn]: The data property "hashid" is already declared as a prop. Use prop default value instead. (found in component at /Users/kimdevylder/Data/Sites/listrian/listrian.dev/resources/assets/js/components/Subscribe.vue)

Kimmer left a reply on Pass A Variable From Blade To Vue Component • 1 year ago

Thanks for your reply. I forgot to mention what's in my blade template:

<subscribe :hashid="{{ $list->hashid }}"></subscribe>

Is this what you're asking?

Sorry for messing this up. Kinda new to this ;-)

Kimmer left a reply on Pass A Variable From Blade To Vue Component • 1 year ago

Sorry for making a mess with the code block. Aparently I can not update my post (getting a blank page). I'm trying to get my Vue component code right below.

<template>
    <button 
        class="btn" 
        v-bind:class="buttonClass"
        v-bind:disabled="disabledState"
        v-bind:title="title"
        aria-label="Left Align"
        @click="changeSubscriptionState(getListId())"
    >
            <i 
                class="glyphicon" 
                v-bind:class="iconClass"
                aria-hidden="true"
            ></i> {{ text }} 
    </button>
</template>

<script>
    export default {
        data: function () {
            return {
                buttonClass: 'btn-primary',
                text: 'Subscribe',
                disabledState: false,
                title: 'Subscribe to this list',
                iconClass: 'glyphicon-paperclip',
                hashid: ''
            }
        }
        created() {
            console.log('Component ready.');
            this.fetchSubscriptionStatus(this.hashid);
        },
        methods: {
            fetchSubscriptionStatus: function(list) {

                $.getJSON('api/'+list+'/subscription-status', function(status) {
                    console.log(status);
                    this.setButton(status);
                }.bind(this));

            },
            changeSubscriptionState: function(list) {
                $.getJSON('api/'+list+'/change-subscription-status', function(status) {
                    console.log(status);
                    this.setButton(status);
                }.bind(this));
            },
            setButton: function(status) {
                switch(status) {
                    case 1:
                        this.buttonClass = 'btn-danger';
                        this.text = 'Subscription denied';
                        this.disabledState = true;
                        this.title= 'Blocked';
                        this.iconClass = 'glyphicon-ban-circle';
                        break;
                    case 2:
                        this.buttonClass = 'btn-info';
                        this.text = 'Subscription pending';
                        this.disabledState = false;
                        this.title= 'Unsubscribe';
                        this.iconClass = 'glyphicon-alert';
                        break;
                    case 3:
                        this.buttonClass = 'btn-success';
                        this.text = 'Subscribed';
                        this.disabledState = false;
                        this.title= 'Unsubscribe';
                        this.iconClass = 'glyphicon-ok';
                        break;
                    default:
                        this.buttonClass = 'btn-primary';
                        this.text = 'Subscribe';
                        this.disabledState= false;
                        this.title= 'Subscribe to this list';
                        this.iconClass = 'glyphicon-paperclip';
                }
            }
        }
    }
</script>

Edit Your Profile
Update

Want to change your profile photo? We pull from gravatar.com.